@classytic/revenue 2.0.0 → 2.1.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.
Files changed (41) hide show
  1. package/dist/bank-feed-DJtLvz_7.mjs +133 -0
  2. package/dist/bank-feed.enums-BadqNJTC.d.mts +118 -0
  3. package/dist/bank-feed.enums-kYTLTTbe.mjs +165 -0
  4. package/dist/bridges/index.d.mts +1 -1
  5. package/dist/core/state-machines.d.mts +45 -4
  6. package/dist/core/state-machines.mjs +71 -12
  7. package/dist/{engine-types-CcjIb4Fy.d.mts → engine-types-txFXOiQS.d.mts} +451 -14
  8. package/dist/enums/index.d.mts +4 -3
  9. package/dist/enums/index.mjs +4 -3
  10. package/dist/{errors-DHa8JVQ-.mjs → errors-Dt46UZL_.mjs} +23 -1
  11. package/dist/{escrow.schema-CC8XuD46.d.mts → escrow.schema-9yh4Q-aQ.d.mts} +9 -9
  12. package/dist/{event-constants-CEMitnIV.mjs → event-constants-CTiDNWzc.mjs} +6 -0
  13. package/dist/events/index.d.mts +2 -2
  14. package/dist/events/index.mjs +3 -3
  15. package/dist/index.d.mts +21 -11
  16. package/dist/index.mjs +120 -19
  17. package/dist/providers/index.d.mts +2 -2
  18. package/dist/providers/index.mjs +2 -2
  19. package/dist/registry-h8sasoLh.d.mts +145 -0
  20. package/dist/repositories/create-repositories.d.mts +1 -1
  21. package/dist/repositories/create-repositories.mjs +1 -1
  22. package/dist/{revenue-bridges-sdlrR85c.d.mts → revenue-bridges-BtkWFsJu.d.mts} +107 -1
  23. package/dist/{revenue-event-catalog-LqxPnsU_.mjs → revenue-event-catalog-CgZ57M-f.mjs} +77 -3
  24. package/dist/{revenue-event-catalog-BX3g7RUi.d.mts → revenue-event-catalog-JpJcyK1E.d.mts} +198 -2
  25. package/dist/{settlement.repository-Cy3mMWGH.mjs → settlement.repository-Ba2U17zY.mjs} +559 -17
  26. package/dist/shared/index.d.mts +1 -1
  27. package/dist/shared/index.mjs +2 -2
  28. package/dist/{split.enums-CQE3ekH1.mjs → subscription.enums-DoIr56O6.mjs} +28 -67
  29. package/dist/{split.enums-Dw4zCrcZ.d.mts → subscription.enums-k24kLpF7.d.mts} +48 -83
  30. package/dist/validators/index.d.mts +158 -2
  31. package/dist/validators/index.mjs +95 -2
  32. package/package.json +11 -8
  33. package/dist/registry-DhFMsSn5.mjs +0 -150
  34. package/dist/registry-SvIGPAx_.d.mts +0 -143
  35. /package/dist/{audit-B39B0Sdq.mjs → audit-Ba2XB2C4.mjs} +0 -0
  36. /package/dist/{audit-DZ0eTr9g.d.mts → audit-DRKuLBFO.d.mts} +0 -0
  37. /package/dist/{context-DRqSeTPM.d.mts → context-pjP1QeE3.d.mts} +0 -0
  38. /package/dist/{escrow.schema-BBv9oVEW.mjs → escrow.schema-C-b41z_G.mjs} +0 -0
  39. /package/dist/{monetization.enums-BtiU3t8o.mjs → monetization.enums-B9HBOecd.mjs} +0 -0
  40. /package/dist/{monetization.enums-D2xbxXJM.d.mts → monetization.enums-DzAI4sT7.d.mts} +0 -0
  41. /package/dist/{splits-BAfY-a9P.mjs → splits-D8XkNWgX.mjs} +0 -0
@@ -0,0 +1,133 @@
1
+ import { l as ProviderNotFoundError } from "./errors-Dt46UZL_.mjs";
2
+
3
+ //#region src/providers/base.ts
4
+ /**
5
+ * Abstract `PaymentProvider` — the contract revenue's repositories
6
+ * consume. Provider implementations may extend this for the default
7
+ * config plumbing, or just satisfy the structural shape.
8
+ */
9
+ var PaymentProvider = class {
10
+ config;
11
+ name;
12
+ _defaultCurrency = "USD";
13
+ constructor(config = {}) {
14
+ this.config = config;
15
+ this.name = "base";
16
+ if (config.defaultCurrency && typeof config.defaultCurrency === "string") this._defaultCurrency = config.defaultCurrency;
17
+ }
18
+ get defaultCurrency() {
19
+ return this._defaultCurrency;
20
+ }
21
+ setDefaultCurrency(currency) {
22
+ this._defaultCurrency = currency;
23
+ }
24
+ /**
25
+ * Default: accept all signatures (manual / dev provider). Real
26
+ * gateways MUST override with HMAC / timing-safe verification.
27
+ */
28
+ verifyWebhookSignature(_payload, _signature) {
29
+ return true;
30
+ }
31
+ getCapabilities() {
32
+ return {
33
+ supportsWebhooks: false,
34
+ supportsRefunds: false,
35
+ supportsPartialRefunds: false,
36
+ requiresManualVerification: true
37
+ };
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ //#region src/providers/registry.ts
43
+ var ProviderRegistry = class {
44
+ providers = /* @__PURE__ */ new Map();
45
+ register(name, provider) {
46
+ this.providers.set(name, provider);
47
+ }
48
+ get(name) {
49
+ const provider = this.providers.get(name);
50
+ if (!provider) throw new ProviderNotFoundError(name);
51
+ return provider;
52
+ }
53
+ has(name) {
54
+ return this.providers.has(name);
55
+ }
56
+ list() {
57
+ return Array.from(this.providers.keys());
58
+ }
59
+ setDefaultCurrency(currency) {
60
+ for (const provider of this.providers.values()) provider.setDefaultCurrency(currency);
61
+ }
62
+ };
63
+ function createProviderRegistry(providers = {}, defaultCurrency) {
64
+ const registry = new ProviderRegistry();
65
+ for (const [name, provider] of Object.entries(providers)) {
66
+ if (defaultCurrency) provider.setDefaultCurrency(defaultCurrency);
67
+ registry.register(name, provider);
68
+ }
69
+ return registry;
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/providers/bank-feed.ts
74
+ /**
75
+ * Bank-feed provider — implement one method or both depending on the
76
+ * upstream's capabilities. Mirrors the optional-method pattern that
77
+ * works well across PaymentProvider's gateway plurality.
78
+ */
79
+ var BankFeedProvider = class {
80
+ config;
81
+ name;
82
+ constructor(name, config = {}) {
83
+ this.name = name;
84
+ this.config = config;
85
+ }
86
+ /**
87
+ * Async drain — yields one batch per call until the upstream is
88
+ * caught up. Default implementation pulls `fetchTransactions` in a
89
+ * loop; providers can override for more efficient pagination
90
+ * (e.g. SSE / long-poll) or to interleave `removed[]` correctly.
91
+ */
92
+ async *drain(params = {}) {
93
+ if (!this.fetchTransactions) throw new Error(`Provider ${this.name} does not support fetchTransactions()`);
94
+ let cursor = params.cursor;
95
+ const MAX_PAGES = 1e4;
96
+ for (let i = 0; i < MAX_PAGES; i++) {
97
+ const result = await this.fetchTransactions({
98
+ ...params,
99
+ cursor
100
+ });
101
+ yield result;
102
+ const tooLittle = result.transactions.length === 0 && (result.removed?.length ?? 0) === 0;
103
+ if (result.hasMore === false || tooLittle) return;
104
+ if (!result.nextCursor || result.nextCursor === cursor) return;
105
+ cursor = result.nextCursor;
106
+ }
107
+ }
108
+ };
109
+ var BankFeedProviderRegistry = class {
110
+ providers = /* @__PURE__ */ new Map();
111
+ register(name, provider) {
112
+ this.providers.set(name, provider);
113
+ }
114
+ get(name) {
115
+ const provider = this.providers.get(name);
116
+ if (!provider) throw new ProviderNotFoundError(name);
117
+ return provider;
118
+ }
119
+ has(name) {
120
+ return this.providers.has(name);
121
+ }
122
+ list() {
123
+ return Array.from(this.providers.keys());
124
+ }
125
+ };
126
+ function createBankFeedProviderRegistry(providers = {}) {
127
+ const registry = new BankFeedProviderRegistry();
128
+ for (const [name, provider] of Object.entries(providers)) registry.register(name, provider);
129
+ return registry;
130
+ }
131
+
132
+ //#endregion
133
+ export { createProviderRegistry as a, ProviderRegistry as i, BankFeedProviderRegistry as n, PaymentProvider as o, createBankFeedProviderRegistry as r, BankFeedProvider as t };
@@ -0,0 +1,118 @@
1
+ //#region src/enums/transaction.enums.d.ts
2
+ declare const TRANSACTION_FLOW: {
3
+ readonly INFLOW: "inflow";
4
+ readonly OUTFLOW: "outflow";
5
+ };
6
+ type TransactionFlow = typeof TRANSACTION_FLOW;
7
+ type TransactionFlowValue = TransactionFlow[keyof TransactionFlow];
8
+ declare const TRANSACTION_FLOW_VALUES: TransactionFlowValue[];
9
+ declare const TRANSACTION_STATUS: {
10
+ readonly PENDING: "pending";
11
+ readonly PAYMENT_INITIATED: "payment_initiated";
12
+ readonly PROCESSING: "processing";
13
+ readonly REQUIRES_ACTION: "requires_action";
14
+ readonly VERIFIED: "verified";
15
+ readonly COMPLETED: "completed";
16
+ readonly FAILED: "failed";
17
+ readonly CANCELLED: "cancelled";
18
+ readonly EXPIRED: "expired";
19
+ readonly REFUNDED: "refunded";
20
+ readonly PARTIALLY_REFUNDED: "partially_refunded";
21
+ readonly IMPORTED: "imported";
22
+ readonly MATCHED: "matched";
23
+ readonly JOURNALIZED: "journalized";
24
+ readonly REJECTED: "rejected";
25
+ };
26
+ type TransactionStatus = typeof TRANSACTION_STATUS;
27
+ type TransactionStatusValue = TransactionStatus[keyof TransactionStatus];
28
+ declare const TRANSACTION_STATUS_VALUES: TransactionStatusValue[];
29
+ declare const LIBRARY_CATEGORIES: {
30
+ readonly SUBSCRIPTION: "subscription";
31
+ readonly PURCHASE: "purchase";
32
+ };
33
+ type LibraryCategories = typeof LIBRARY_CATEGORIES;
34
+ type LibraryCategoryValue = LibraryCategories[keyof LibraryCategories];
35
+ declare const LIBRARY_CATEGORY_VALUES: LibraryCategoryValue[];
36
+ declare function isLibraryCategory(value: unknown): value is LibraryCategoryValue;
37
+ declare function isTransactionFlow(value: unknown): value is TransactionFlowValue;
38
+ declare function isTransactionStatus(value: unknown): value is TransactionStatusValue;
39
+ //#endregion
40
+ //#region src/enums/bank-feed.enums.d.ts
41
+ declare const TRANSACTION_KIND: {
42
+ /**
43
+ * Payment-gateway flow — the original revenue lifecycle. Stripe / SSL /
44
+ * Bkash / manual all share this graph.
45
+ * pending → payment_initiated → processing → requires_action → verified
46
+ * → completed → refunded | partially_refunded
47
+ */
48
+ readonly PAYMENT_FLOW: "payment_flow";
49
+ /**
50
+ * Bank / accounting feed — OFX upload, Plaid sync, QBO/Xero CDC.
51
+ * imported → matched → journalized (happy path)
52
+ * imported → rejected (operator skip)
53
+ * matched → imported (un-match)
54
+ */
55
+ readonly BANK_FEED: "bank_feed";
56
+ /**
57
+ * Hand-keyed entry — treasurer logs a cash deposit, owner injects
58
+ * capital. Cleaner two-step lifecycle than payment_flow.
59
+ * pending → matched → journalized | rejected
60
+ */
61
+ readonly MANUAL: "manual";
62
+ };
63
+ type TransactionKind = typeof TRANSACTION_KIND;
64
+ type TransactionKindValue = TransactionKind[keyof TransactionKind];
65
+ declare const TRANSACTION_KIND_VALUES: TransactionKindValue[];
66
+ declare function isTransactionKind(value: unknown): value is TransactionKindValue;
67
+ declare const BANK_FEED_STATUS: {
68
+ readonly IMPORTED: "imported";
69
+ readonly MATCHED: "matched";
70
+ readonly JOURNALIZED: "journalized";
71
+ readonly REJECTED: "rejected";
72
+ };
73
+ type BankFeedStatusValue = (typeof BANK_FEED_STATUS)[keyof typeof BANK_FEED_STATUS];
74
+ declare const BANK_FEED_STATUS_VALUES: BankFeedStatusValue[];
75
+ declare function isBankFeedStatus(value: unknown): value is BankFeedStatusValue;
76
+ declare const BANK_FEED_SOURCE: {
77
+ readonly OFX: "ofx";
78
+ readonly CAMT053: "camt.053";
79
+ readonly MT940: "mt940";
80
+ readonly CSV: "csv";
81
+ readonly IIF: "iif";
82
+ readonly QBO: "qbo";
83
+ readonly XERO: "xero";
84
+ readonly PLAID: "plaid";
85
+ readonly MANUAL: "manual";
86
+ };
87
+ type BankFeedSourceValue = (typeof BANK_FEED_SOURCE)[keyof typeof BANK_FEED_SOURCE];
88
+ declare const BANK_FEED_SOURCE_VALUES: BankFeedSourceValue[];
89
+ declare function isBankFeedSource(value: unknown): value is BankFeedSourceValue;
90
+ /**
91
+ * Initial status for a freshly created row of a given kind. Centralized so
92
+ * the schema, repo verbs, and validators agree.
93
+ *
94
+ * - `payment_flow` → `pending` — provider may flip to verified instantly
95
+ * for zero-amount rows (see `createPaymentIntent`).
96
+ * - `bank_feed` → `imported` — bulk upsert from a feed/upload.
97
+ * - `manual` → `pending` — treasurer reviews then `match()`es.
98
+ */
99
+ declare function initialStatusFor(kind: TransactionKindValue): TransactionStatusValue;
100
+ /**
101
+ * True iff `status` is a legal value for a transaction of the given
102
+ * `kind`. Use at API boundaries (admin status filters, list-page query
103
+ * params, JSON imports) to reject `?kind=payment_flow&status=imported`
104
+ * before it reaches the repository.
105
+ *
106
+ * @example
107
+ * if (!isStatusValidForKind(req.query.status, req.query.kind)) {
108
+ * throw new ValidationError('status invalid for kind');
109
+ * }
110
+ */
111
+ declare function isStatusValidForKind(status: unknown, kind: TransactionKindValue): boolean;
112
+ /**
113
+ * The set of status values legal for a given kind. Useful for building
114
+ * dropdown options or `$in` filters at the API layer.
115
+ */
116
+ declare function statusesForKind(kind: TransactionKindValue): readonly string[];
117
+ //#endregion
118
+ export { isTransactionFlow as A, TRANSACTION_STATUS as C, TransactionStatus as D, TransactionFlowValue as E, TransactionStatusValue as O, TRANSACTION_FLOW_VALUES as S, TransactionFlow as T, LIBRARY_CATEGORIES as _, BankFeedSourceValue as a, LibraryCategoryValue as b, TRANSACTION_KIND_VALUES as c, initialStatusFor as d, isBankFeedSource as f, statusesForKind as g, isTransactionKind as h, BANK_FEED_STATUS_VALUES as i, isTransactionStatus as j, isLibraryCategory as k, TransactionKind as l, isStatusValidForKind as m, BANK_FEED_SOURCE_VALUES as n, BankFeedStatusValue as o, isBankFeedStatus as p, BANK_FEED_STATUS as r, TRANSACTION_KIND as s, BANK_FEED_SOURCE as t, TransactionKindValue as u, LIBRARY_CATEGORY_VALUES as v, TRANSACTION_STATUS_VALUES as w, TRANSACTION_FLOW as x, LibraryCategories as y };
@@ -0,0 +1,165 @@
1
+ //#region src/enums/transaction.enums.ts
2
+ const TRANSACTION_FLOW = {
3
+ INFLOW: "inflow",
4
+ OUTFLOW: "outflow"
5
+ };
6
+ const TRANSACTION_FLOW_VALUES = Object.values(TRANSACTION_FLOW);
7
+ const TRANSACTION_STATUS = {
8
+ PENDING: "pending",
9
+ PAYMENT_INITIATED: "payment_initiated",
10
+ PROCESSING: "processing",
11
+ REQUIRES_ACTION: "requires_action",
12
+ VERIFIED: "verified",
13
+ COMPLETED: "completed",
14
+ FAILED: "failed",
15
+ CANCELLED: "cancelled",
16
+ EXPIRED: "expired",
17
+ REFUNDED: "refunded",
18
+ PARTIALLY_REFUNDED: "partially_refunded",
19
+ IMPORTED: "imported",
20
+ MATCHED: "matched",
21
+ JOURNALIZED: "journalized",
22
+ REJECTED: "rejected"
23
+ };
24
+ const TRANSACTION_STATUS_VALUES = Object.values(TRANSACTION_STATUS);
25
+ const LIBRARY_CATEGORIES = {
26
+ SUBSCRIPTION: "subscription",
27
+ PURCHASE: "purchase"
28
+ };
29
+ const LIBRARY_CATEGORY_VALUES = Object.values(LIBRARY_CATEGORIES);
30
+ const transactionFlowSet = new Set(TRANSACTION_FLOW_VALUES);
31
+ const transactionStatusSet = new Set(TRANSACTION_STATUS_VALUES);
32
+ const libraryCategorySet = new Set(LIBRARY_CATEGORY_VALUES);
33
+ function isLibraryCategory(value) {
34
+ return typeof value === "string" && libraryCategorySet.has(value);
35
+ }
36
+ function isTransactionFlow(value) {
37
+ return typeof value === "string" && transactionFlowSet.has(value);
38
+ }
39
+ function isTransactionStatus(value) {
40
+ return typeof value === "string" && transactionStatusSet.has(value);
41
+ }
42
+
43
+ //#endregion
44
+ //#region src/enums/bank-feed.enums.ts
45
+ /**
46
+ * Bank-feed lifecycle enums.
47
+ *
48
+ * Revenue 3.0 generalizes the Transaction model from "payment-gateway-only"
49
+ * to a unified cashflow ledger. The `kind` discriminator selects which
50
+ * state machine governs the row (see `core/state-machines.ts`); these
51
+ * enums own the bank-feed and manual lifecycles plus the canonical
52
+ * `TransactionKind` literals every consumer should branch on.
53
+ *
54
+ * Why a discriminator instead of a separate model — same collection wins
55
+ * the unified-audit-ledger query ("everything that touched cash this
56
+ * quarter"), keeps soft-delete + retention policies single-sourced, and
57
+ * lets `relatedTransactionId` cross-link a Stripe charge to its Plaid
58
+ * deposit without a polymorphic ref. See PACKAGE_RULES §30 / §35.
59
+ */
60
+ const TRANSACTION_KIND = {
61
+ PAYMENT_FLOW: "payment_flow",
62
+ BANK_FEED: "bank_feed",
63
+ MANUAL: "manual"
64
+ };
65
+ const TRANSACTION_KIND_VALUES = Object.values(TRANSACTION_KIND);
66
+ const transactionKindSet = new Set(TRANSACTION_KIND_VALUES);
67
+ function isTransactionKind(value) {
68
+ return typeof value === "string" && transactionKindSet.has(value);
69
+ }
70
+ const BANK_FEED_STATUS = {
71
+ IMPORTED: "imported",
72
+ MATCHED: "matched",
73
+ JOURNALIZED: "journalized",
74
+ REJECTED: "rejected"
75
+ };
76
+ const BANK_FEED_STATUS_VALUES = Object.values(BANK_FEED_STATUS);
77
+ const bankFeedStatusSet = new Set(BANK_FEED_STATUS_VALUES);
78
+ function isBankFeedStatus(value) {
79
+ return typeof value === "string" && bankFeedStatusSet.has(value);
80
+ }
81
+ const BANK_FEED_SOURCE = {
82
+ OFX: "ofx",
83
+ CAMT053: "camt.053",
84
+ MT940: "mt940",
85
+ CSV: "csv",
86
+ IIF: "iif",
87
+ QBO: "qbo",
88
+ XERO: "xero",
89
+ PLAID: "plaid",
90
+ MANUAL: "manual"
91
+ };
92
+ const BANK_FEED_SOURCE_VALUES = Object.values(BANK_FEED_SOURCE);
93
+ const bankFeedSourceSet = new Set(BANK_FEED_SOURCE_VALUES);
94
+ function isBankFeedSource(value) {
95
+ return typeof value === "string" && bankFeedSourceSet.has(value);
96
+ }
97
+ /**
98
+ * Initial status for a freshly created row of a given kind. Centralized so
99
+ * the schema, repo verbs, and validators agree.
100
+ *
101
+ * - `payment_flow` → `pending` — provider may flip to verified instantly
102
+ * for zero-amount rows (see `createPaymentIntent`).
103
+ * - `bank_feed` → `imported` — bulk upsert from a feed/upload.
104
+ * - `manual` → `pending` — treasurer reviews then `match()`es.
105
+ */
106
+ function initialStatusFor(kind) {
107
+ switch (kind) {
108
+ case TRANSACTION_KIND.BANK_FEED: return BANK_FEED_STATUS.IMPORTED;
109
+ case TRANSACTION_KIND.MANUAL: return TRANSACTION_STATUS.PENDING;
110
+ case TRANSACTION_KIND.PAYMENT_FLOW:
111
+ default: return TRANSACTION_STATUS.PENDING;
112
+ }
113
+ }
114
+ const STATUSES_BY_KIND = {
115
+ [TRANSACTION_KIND.PAYMENT_FLOW]: new Set([
116
+ TRANSACTION_STATUS.PENDING,
117
+ TRANSACTION_STATUS.PAYMENT_INITIATED,
118
+ TRANSACTION_STATUS.PROCESSING,
119
+ TRANSACTION_STATUS.REQUIRES_ACTION,
120
+ TRANSACTION_STATUS.VERIFIED,
121
+ TRANSACTION_STATUS.COMPLETED,
122
+ TRANSACTION_STATUS.FAILED,
123
+ TRANSACTION_STATUS.CANCELLED,
124
+ TRANSACTION_STATUS.EXPIRED,
125
+ TRANSACTION_STATUS.REFUNDED,
126
+ TRANSACTION_STATUS.PARTIALLY_REFUNDED
127
+ ]),
128
+ [TRANSACTION_KIND.BANK_FEED]: new Set([
129
+ TRANSACTION_STATUS.IMPORTED,
130
+ TRANSACTION_STATUS.MATCHED,
131
+ TRANSACTION_STATUS.JOURNALIZED,
132
+ TRANSACTION_STATUS.REJECTED
133
+ ]),
134
+ [TRANSACTION_KIND.MANUAL]: new Set([
135
+ TRANSACTION_STATUS.PENDING,
136
+ TRANSACTION_STATUS.MATCHED,
137
+ TRANSACTION_STATUS.JOURNALIZED,
138
+ TRANSACTION_STATUS.REJECTED
139
+ ])
140
+ };
141
+ /**
142
+ * True iff `status` is a legal value for a transaction of the given
143
+ * `kind`. Use at API boundaries (admin status filters, list-page query
144
+ * params, JSON imports) to reject `?kind=payment_flow&status=imported`
145
+ * before it reaches the repository.
146
+ *
147
+ * @example
148
+ * if (!isStatusValidForKind(req.query.status, req.query.kind)) {
149
+ * throw new ValidationError('status invalid for kind');
150
+ * }
151
+ */
152
+ function isStatusValidForKind(status, kind) {
153
+ if (typeof status !== "string") return false;
154
+ return STATUSES_BY_KIND[kind].has(status);
155
+ }
156
+ /**
157
+ * The set of status values legal for a given kind. Useful for building
158
+ * dropdown options or `$in` filters at the API layer.
159
+ */
160
+ function statusesForKind(kind) {
161
+ return [...STATUSES_BY_KIND[kind]];
162
+ }
163
+
164
+ //#endregion
165
+ export { TRANSACTION_STATUS as _, TRANSACTION_KIND as a, isTransactionFlow as b, isBankFeedSource as c, isTransactionKind as d, statusesForKind as f, TRANSACTION_FLOW_VALUES as g, TRANSACTION_FLOW as h, BANK_FEED_STATUS_VALUES as i, isBankFeedStatus as l, LIBRARY_CATEGORY_VALUES as m, BANK_FEED_SOURCE_VALUES as n, TRANSACTION_KIND_VALUES as o, LIBRARY_CATEGORIES as p, BANK_FEED_STATUS as r, initialStatusFor as s, BANK_FEED_SOURCE as t, isStatusValidForKind as u, TRANSACTION_STATUS_VALUES as v, isTransactionStatus as x, isLibraryCategory as y };
@@ -1,2 +1,2 @@
1
- import { a as CurrencyBridge, c as LedgerBridge, i as CustomerBridge, n as SourceBridge, o as NotificationBridge, r as AnalyticsBridge, s as TaxBridge, t as RevenueBridges } from "../revenue-bridges-sdlrR85c.mjs";
1
+ import { a as CurrencyBridge, c as LedgerBridge, i as CustomerBridge, n as SourceBridge, o as NotificationBridge, r as AnalyticsBridge, s as TaxBridge, t as RevenueBridges } from "../revenue-bridges-BtkWFsJu.mjs";
2
2
  export { type AnalyticsBridge, type CurrencyBridge, type CustomerBridge, type LedgerBridge, type NotificationBridge, type RevenueBridges, type SourceBridge, type TaxBridge };
@@ -1,6 +1,13 @@
1
- import { C as HoldStatusValue, I as SettlementStatusValue, J as SubscriptionStatusValue, ct as TransactionStatusValue, u as SplitStatusValue } from "../split.enums-Dw4zCrcZ.mjs";
1
+ import { U as HoldStatusValue, b as SplitStatusValue, c as SubscriptionStatusValue, j as SettlementStatusValue } from "../subscription.enums-k24kLpF7.mjs";
2
+ import { O as TransactionStatusValue, u as TransactionKindValue } from "../bank-feed.enums-BadqNJTC.mjs";
2
3
 
3
4
  //#region src/core/state-machines.d.ts
5
+ /**
6
+ * Audit-trail event emitted by `validateAndCreateAuditEvent`.
7
+ *
8
+ * Revenue-specific shape — primitives' state-machine is intentionally
9
+ * ledger-agnostic, so the audit envelope stays here next to the consumers.
10
+ */
4
11
  interface StateChangeEvent<TState extends string = string> {
5
12
  resourceType: string;
6
13
  resourceId: string;
@@ -11,9 +18,21 @@ interface StateChangeEvent<TState extends string = string> {
11
18
  reason?: string;
12
19
  metadata?: Record<string, unknown>;
13
20
  }
21
+ /**
22
+ * Revenue's typed state machine.
23
+ *
24
+ * Thin facade over `@classytic/primitives/state-machine`'s
25
+ * `defineStateMachine` — primitives owns the transition logic, revenue
26
+ * owns the API shape (`validate`, `getAllowedTransitions`,
27
+ * `validateAndCreateAuditEvent`) that the existing repos and tests
28
+ * depend on. Wires `InvalidStateTransitionError` through the primitive's
29
+ * `errorFactory` so thrown types are unchanged.
30
+ *
31
+ * The constructor still accepts `Map<TState, Set<TState>>` so existing
32
+ * instance definitions don't need to be rewritten.
33
+ */
14
34
  declare class StateMachine<TState extends string> {
15
- private readonly transitions;
16
- private readonly resourceType;
35
+ private readonly inner;
17
36
  constructor(transitions: Map<TState, Set<TState>>, resourceType: string);
18
37
  validate(from: TState, to: TState, resourceId: string): void;
19
38
  canTransition(from: TState, to: TState): boolean;
@@ -31,5 +50,27 @@ declare const SUBSCRIPTION_STATE_MACHINE: StateMachine<SubscriptionStatusValue>;
31
50
  declare const SETTLEMENT_STATE_MACHINE: StateMachine<SettlementStatusValue>;
32
51
  declare const HOLD_STATE_MACHINE: StateMachine<HoldStatusValue>;
33
52
  declare const SPLIT_STATE_MACHINE: StateMachine<SplitStatusValue>;
53
+ declare const PAYMENT_FLOW_STATE_MACHINE: StateMachine<TransactionStatusValue>;
54
+ declare const BANK_FEED_STATE_MACHINE: StateMachine<TransactionStatusValue>;
55
+ declare const MANUAL_STATE_MACHINE: StateMachine<TransactionStatusValue>;
56
+ /**
57
+ * Select the state machine that governs a transaction row, given its
58
+ * `kind`. Repo verbs call this at the start of every state transition
59
+ * so the same `from → to` rules apply on both the in-memory check
60
+ * (state machine) and the atomic CAS (mongokit `claim()` with the
61
+ * `where: { kind }` predicate).
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const machine = smFor(transaction.kind);
66
+ * machine.validate(transaction.status, 'matched', String(transaction._id));
67
+ * await this.claim(id, {
68
+ * from: ['imported', 'matched'],
69
+ * to: 'matched',
70
+ * where: { kind: transaction.kind },
71
+ * }, patch, opts);
72
+ * ```
73
+ */
74
+ declare function smFor(kind: TransactionKindValue): StateMachine<TransactionStatusValue>;
34
75
  //#endregion
35
- export { HOLD_STATE_MACHINE, SETTLEMENT_STATE_MACHINE, SPLIT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, StateChangeEvent, StateMachine, TRANSACTION_STATE_MACHINE };
76
+ export { BANK_FEED_STATE_MACHINE, HOLD_STATE_MACHINE, MANUAL_STATE_MACHINE, PAYMENT_FLOW_STATE_MACHINE, SETTLEMENT_STATE_MACHINE, SPLIT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, StateChangeEvent, StateMachine, TRANSACTION_STATE_MACHINE, smFor };
@@ -1,32 +1,52 @@
1
- import { F as TRANSACTION_STATUS, r as SPLIT_STATUS, u as SETTLEMENT_STATUS, v as SUBSCRIPTION_STATUS, w as HOLD_STATUS } from "../split.enums-CQE3ekH1.mjs";
2
- import { r as InvalidStateTransitionError } from "../errors-DHa8JVQ-.mjs";
1
+ import { _ as TRANSACTION_STATUS, a as TRANSACTION_KIND } from "../bank-feed.enums-kYTLTTbe.mjs";
2
+ import { g as SETTLEMENT_STATUS, l as SPLIT_STATUS, r as SUBSCRIPTION_STATUS, w as HOLD_STATUS } from "../subscription.enums-DoIr56O6.mjs";
3
+ import { a as InvalidStateTransitionError } from "../errors-Dt46UZL_.mjs";
4
+ import { defineStateMachine } from "@classytic/primitives/state-machine";
3
5
 
4
6
  //#region src/core/state-machines.ts
7
+ /**
8
+ * Revenue's typed state machine.
9
+ *
10
+ * Thin facade over `@classytic/primitives/state-machine`'s
11
+ * `defineStateMachine` — primitives owns the transition logic, revenue
12
+ * owns the API shape (`validate`, `getAllowedTransitions`,
13
+ * `validateAndCreateAuditEvent`) that the existing repos and tests
14
+ * depend on. Wires `InvalidStateTransitionError` through the primitive's
15
+ * `errorFactory` so thrown types are unchanged.
16
+ *
17
+ * The constructor still accepts `Map<TState, Set<TState>>` so existing
18
+ * instance definitions don't need to be rewritten.
19
+ */
5
20
  var StateMachine = class {
21
+ inner;
6
22
  constructor(transitions, resourceType) {
7
- this.transitions = transitions;
8
- this.resourceType = resourceType;
23
+ const record = {};
24
+ for (const [from, toSet] of transitions.entries()) record[from] = Array.from(toSet);
25
+ this.inner = defineStateMachine({
26
+ name: resourceType,
27
+ transitions: record,
28
+ errorFactory: ({ entityId, from, to }) => new InvalidStateTransitionError(resourceType, entityId, from, to)
29
+ });
9
30
  }
10
31
  validate(from, to, resourceId) {
11
- if (!this.transitions.get(from)?.has(to)) throw new InvalidStateTransitionError(this.resourceType, resourceId, from, to);
32
+ this.inner.assertTransition(resourceId, from, to);
12
33
  }
13
34
  canTransition(from, to) {
14
- return this.transitions.get(from)?.has(to) ?? false;
35
+ return this.inner.canTransition(from, to);
15
36
  }
16
37
  getAllowedTransitions(from) {
17
- return Array.from(this.transitions.get(from) ?? []);
38
+ return [...this.inner.transitions[from] ?? []];
18
39
  }
19
40
  isTerminalState(state) {
20
- const t = this.transitions.get(state);
21
- return !t || t.size === 0;
41
+ return this.inner.isTerminal(state);
22
42
  }
23
43
  getResourceType() {
24
- return this.resourceType;
44
+ return this.inner.name;
25
45
  }
26
46
  validateAndCreateAuditEvent(from, to, resourceId, context) {
27
47
  this.validate(from, to, resourceId);
28
48
  return {
29
- resourceType: this.resourceType,
49
+ resourceType: this.inner.name,
30
50
  resourceId,
31
51
  fromState: from,
32
52
  toState: to,
@@ -129,6 +149,45 @@ const SPLIT_STATE_MACHINE = new StateMachine(new Map([
129
149
  [SPLIT_STATUS.WAIVED, /* @__PURE__ */ new Set([])],
130
150
  [SPLIT_STATUS.CANCELLED, /* @__PURE__ */ new Set([])]
131
151
  ]), "split");
152
+ const PAYMENT_FLOW_STATE_MACHINE = TRANSACTION_STATE_MACHINE;
153
+ const BANK_FEED_STATE_MACHINE = new StateMachine(new Map([
154
+ [TRANSACTION_STATUS.IMPORTED, new Set([TRANSACTION_STATUS.MATCHED, TRANSACTION_STATUS.REJECTED])],
155
+ [TRANSACTION_STATUS.MATCHED, new Set([TRANSACTION_STATUS.IMPORTED, TRANSACTION_STATUS.JOURNALIZED])],
156
+ [TRANSACTION_STATUS.JOURNALIZED, /* @__PURE__ */ new Set([])],
157
+ [TRANSACTION_STATUS.REJECTED, /* @__PURE__ */ new Set([])]
158
+ ]), "transaction.bank_feed");
159
+ const MANUAL_STATE_MACHINE = new StateMachine(new Map([
160
+ [TRANSACTION_STATUS.PENDING, new Set([TRANSACTION_STATUS.MATCHED, TRANSACTION_STATUS.REJECTED])],
161
+ [TRANSACTION_STATUS.MATCHED, new Set([TRANSACTION_STATUS.JOURNALIZED])],
162
+ [TRANSACTION_STATUS.JOURNALIZED, /* @__PURE__ */ new Set([])],
163
+ [TRANSACTION_STATUS.REJECTED, /* @__PURE__ */ new Set([])]
164
+ ]), "transaction.manual");
165
+ /**
166
+ * Select the state machine that governs a transaction row, given its
167
+ * `kind`. Repo verbs call this at the start of every state transition
168
+ * so the same `from → to` rules apply on both the in-memory check
169
+ * (state machine) and the atomic CAS (mongokit `claim()` with the
170
+ * `where: { kind }` predicate).
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * const machine = smFor(transaction.kind);
175
+ * machine.validate(transaction.status, 'matched', String(transaction._id));
176
+ * await this.claim(id, {
177
+ * from: ['imported', 'matched'],
178
+ * to: 'matched',
179
+ * where: { kind: transaction.kind },
180
+ * }, patch, opts);
181
+ * ```
182
+ */
183
+ function smFor(kind) {
184
+ switch (kind) {
185
+ case TRANSACTION_KIND.BANK_FEED: return BANK_FEED_STATE_MACHINE;
186
+ case TRANSACTION_KIND.MANUAL: return MANUAL_STATE_MACHINE;
187
+ case TRANSACTION_KIND.PAYMENT_FLOW:
188
+ default: return PAYMENT_FLOW_STATE_MACHINE;
189
+ }
190
+ }
132
191
 
133
192
  //#endregion
134
- export { HOLD_STATE_MACHINE, SETTLEMENT_STATE_MACHINE, SPLIT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, StateMachine, TRANSACTION_STATE_MACHINE };
193
+ export { BANK_FEED_STATE_MACHINE, HOLD_STATE_MACHINE, MANUAL_STATE_MACHINE, PAYMENT_FLOW_STATE_MACHINE, SETTLEMENT_STATE_MACHINE, SPLIT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, StateMachine, TRANSACTION_STATE_MACHINE, smFor };