@drawbridge/drawbridge-utils 0.0.28 → 0.0.31
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/dist/ai.cjs +82 -75
- package/dist/ai.d.cts +72 -29
- package/dist/ai.d.ts +72 -29
- package/dist/ai.js +42 -14
- package/dist/chunk-6S43OFA7.js +115 -0
- package/dist/transactions.cjs +58 -98
- package/dist/transactions.d.cts +101 -127
- package/dist/transactions.d.ts +101 -127
- package/dist/transactions.js +1 -3
- package/package.json +1 -1
- package/dist/chunk-RC5E56UB.js +0 -154
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// transactions.js
|
|
2
|
+
var insertTransaction = async ({
|
|
3
|
+
db,
|
|
4
|
+
user,
|
|
5
|
+
userId,
|
|
6
|
+
type,
|
|
7
|
+
category,
|
|
8
|
+
source,
|
|
9
|
+
amount,
|
|
10
|
+
_id,
|
|
11
|
+
stripeInvoiceId,
|
|
12
|
+
stripeEventId,
|
|
13
|
+
session,
|
|
14
|
+
...rest
|
|
15
|
+
}) => {
|
|
16
|
+
var _a;
|
|
17
|
+
const beforeRaw = (_a = user == null ? void 0 : user.balance) == null ? void 0 : _a[type];
|
|
18
|
+
const balance = typeof beforeRaw === "number" ? { before: beforeRaw, after: beforeRaw + amount } : void 0;
|
|
19
|
+
await db.create({
|
|
20
|
+
authenticated: user,
|
|
21
|
+
collection: "transaction",
|
|
22
|
+
data: {
|
|
23
|
+
..._id && { _id },
|
|
24
|
+
userId,
|
|
25
|
+
type,
|
|
26
|
+
category,
|
|
27
|
+
source,
|
|
28
|
+
amount,
|
|
29
|
+
...balance && { balance },
|
|
30
|
+
...rest,
|
|
31
|
+
...stripeInvoiceId && { stripeInvoiceId },
|
|
32
|
+
...stripeEventId && { stripeEventId }
|
|
33
|
+
},
|
|
34
|
+
...session && { options: { session } }
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
var credit = async ({
|
|
38
|
+
db,
|
|
39
|
+
user,
|
|
40
|
+
userId,
|
|
41
|
+
amount,
|
|
42
|
+
type,
|
|
43
|
+
category,
|
|
44
|
+
source,
|
|
45
|
+
_id,
|
|
46
|
+
stripeInvoiceId,
|
|
47
|
+
stripeEventId,
|
|
48
|
+
session,
|
|
49
|
+
...rest
|
|
50
|
+
}) => {
|
|
51
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
52
|
+
throw new Error(`credit() requires a positive integer amount, got ${amount}`);
|
|
53
|
+
}
|
|
54
|
+
if (!type) {
|
|
55
|
+
throw new Error('credit() requires a type (e.g., "ai")');
|
|
56
|
+
}
|
|
57
|
+
if (!source) {
|
|
58
|
+
throw new Error('credit() requires a source ("system" | "admin" | "user")');
|
|
59
|
+
}
|
|
60
|
+
await insertTransaction({
|
|
61
|
+
db,
|
|
62
|
+
user,
|
|
63
|
+
userId,
|
|
64
|
+
type,
|
|
65
|
+
category,
|
|
66
|
+
source,
|
|
67
|
+
amount,
|
|
68
|
+
_id,
|
|
69
|
+
stripeInvoiceId,
|
|
70
|
+
stripeEventId,
|
|
71
|
+
session,
|
|
72
|
+
...rest
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
var debit = async ({
|
|
76
|
+
db,
|
|
77
|
+
user,
|
|
78
|
+
userId,
|
|
79
|
+
amount,
|
|
80
|
+
type,
|
|
81
|
+
category,
|
|
82
|
+
source,
|
|
83
|
+
stripeInvoiceId,
|
|
84
|
+
stripeEventId,
|
|
85
|
+
session,
|
|
86
|
+
...rest
|
|
87
|
+
}) => {
|
|
88
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
89
|
+
throw new Error(`debit() requires a positive integer amount, got ${amount}`);
|
|
90
|
+
}
|
|
91
|
+
if (!type) {
|
|
92
|
+
throw new Error('debit() requires a type (e.g., "ai")');
|
|
93
|
+
}
|
|
94
|
+
if (!source) {
|
|
95
|
+
throw new Error('debit() requires a source ("system" | "admin" | "user")');
|
|
96
|
+
}
|
|
97
|
+
await insertTransaction({
|
|
98
|
+
db,
|
|
99
|
+
user,
|
|
100
|
+
userId,
|
|
101
|
+
type,
|
|
102
|
+
category,
|
|
103
|
+
source,
|
|
104
|
+
amount: -amount,
|
|
105
|
+
stripeInvoiceId,
|
|
106
|
+
stripeEventId,
|
|
107
|
+
session,
|
|
108
|
+
...rest
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
credit,
|
|
114
|
+
debit
|
|
115
|
+
};
|
package/dist/transactions.cjs
CHANGED
|
@@ -19,161 +19,121 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// transactions.js
|
|
20
20
|
var transactions_exports = {};
|
|
21
21
|
__export(transactions_exports, {
|
|
22
|
-
InsufficientCreditsError: () => InsufficientCreditsError,
|
|
23
22
|
credit: () => credit,
|
|
24
23
|
debit: () => debit
|
|
25
24
|
});
|
|
26
25
|
module.exports = __toCommonJS(transactions_exports);
|
|
27
|
-
var
|
|
26
|
+
var insertTransaction = async ({
|
|
28
27
|
db,
|
|
29
|
-
|
|
28
|
+
user,
|
|
30
29
|
userId,
|
|
30
|
+
type,
|
|
31
31
|
category,
|
|
32
|
-
|
|
32
|
+
source,
|
|
33
33
|
amount,
|
|
34
|
-
|
|
35
|
-
provider,
|
|
34
|
+
_id,
|
|
36
35
|
stripeInvoiceId,
|
|
37
|
-
stripeEventId
|
|
36
|
+
stripeEventId,
|
|
37
|
+
session,
|
|
38
|
+
...rest
|
|
38
39
|
}) => {
|
|
40
|
+
var _a;
|
|
41
|
+
const beforeRaw = (_a = user == null ? void 0 : user.balance) == null ? void 0 : _a[type];
|
|
42
|
+
const balance = typeof beforeRaw === "number" ? { before: beforeRaw, after: beforeRaw + amount } : void 0;
|
|
39
43
|
await db.create({
|
|
40
|
-
authenticated,
|
|
41
|
-
collection: "
|
|
44
|
+
authenticated: user,
|
|
45
|
+
collection: "transaction",
|
|
42
46
|
data: {
|
|
47
|
+
..._id && { _id },
|
|
43
48
|
userId,
|
|
44
|
-
|
|
45
|
-
item: "ai"
|
|
46
|
-
},
|
|
49
|
+
type,
|
|
47
50
|
category,
|
|
48
|
-
|
|
51
|
+
source,
|
|
49
52
|
amount,
|
|
50
|
-
balance,
|
|
51
|
-
...
|
|
53
|
+
...balance && { balance },
|
|
54
|
+
...rest,
|
|
52
55
|
...stripeInvoiceId && { stripeInvoiceId },
|
|
53
56
|
...stripeEventId && { stripeEventId }
|
|
54
|
-
}
|
|
57
|
+
},
|
|
58
|
+
...session && { options: { session } }
|
|
55
59
|
});
|
|
56
60
|
};
|
|
57
61
|
var credit = async ({
|
|
58
62
|
db,
|
|
59
|
-
|
|
63
|
+
user,
|
|
60
64
|
userId,
|
|
61
65
|
amount,
|
|
66
|
+
type,
|
|
62
67
|
category,
|
|
63
|
-
|
|
68
|
+
source,
|
|
69
|
+
_id,
|
|
64
70
|
stripeInvoiceId,
|
|
65
|
-
stripeEventId
|
|
71
|
+
stripeEventId,
|
|
72
|
+
session,
|
|
73
|
+
...rest
|
|
66
74
|
}) => {
|
|
67
|
-
var _a, _b, _c;
|
|
68
75
|
if (!Number.isInteger(amount) || amount <= 0) {
|
|
69
76
|
throw new Error(`credit() requires a positive integer amount, got ${amount}`);
|
|
70
77
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
collection: "users",
|
|
74
|
-
query: {
|
|
75
|
-
id: userId
|
|
76
|
-
},
|
|
77
|
-
data: {
|
|
78
|
-
$inc: {
|
|
79
|
-
"balance.ai": amount
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
const after = ((_b = (_a = result == null ? void 0 : result.value) == null ? void 0 : _a.balance) == null ? void 0 : _b.ai) ?? ((_c = result == null ? void 0 : result.balance) == null ? void 0 : _c.ai);
|
|
84
|
-
if (typeof after !== "number") {
|
|
85
|
-
throw new Error(`credit() could not read updated balance for user ${userId}`);
|
|
78
|
+
if (!type) {
|
|
79
|
+
throw new Error('credit() requires a type (e.g., "ai")');
|
|
86
80
|
}
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
if (!source) {
|
|
82
|
+
throw new Error('credit() requires a source ("system" | "admin" | "user")');
|
|
83
|
+
}
|
|
84
|
+
await insertTransaction({
|
|
89
85
|
db,
|
|
90
|
-
|
|
86
|
+
user,
|
|
91
87
|
userId,
|
|
88
|
+
type,
|
|
92
89
|
category,
|
|
93
|
-
|
|
90
|
+
source,
|
|
94
91
|
amount,
|
|
95
|
-
|
|
96
|
-
before,
|
|
97
|
-
after
|
|
98
|
-
},
|
|
92
|
+
_id,
|
|
99
93
|
stripeInvoiceId,
|
|
100
|
-
stripeEventId
|
|
94
|
+
stripeEventId,
|
|
95
|
+
session,
|
|
96
|
+
...rest
|
|
101
97
|
});
|
|
102
|
-
return {
|
|
103
|
-
balance: {
|
|
104
|
-
before,
|
|
105
|
-
after
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
var InsufficientCreditsError = class extends Error {
|
|
110
|
-
constructor(message = "Insufficient AI credits") {
|
|
111
|
-
super(message);
|
|
112
|
-
this.name = "InsufficientCreditsError";
|
|
113
|
-
this.status = 402;
|
|
114
|
-
}
|
|
115
98
|
};
|
|
116
99
|
var debit = async ({
|
|
117
100
|
db,
|
|
118
|
-
|
|
101
|
+
user,
|
|
119
102
|
userId,
|
|
120
103
|
amount,
|
|
104
|
+
type,
|
|
121
105
|
category,
|
|
122
|
-
|
|
123
|
-
provider,
|
|
106
|
+
source,
|
|
124
107
|
stripeInvoiceId,
|
|
125
|
-
stripeEventId
|
|
108
|
+
stripeEventId,
|
|
109
|
+
session,
|
|
110
|
+
...rest
|
|
126
111
|
}) => {
|
|
127
|
-
var _a, _b, _c;
|
|
128
112
|
if (!Number.isInteger(amount) || amount <= 0) {
|
|
129
113
|
throw new Error(`debit() requires a positive integer amount, got ${amount}`);
|
|
130
114
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
collection: "users",
|
|
134
|
-
query: {
|
|
135
|
-
id: userId,
|
|
136
|
-
"balance.ai": {
|
|
137
|
-
$gte: amount
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
data: {
|
|
141
|
-
$inc: {
|
|
142
|
-
"balance.ai": -amount
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
const after = ((_b = (_a = result == null ? void 0 : result.value) == null ? void 0 : _a.balance) == null ? void 0 : _b.ai) ?? ((_c = result == null ? void 0 : result.balance) == null ? void 0 : _c.ai);
|
|
147
|
-
if (typeof after !== "number") {
|
|
148
|
-
throw new InsufficientCreditsError();
|
|
115
|
+
if (!type) {
|
|
116
|
+
throw new Error('debit() requires a type (e.g., "ai")');
|
|
149
117
|
}
|
|
150
|
-
|
|
151
|
-
|
|
118
|
+
if (!source) {
|
|
119
|
+
throw new Error('debit() requires a source ("system" | "admin" | "user")');
|
|
120
|
+
}
|
|
121
|
+
await insertTransaction({
|
|
152
122
|
db,
|
|
153
|
-
|
|
123
|
+
user,
|
|
154
124
|
userId,
|
|
125
|
+
type,
|
|
155
126
|
category,
|
|
156
|
-
|
|
127
|
+
source,
|
|
157
128
|
amount: -amount,
|
|
158
|
-
balance: {
|
|
159
|
-
before,
|
|
160
|
-
after
|
|
161
|
-
},
|
|
162
|
-
provider,
|
|
163
129
|
stripeInvoiceId,
|
|
164
|
-
stripeEventId
|
|
130
|
+
stripeEventId,
|
|
131
|
+
session,
|
|
132
|
+
...rest
|
|
165
133
|
});
|
|
166
|
-
return {
|
|
167
|
-
amount: -amount,
|
|
168
|
-
balance: {
|
|
169
|
-
before,
|
|
170
|
-
after
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
134
|
};
|
|
174
135
|
// Annotate the CommonJS export names for ESM import in node:
|
|
175
136
|
0 && (module.exports = {
|
|
176
|
-
InsufficientCreditsError,
|
|
177
137
|
credit,
|
|
178
138
|
debit
|
|
179
139
|
});
|
package/dist/transactions.d.cts
CHANGED
|
@@ -1,68 +1,88 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Ledger transaction insert helpers — no balance writes happen here.
|
|
2
|
+
//
|
|
3
|
+
// User-balance updates are the exclusive job of drawbridge-sync's
|
|
4
|
+
// stream/transaction.js change-stream listener: every insert into the
|
|
5
|
+
// `transaction` collection triggers an atomic $inc on user.balance.<type>
|
|
6
|
+
// (guarded against going negative). This decouples the API surface from
|
|
7
|
+
// the balance arithmetic and makes the `transaction` collection the single
|
|
8
|
+
// source of truth for both audit history and balance derivation.
|
|
5
9
|
//
|
|
6
10
|
// import { credit, debit } from '@drawbridge/drawbridge-utils/transactions';
|
|
7
11
|
//
|
|
8
|
-
// await credit({ db,
|
|
9
|
-
// category: 'promotional',
|
|
12
|
+
// await credit({ db, user, amount: 500,
|
|
13
|
+
// type: 'ai', category: 'promotional', source: 'system' });
|
|
10
14
|
//
|
|
11
|
-
// await debit({ db,
|
|
12
|
-
//
|
|
13
|
-
//
|
|
15
|
+
// await debit({ db, user, amount: 6,
|
|
16
|
+
// type: 'ai', category: 'usage', source: 'user',
|
|
17
|
+
// ai: { name, model, tokens, rates, totals } });
|
|
14
18
|
//
|
|
15
|
-
// `db` is the wrapper returned by @drawbridge/mongodb — credit/debit
|
|
16
|
-
// against its `.create
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
19
|
+
// `db` is the wrapper returned by @drawbridge/mongodb — credit/debit
|
|
20
|
+
// duck-type against its `.create` interface so this module has no hard dep.
|
|
21
|
+
//
|
|
22
|
+
// `user` is the user the transaction is being recorded against. The helper
|
|
23
|
+
// reads `user.balance.<type>` to stamp `balance: { before, after }` on the
|
|
24
|
+
// row as an audit snapshot of what the actor saw at action time — useful
|
|
25
|
+
// for support / dispute resolution. When `balance.<type>` isn't on the user
|
|
26
|
+
// (fresh signup, webhook-initiated row), the snapshot is omitted, which is
|
|
27
|
+
// the honest representation of "no prior view to record".
|
|
28
|
+
|
|
29
|
+
const insertTransaction = async ({
|
|
21
30
|
db,
|
|
22
|
-
|
|
31
|
+
user,
|
|
23
32
|
userId,
|
|
33
|
+
type,
|
|
24
34
|
category,
|
|
25
|
-
|
|
35
|
+
source,
|
|
26
36
|
amount,
|
|
27
|
-
|
|
28
|
-
provider,
|
|
37
|
+
_id,
|
|
29
38
|
stripeInvoiceId,
|
|
30
|
-
stripeEventId
|
|
39
|
+
stripeEventId,
|
|
40
|
+
session,
|
|
41
|
+
...rest
|
|
31
42
|
}) => {
|
|
32
43
|
|
|
44
|
+
const beforeRaw = user?.balance?.[ type ];
|
|
45
|
+
const balance = typeof beforeRaw === 'number'
|
|
46
|
+
? { before : beforeRaw, after : beforeRaw + amount }
|
|
47
|
+
: undefined;
|
|
48
|
+
|
|
33
49
|
await db.create({
|
|
34
|
-
authenticated,
|
|
35
|
-
collection : '
|
|
50
|
+
authenticated : user,
|
|
51
|
+
collection : 'transaction',
|
|
36
52
|
data : {
|
|
53
|
+
...( _id && { _id }),
|
|
37
54
|
userId,
|
|
38
|
-
|
|
39
|
-
item : 'ai'
|
|
40
|
-
},
|
|
55
|
+
type,
|
|
41
56
|
category,
|
|
42
|
-
|
|
57
|
+
source,
|
|
43
58
|
amount,
|
|
44
|
-
balance,
|
|
45
|
-
...
|
|
59
|
+
...( balance && { balance }),
|
|
60
|
+
...rest,
|
|
46
61
|
...( stripeInvoiceId && { stripeInvoiceId }),
|
|
47
62
|
...( stripeEventId && { stripeEventId })
|
|
48
|
-
}
|
|
63
|
+
},
|
|
64
|
+
...( session && { options : { session } })
|
|
49
65
|
});
|
|
50
66
|
|
|
51
67
|
};
|
|
52
68
|
|
|
53
|
-
// Additive:
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
69
|
+
// Additive: record a credit. The stream handler does the $inc separately.
|
|
70
|
+
// Optional `_id` lets callers pre-generate the transaction's ObjectId — the
|
|
71
|
+
// top-up route stamps it onto the Stripe invoice metadata so Stripe-side and
|
|
72
|
+
// Mongo-side IDs match for cross-system reconciliation.
|
|
57
73
|
const credit = async ({
|
|
58
74
|
db,
|
|
59
|
-
|
|
75
|
+
user,
|
|
60
76
|
userId,
|
|
61
77
|
amount,
|
|
78
|
+
type,
|
|
62
79
|
category,
|
|
63
|
-
|
|
80
|
+
source,
|
|
81
|
+
_id,
|
|
64
82
|
stripeInvoiceId,
|
|
65
|
-
stripeEventId
|
|
83
|
+
stripeEventId,
|
|
84
|
+
session,
|
|
85
|
+
...rest
|
|
66
86
|
}) => {
|
|
67
87
|
|
|
68
88
|
if( !Number.isInteger( amount ) || amount <= 0 ){
|
|
@@ -71,80 +91,58 @@ const credit = async ({
|
|
|
71
91
|
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
authenticated,
|
|
76
|
-
collection : 'users',
|
|
77
|
-
query : {
|
|
78
|
-
id : userId
|
|
79
|
-
},
|
|
80
|
-
data : {
|
|
81
|
-
$inc : {
|
|
82
|
-
'balance.ai' : amount
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
94
|
+
if( !type ){
|
|
86
95
|
|
|
87
|
-
|
|
96
|
+
throw new Error( 'credit() requires a type (e.g., "ai")' );
|
|
88
97
|
|
|
89
|
-
|
|
98
|
+
}
|
|
90
99
|
|
|
91
|
-
|
|
100
|
+
if( !source ){
|
|
92
101
|
|
|
93
|
-
|
|
102
|
+
throw new Error( 'credit() requires a source ("system" | "admin" | "user")' );
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
}
|
|
96
105
|
|
|
97
|
-
await
|
|
106
|
+
await insertTransaction({
|
|
98
107
|
db,
|
|
99
|
-
|
|
108
|
+
user,
|
|
100
109
|
userId,
|
|
110
|
+
type,
|
|
101
111
|
category,
|
|
102
|
-
|
|
112
|
+
source,
|
|
103
113
|
amount,
|
|
104
|
-
|
|
105
|
-
before,
|
|
106
|
-
after
|
|
107
|
-
},
|
|
114
|
+
_id,
|
|
108
115
|
stripeInvoiceId,
|
|
109
|
-
stripeEventId
|
|
116
|
+
stripeEventId,
|
|
117
|
+
session,
|
|
118
|
+
...rest
|
|
110
119
|
});
|
|
111
120
|
|
|
112
|
-
return {
|
|
113
|
-
balance : {
|
|
114
|
-
before,
|
|
115
|
-
after
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
121
|
};
|
|
120
122
|
|
|
121
|
-
// Subtractive:
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.status = 402;
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
123
|
+
// Subtractive: record a debit (negative amount). The stream handler's $inc
|
|
124
|
+
// is guarded against negative balance — if the resulting balance would be
|
|
125
|
+
// less than zero, the $inc is skipped and the row stays as audit-only.
|
|
126
|
+
// Callers (e.g., ai.js) pre-compute `amount` from their domain-specific
|
|
127
|
+
// pricing.
|
|
128
|
+
//
|
|
129
|
+
// Note: there is no synchronous gate here. The atomic gate-and-decrement
|
|
130
|
+
// pattern moves to the AI middleware (`balance.<type> >= MAX_REQUEST_CENTS`)
|
|
131
|
+
// plus the stream-side $inc guard. Concurrent debits with low balance can
|
|
132
|
+
// race past the middleware check but the stream guard prevents the actual
|
|
133
|
+
// balance from going negative.
|
|
138
134
|
const debit = async ({
|
|
139
135
|
db,
|
|
140
|
-
|
|
136
|
+
user,
|
|
141
137
|
userId,
|
|
142
138
|
amount,
|
|
139
|
+
type,
|
|
143
140
|
category,
|
|
144
|
-
|
|
145
|
-
provider,
|
|
141
|
+
source,
|
|
146
142
|
stripeInvoiceId,
|
|
147
|
-
stripeEventId
|
|
143
|
+
stripeEventId,
|
|
144
|
+
session,
|
|
145
|
+
...rest
|
|
148
146
|
}) => {
|
|
149
147
|
|
|
150
148
|
if( !Number.isInteger( amount ) || amount <= 0 ){
|
|
@@ -153,56 +151,32 @@ const debit = async ({
|
|
|
153
151
|
|
|
154
152
|
}
|
|
155
153
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
query : {
|
|
160
|
-
id : userId,
|
|
161
|
-
'balance.ai' : {
|
|
162
|
-
$gte : amount
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
data : {
|
|
166
|
-
$inc : {
|
|
167
|
-
'balance.ai' : -amount
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
});
|
|
154
|
+
if( !type ){
|
|
155
|
+
|
|
156
|
+
throw new Error( 'debit() requires a type (e.g., "ai")' );
|
|
171
157
|
|
|
172
|
-
|
|
158
|
+
}
|
|
173
159
|
|
|
174
|
-
if(
|
|
160
|
+
if( !source ){
|
|
175
161
|
|
|
176
|
-
throw new
|
|
162
|
+
throw new Error( 'debit() requires a source ("system" | "admin" | "user")' );
|
|
177
163
|
|
|
178
164
|
}
|
|
179
165
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
await recordTransaction({
|
|
166
|
+
await insertTransaction({
|
|
183
167
|
db,
|
|
184
|
-
|
|
168
|
+
user,
|
|
185
169
|
userId,
|
|
170
|
+
type,
|
|
186
171
|
category,
|
|
187
|
-
|
|
172
|
+
source,
|
|
188
173
|
amount : -amount,
|
|
189
|
-
balance : {
|
|
190
|
-
before,
|
|
191
|
-
after
|
|
192
|
-
},
|
|
193
|
-
provider,
|
|
194
174
|
stripeInvoiceId,
|
|
195
|
-
stripeEventId
|
|
175
|
+
stripeEventId,
|
|
176
|
+
session,
|
|
177
|
+
...rest
|
|
196
178
|
});
|
|
197
179
|
|
|
198
|
-
return {
|
|
199
|
-
amount : -amount,
|
|
200
|
-
balance : {
|
|
201
|
-
before,
|
|
202
|
-
after
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
|
|
206
180
|
};
|
|
207
181
|
|
|
208
|
-
export {
|
|
182
|
+
export { credit, debit };
|