@wopr-network/platform-core 1.13.2 → 1.14.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 (238) hide show
  1. package/dist/api/routes/admin-credits.d.ts +2 -2
  2. package/dist/api/routes/admin-credits.js +9 -4
  3. package/dist/api/routes/quota.d.ts +2 -2
  4. package/dist/api/routes/verify-email.d.ts +3 -3
  5. package/dist/backup/on-demand-snapshot-service.d.ts +2 -2
  6. package/dist/billing/payram/webhook.d.ts +3 -3
  7. package/dist/billing/payram/webhook.js +5 -1
  8. package/dist/billing/payram/webhook.test.js +5 -4
  9. package/dist/billing/stripe/stripe-payment-processor.d.ts +2 -2
  10. package/dist/billing/stripe/stripe-payment-processor.test.js +7 -0
  11. package/dist/billing/stripe/tenant-store.d.ts +1 -1
  12. package/dist/billing/stripe/tenant-store.js +1 -1
  13. package/dist/credits/auto-topup-charge.d.ts +2 -2
  14. package/dist/credits/auto-topup-charge.js +5 -1
  15. package/dist/credits/auto-topup-charge.test.js +5 -4
  16. package/dist/credits/auto-topup-usage.d.ts +2 -2
  17. package/dist/credits/auto-topup-usage.test.js +53 -12
  18. package/dist/credits/credit-expiry-cron.d.ts +2 -2
  19. package/dist/credits/credit-expiry-cron.js +7 -4
  20. package/dist/credits/credit-expiry-cron.test.js +25 -8
  21. package/dist/credits/credit-ledger.d.ts +2 -2
  22. package/dist/credits/credit-ledger.js +1 -1
  23. package/dist/credits/dividend-cron.d.ts +4 -6
  24. package/dist/credits/dividend-cron.js +10 -16
  25. package/dist/credits/dividend-cron.test.js +31 -44
  26. package/dist/credits/dividend-repository.js +19 -22
  27. package/dist/credits/dividend-repository.test.js +4 -3
  28. package/dist/credits/index.d.ts +4 -2
  29. package/dist/credits/index.js +2 -1
  30. package/dist/credits/ledger.d.ts +195 -0
  31. package/dist/credits/ledger.js +561 -0
  32. package/dist/credits/ledger.test.js +418 -0
  33. package/dist/credits/signup-grant.d.ts +2 -2
  34. package/dist/credits/signup-grant.js +4 -4
  35. package/dist/credits/signup-grant.test.js +5 -3
  36. package/dist/credits/trial-balance-cron.d.ts +19 -0
  37. package/dist/credits/trial-balance-cron.js +30 -0
  38. package/dist/credits/trial-balance-cron.test.js +55 -0
  39. package/dist/db/schema/gateway-service-keys.d.ts +109 -0
  40. package/dist/db/schema/gateway-service-keys.js +18 -0
  41. package/dist/db/schema/index.d.ts +2 -0
  42. package/dist/db/schema/index.js +2 -0
  43. package/dist/db/schema/ledger.d.ts +442 -0
  44. package/dist/db/schema/ledger.js +76 -0
  45. package/dist/gateway/credit-gate.d.ts +2 -2
  46. package/dist/gateway/credit-gate.js +5 -1
  47. package/dist/gateway/credit-gate.test.js +35 -33
  48. package/dist/gateway/gateway-routes.test.js +1 -1
  49. package/dist/gateway/index.d.ts +2 -0
  50. package/dist/gateway/index.js +1 -0
  51. package/dist/gateway/protocol/anthropic.js +1 -1
  52. package/dist/gateway/protocol/deps.d.ts +5 -5
  53. package/dist/gateway/protocol/openai.js +1 -1
  54. package/dist/gateway/proxy.d.ts +4 -4
  55. package/dist/gateway/route-mounting.test.js +1 -1
  56. package/dist/gateway/service-key-auth.d.ts +1 -1
  57. package/dist/gateway/service-key-auth.js +1 -1
  58. package/dist/gateway/service-key-repository.d.ts +27 -0
  59. package/dist/gateway/service-key-repository.js +64 -0
  60. package/dist/gateway/types.d.ts +5 -5
  61. package/dist/metering/reconciliation-cron.test.js +9 -8
  62. package/dist/metering/reconciliation-repository.js +12 -10
  63. package/dist/metering/reconciliation-repository.test.js +9 -8
  64. package/dist/monetization/affiliate/affiliate-admin-repository.js +10 -8
  65. package/dist/monetization/affiliate/affiliate-admin-repository.test.js +32 -13
  66. package/dist/monetization/affiliate/credit-match.d.ts +2 -2
  67. package/dist/monetization/affiliate/credit-match.js +4 -1
  68. package/dist/monetization/affiliate/credit-match.test.js +58 -13
  69. package/dist/monetization/affiliate/new-user-bonus.d.ts +2 -2
  70. package/dist/monetization/affiliate/new-user-bonus.js +4 -1
  71. package/dist/monetization/affiliate/new-user-bonus.test.js +4 -3
  72. package/dist/monetization/credits/auto-topup-charge.d.ts +2 -2
  73. package/dist/monetization/credits/auto-topup-charge.js +5 -1
  74. package/dist/monetization/credits/auto-topup-charge.test.js +5 -4
  75. package/dist/monetization/credits/auto-topup-usage.d.ts +2 -2
  76. package/dist/monetization/credits/auto-topup-usage.test.js +53 -12
  77. package/dist/monetization/credits/bot-billing.d.ts +3 -3
  78. package/dist/monetization/credits/bot-billing.test.js +18 -5
  79. package/dist/monetization/credits/credit-expiry-cron.test.js +25 -8
  80. package/dist/monetization/credits/dividend-cron.d.ts +2 -4
  81. package/dist/monetization/credits/dividend-cron.js +7 -4
  82. package/dist/monetization/credits/dividend-cron.test.js +26 -46
  83. package/dist/monetization/credits/dividend-repository.js +15 -24
  84. package/dist/monetization/credits/dividend-repository.test.js +4 -3
  85. package/dist/monetization/credits/index.d.ts +2 -2
  86. package/dist/monetization/credits/index.js +1 -1
  87. package/dist/monetization/credits/member-usage.test.js +23 -10
  88. package/dist/monetization/credits/phone-billing.d.ts +2 -2
  89. package/dist/monetization/credits/phone-billing.js +5 -1
  90. package/dist/monetization/credits/phone-billing.test.js +9 -12
  91. package/dist/monetization/credits/runtime-cron.d.ts +2 -2
  92. package/dist/monetization/credits/runtime-cron.js +32 -8
  93. package/dist/monetization/credits/runtime-cron.test.js +28 -27
  94. package/dist/monetization/credits/runtime-scheduler.d.ts +2 -2
  95. package/dist/monetization/credits/runtime-scheduler.test.js +1 -1
  96. package/dist/monetization/credits/signup-grant.test.js +5 -3
  97. package/dist/monetization/credits/storage-tier-cron.test.js +3 -2
  98. package/dist/monetization/credits/trial-balance-cron.test.js +42 -0
  99. package/dist/monetization/feature-gate.d.ts +3 -3
  100. package/dist/monetization/index.d.ts +3 -3
  101. package/dist/monetization/index.js +1 -1
  102. package/dist/monetization/metering/reconciliation-cron.test.js +9 -8
  103. package/dist/monetization/metering/reconciliation-repository.js +11 -10
  104. package/dist/monetization/metering/reconciliation-repository.test.js +9 -8
  105. package/dist/monetization/payram/webhook.d.ts +2 -2
  106. package/dist/monetization/payram/webhook.js +5 -1
  107. package/dist/monetization/payram/webhook.test.js +5 -4
  108. package/dist/monetization/promotions/engine.d.ts +2 -2
  109. package/dist/monetization/promotions/engine.js +4 -1
  110. package/dist/monetization/promotions/engine.test.js +3 -1
  111. package/dist/monetization/repository-types.d.ts +1 -1
  112. package/dist/monetization/socket/socket.d.ts +3 -3
  113. package/dist/monetization/stripe/stripe-payment-processor.d.ts +2 -2
  114. package/dist/monetization/stripe/stripe-payment-processor.test.js +7 -0
  115. package/dist/monetization/stripe/webhook.d.ts +2 -2
  116. package/dist/monetization/stripe/webhook.js +70 -6
  117. package/dist/monetization/stripe/webhook.test.js +20 -15
  118. package/dist/onboarding/onboarding-service.d.ts +2 -2
  119. package/dist/onboarding/onboarding-service.js +6 -2
  120. package/drizzle/migrations/0002_gateway_service_keys.sql +14 -0
  121. package/drizzle/migrations/0003_double_entry_ledger.sql +82 -0
  122. package/drizzle/migrations/meta/_journal.json +14 -0
  123. package/package.json +1 -1
  124. package/src/api/routes/admin-credits.ts +11 -14
  125. package/src/api/routes/quota.ts +2 -2
  126. package/src/api/routes/verify-email.ts +4 -4
  127. package/src/backup/on-demand-snapshot-service.test.ts +3 -3
  128. package/src/backup/on-demand-snapshot-service.ts +3 -3
  129. package/src/billing/payram/webhook.test.ts +7 -5
  130. package/src/billing/payram/webhook.ts +8 -11
  131. package/src/billing/stripe/stripe-payment-processor.test.ts +10 -3
  132. package/src/billing/stripe/stripe-payment-processor.ts +3 -3
  133. package/src/billing/stripe/tenant-store.ts +1 -1
  134. package/src/credits/auto-topup-charge.test.ts +7 -5
  135. package/src/credits/auto-topup-charge.ts +7 -10
  136. package/src/credits/auto-topup-usage.test.ts +55 -13
  137. package/src/credits/auto-topup-usage.ts +2 -2
  138. package/src/credits/credit-expiry-cron.test.ts +26 -45
  139. package/src/credits/credit-expiry-cron.ts +9 -12
  140. package/src/credits/credit-ledger.ts +3 -3
  141. package/src/credits/dividend-cron.test.ts +38 -45
  142. package/src/credits/dividend-cron.ts +12 -26
  143. package/src/credits/dividend-repository.test.ts +4 -3
  144. package/src/credits/dividend-repository.ts +21 -23
  145. package/src/credits/index.ts +23 -4
  146. package/src/credits/ledger.test.ts +514 -0
  147. package/src/credits/ledger.ts +851 -0
  148. package/src/credits/signup-grant.test.ts +7 -4
  149. package/src/credits/signup-grant.ts +6 -12
  150. package/src/credits/trial-balance-cron.test.ts +68 -0
  151. package/src/credits/trial-balance-cron.ts +46 -0
  152. package/src/db/schema/gateway-service-keys.ts +23 -0
  153. package/src/db/schema/index.ts +2 -0
  154. package/src/db/schema/ledger.ts +94 -0
  155. package/src/gateway/credit-gate-wiring.test.ts +3 -3
  156. package/src/gateway/credit-gate.test.ts +35 -33
  157. package/src/gateway/credit-gate.ts +6 -10
  158. package/src/gateway/gateway-routes.test.ts +6 -6
  159. package/src/gateway/index.ts +2 -0
  160. package/src/gateway/protocol/anthropic.ts +2 -2
  161. package/src/gateway/protocol/deps.ts +5 -5
  162. package/src/gateway/protocol/openai.ts +2 -2
  163. package/src/gateway/proxy.ts +4 -4
  164. package/src/gateway/route-mounting.test.ts +3 -3
  165. package/src/gateway/service-key-auth.ts +4 -2
  166. package/src/gateway/service-key-repository.ts +87 -0
  167. package/src/gateway/types.ts +5 -5
  168. package/src/metering/reconciliation-cron.test.ts +10 -9
  169. package/src/metering/reconciliation-repository.test.ts +10 -9
  170. package/src/metering/reconciliation-repository.ts +14 -11
  171. package/src/monetization/affiliate/affiliate-admin-repository.test.ts +32 -19
  172. package/src/monetization/affiliate/affiliate-admin-repository.ts +16 -8
  173. package/src/monetization/affiliate/credit-match.test.ts +60 -14
  174. package/src/monetization/affiliate/credit-match.ts +6 -9
  175. package/src/monetization/affiliate/new-user-bonus.test.ts +6 -4
  176. package/src/monetization/affiliate/new-user-bonus.ts +6 -9
  177. package/src/monetization/credits/auto-topup-charge.test.ts +7 -5
  178. package/src/monetization/credits/auto-topup-charge.ts +7 -10
  179. package/src/monetization/credits/auto-topup-usage.test.ts +55 -13
  180. package/src/monetization/credits/auto-topup-usage.ts +2 -2
  181. package/src/monetization/credits/bot-billing.test.ts +20 -6
  182. package/src/monetization/credits/bot-billing.ts +3 -3
  183. package/src/monetization/credits/credit-expiry-cron.test.ts +26 -45
  184. package/src/monetization/credits/dividend-cron.test.ts +34 -48
  185. package/src/monetization/credits/dividend-cron.ts +9 -14
  186. package/src/monetization/credits/dividend-repository.test.ts +4 -3
  187. package/src/monetization/credits/dividend-repository.ts +19 -25
  188. package/src/monetization/credits/index.ts +4 -4
  189. package/src/monetization/credits/member-usage.test.ts +25 -11
  190. package/src/monetization/credits/phone-billing.test.ts +18 -26
  191. package/src/monetization/credits/phone-billing.ts +7 -10
  192. package/src/monetization/credits/runtime-cron.test.ts +29 -28
  193. package/src/monetization/credits/runtime-cron.ts +34 -58
  194. package/src/monetization/credits/runtime-scheduler.test.ts +1 -1
  195. package/src/monetization/credits/runtime-scheduler.ts +2 -2
  196. package/src/monetization/credits/signup-grant.test.ts +7 -4
  197. package/src/monetization/credits/storage-tier-cron.test.ts +5 -3
  198. package/src/monetization/credits/trial-balance-cron.test.ts +52 -0
  199. package/src/monetization/feature-gate.ts +3 -3
  200. package/src/monetization/index.ts +4 -4
  201. package/src/monetization/metering/reconciliation-cron.test.ts +10 -9
  202. package/src/monetization/metering/reconciliation-repository.test.ts +11 -9
  203. package/src/monetization/metering/reconciliation-repository.ts +13 -11
  204. package/src/monetization/payram/webhook.test.ts +7 -5
  205. package/src/monetization/payram/webhook.ts +7 -10
  206. package/src/monetization/promotions/engine.test.ts +6 -5
  207. package/src/monetization/promotions/engine.ts +6 -3
  208. package/src/monetization/repository-types.ts +1 -1
  209. package/src/monetization/socket/socket.ts +4 -4
  210. package/src/monetization/stripe/stripe-payment-processor.test.ts +10 -3
  211. package/src/monetization/stripe/stripe-payment-processor.ts +3 -3
  212. package/src/monetization/stripe/webhook.test.ts +22 -16
  213. package/src/monetization/stripe/webhook.ts +75 -50
  214. package/src/onboarding/onboarding-service.ts +8 -11
  215. package/dist/credits/credit-ledger-extra.test.js +0 -40
  216. package/dist/credits/credit-ledger.bench.js +0 -33
  217. package/dist/credits/credit-ledger.test.d.ts +0 -4
  218. package/dist/credits/credit-ledger.test.js +0 -203
  219. package/dist/credits/credit-transaction-repository.test.js +0 -232
  220. package/dist/monetization/credits/credit-ledger-extra.test.d.ts +0 -1
  221. package/dist/monetization/credits/credit-ledger-extra.test.js +0 -39
  222. package/dist/monetization/credits/credit-ledger.bench.d.ts +0 -1
  223. package/dist/monetization/credits/credit-ledger.bench.js +0 -32
  224. package/dist/monetization/credits/credit-ledger.test.d.ts +0 -4
  225. package/dist/monetization/credits/credit-ledger.test.js +0 -202
  226. package/dist/monetization/credits/credit-transaction-repository.test.d.ts +0 -1
  227. package/dist/monetization/credits/credit-transaction-repository.test.js +0 -232
  228. package/src/credits/credit-ledger-extra.test.ts +0 -57
  229. package/src/credits/credit-ledger.bench.ts +0 -56
  230. package/src/credits/credit-ledger.test.ts +0 -276
  231. package/src/credits/credit-transaction-repository.test.ts +0 -274
  232. package/src/monetization/credits/credit-ledger-extra.test.ts +0 -56
  233. package/src/monetization/credits/credit-ledger.bench.ts +0 -55
  234. package/src/monetization/credits/credit-ledger.test.ts +0 -275
  235. package/src/monetization/credits/credit-transaction-repository.test.ts +0 -274
  236. /package/dist/credits/{credit-ledger-extra.test.d.ts → ledger.test.d.ts} +0 -0
  237. /package/dist/credits/{credit-ledger.bench.d.ts → trial-balance-cron.test.d.ts} +0 -0
  238. /package/dist/{credits/credit-transaction-repository.test.d.ts → monetization/credits/trial-balance-cron.test.d.ts} +0 -0
@@ -1,28 +1,20 @@
1
- import {
2
- Credit,
3
- type CreditTransaction,
4
- type ICreditLedger,
5
- InsufficientBalanceError,
6
- } from "@wopr-network/platform-core/credits";
1
+ import { Credit, type ILedger, InsufficientBalanceError, type JournalEntry } from "@wopr-network/platform-core/credits";
7
2
  import type { IMeterEmitter } from "@wopr-network/platform-core/metering";
8
3
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
4
  import type { IPhoneNumberRepository } from "./drizzle-phone-number-repository.js";
10
5
  import { PHONE_NUMBER_MONTHLY_COST, runMonthlyPhoneBilling } from "./phone-billing.js";
11
6
  import type { ProvisionedPhoneNumber } from "./repository-types.js";
12
7
 
13
- function makeTx(tenantId: string): CreditTransaction {
8
+ function makeTx(tenantId: string): JournalEntry {
14
9
  return {
15
10
  id: "tx-1",
11
+ postedAt: new Date().toISOString(),
12
+ entryType: "addon",
16
13
  tenantId,
17
- amount: Credit.fromDollars(1),
18
- balanceAfter: Credit.fromDollars(100),
19
- type: "addon",
20
14
  description: "Monthly phone number fee",
21
15
  referenceId: null,
22
- fundingSource: null,
23
- attributedUserId: null,
24
- createdAt: new Date().toISOString(),
25
- expiresAt: null,
16
+ metadata: null,
17
+ lines: [],
26
18
  };
27
19
  }
28
20
 
@@ -108,7 +100,7 @@ describe("runMonthlyPhoneBilling", () => {
108
100
 
109
101
  const result = await runMonthlyPhoneBilling(
110
102
  phoneRepo as unknown as IPhoneNumberRepository,
111
- ledger as unknown as ICreditLedger,
103
+ ledger as unknown as ILedger,
112
104
  meter as unknown as IMeterEmitter,
113
105
  );
114
106
 
@@ -128,7 +120,7 @@ describe("runMonthlyPhoneBilling", () => {
128
120
 
129
121
  const result = await runMonthlyPhoneBilling(
130
122
  phoneRepo as unknown as IPhoneNumberRepository,
131
- ledger as unknown as ICreditLedger,
123
+ ledger as unknown as ILedger,
132
124
  meter as unknown as IMeterEmitter,
133
125
  );
134
126
 
@@ -138,16 +130,16 @@ describe("runMonthlyPhoneBilling", () => {
138
130
 
139
131
  // Verify debit was called with the margined charge amount
140
132
  expect(ledger.debit).toHaveBeenCalledOnce();
141
- const [tenantId, chargeAmount, type, description, referenceId, allowNegative] = ledger.debit.mock.calls[0];
133
+ const [tenantId, chargeAmount, type, opts] = ledger.debit.mock.calls[0];
142
134
  expect(tenantId).toBe("tenant-1");
143
135
  // chargeCredit = Credit.fromDollars(1.15).multiply(2.6)
144
136
  const expectedCharge = Credit.fromDollars(1.15).multiply(2.6);
145
137
  expect(chargeAmount.toRaw()).toBe(expectedCharge.toRaw());
146
138
  expect(type).toBe("addon");
147
- expect(description).toBe("Monthly phone number fee");
139
+ expect(opts.description).toBe("Monthly phone number fee");
148
140
  const expectedMonth = `${NOW.getFullYear()}-${String(NOW.getMonth() + 1).padStart(2, "0")}`;
149
- expect(referenceId).toMatch(new RegExp(`^phone-billing:PN-abc123:${expectedMonth}$`));
150
- expect(allowNegative).toBe(true);
141
+ expect(opts.referenceId).toMatch(new RegExp(`^phone-billing:PN-abc123:${expectedMonth}$`));
142
+ expect(opts.allowNegative).toBe(true);
151
143
 
152
144
  // Verify meter emission
153
145
  expect(meter.emit).toHaveBeenCalledOnce();
@@ -170,7 +162,7 @@ describe("runMonthlyPhoneBilling", () => {
170
162
 
171
163
  const result = await runMonthlyPhoneBilling(
172
164
  phoneRepo as unknown as IPhoneNumberRepository,
173
- ledger as unknown as ICreditLedger,
165
+ ledger as unknown as ILedger,
174
166
  meter as unknown as IMeterEmitter,
175
167
  );
176
168
 
@@ -191,7 +183,7 @@ describe("runMonthlyPhoneBilling", () => {
191
183
 
192
184
  const result = await runMonthlyPhoneBilling(
193
185
  phoneRepo as unknown as IPhoneNumberRepository,
194
- ledger as unknown as ICreditLedger,
186
+ ledger as unknown as ILedger,
195
187
  meter as unknown as IMeterEmitter,
196
188
  );
197
189
 
@@ -208,7 +200,7 @@ describe("runMonthlyPhoneBilling", () => {
208
200
 
209
201
  const result = await runMonthlyPhoneBilling(
210
202
  phoneRepo as unknown as IPhoneNumberRepository,
211
- ledger as unknown as ICreditLedger,
203
+ ledger as unknown as ILedger,
212
204
  meter as unknown as IMeterEmitter,
213
205
  );
214
206
 
@@ -229,7 +221,7 @@ describe("runMonthlyPhoneBilling", () => {
229
221
 
230
222
  const result = await runMonthlyPhoneBilling(
231
223
  phoneRepo as unknown as IPhoneNumberRepository,
232
- ledger as unknown as ICreditLedger,
224
+ ledger as unknown as ILedger,
233
225
  meter as unknown as IMeterEmitter,
234
226
  );
235
227
 
@@ -252,7 +244,7 @@ describe("runMonthlyPhoneBilling", () => {
252
244
 
253
245
  const result = await runMonthlyPhoneBilling(
254
246
  phoneRepo as unknown as IPhoneNumberRepository,
255
- ledger as unknown as ICreditLedger,
247
+ ledger as unknown as ILedger,
256
248
  meter as unknown as IMeterEmitter,
257
249
  );
258
250
 
@@ -271,7 +263,7 @@ describe("runMonthlyPhoneBilling", () => {
271
263
 
272
264
  const result = await runMonthlyPhoneBilling(
273
265
  phoneRepo as unknown as IPhoneNumberRepository,
274
- ledger as unknown as ICreditLedger,
266
+ ledger as unknown as ILedger,
275
267
  meter as unknown as IMeterEmitter,
276
268
  );
277
269
 
@@ -1,4 +1,4 @@
1
- import type { ICreditLedger } from "@wopr-network/platform-core/credits";
1
+ import type { ILedger } from "@wopr-network/platform-core/credits";
2
2
  import { Credit, InsufficientBalanceError } from "@wopr-network/platform-core/credits";
3
3
  import type { IMeterEmitter } from "@wopr-network/platform-core/metering";
4
4
  import { logger } from "../../config/logger.js";
@@ -15,7 +15,7 @@ const PHONE_NUMBER_MARGIN = 2.6;
15
15
 
16
16
  export async function runMonthlyPhoneBilling(
17
17
  phoneRepo: IPhoneNumberRepository,
18
- ledger: ICreditLedger,
18
+ ledger: ILedger,
19
19
  meter: IMeterEmitter,
20
20
  ): Promise<{
21
21
  processed: number;
@@ -45,14 +45,11 @@ export async function runMonthlyPhoneBilling(
45
45
  const costCredit = Credit.fromDollars(PHONE_NUMBER_MONTHLY_COST);
46
46
  const chargeCredit = withMargin(costCredit, PHONE_NUMBER_MARGIN);
47
47
 
48
- await ledger.debit(
49
- number.tenantId,
50
- chargeCredit,
51
- "addon",
52
- "Monthly phone number fee",
53
- `phone-billing:${number.sid}:${now.toISOString().slice(0, 7)}`,
54
- true,
55
- );
48
+ await ledger.debit(number.tenantId, chargeCredit, "addon", {
49
+ description: "Monthly phone number fee",
50
+ referenceId: `phone-billing:${number.sid}:${now.toISOString().slice(0, 7)}`,
51
+ allowNegative: true,
52
+ });
56
53
 
57
54
  meter.emit({
58
55
  tenant: number.tenantId,
@@ -1,5 +1,5 @@
1
1
  import type { PGlite } from "@electric-sql/pglite";
2
- import { Credit, CreditLedger, InsufficientBalanceError } from "@wopr-network/platform-core/credits";
2
+ import { Credit, DrizzleLedger, InsufficientBalanceError } from "@wopr-network/platform-core/credits";
3
3
  import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
4
4
  import { RESOURCE_TIERS } from "../../fleet/resource-tiers.js";
5
5
  import { createTestDb, truncateAllTables } from "../../test/db.js";
@@ -8,12 +8,12 @@ import { buildResourceTierCosts, DAILY_BOT_COST, runRuntimeDeductions } from "./
8
8
  describe("runRuntimeDeductions", () => {
9
9
  const TODAY = "2025-01-01";
10
10
  let pool: PGlite;
11
- let ledger: CreditLedger;
11
+ let ledger: DrizzleLedger;
12
12
 
13
13
  beforeAll(async () => {
14
14
  const { db, pool: p } = await createTestDb();
15
15
  pool = p;
16
- ledger = new CreditLedger(db);
16
+ ledger = new DrizzleLedger(db);
17
17
  });
18
18
 
19
19
  afterAll(async () => {
@@ -22,6 +22,7 @@ describe("runRuntimeDeductions", () => {
22
22
 
23
23
  beforeEach(async () => {
24
24
  await truncateAllTables(pool);
25
+ await ledger.seedSystemAccounts();
25
26
  });
26
27
 
27
28
  it("DAILY_BOT_COST equals 17 cents", () => {
@@ -40,7 +41,7 @@ describe("runRuntimeDeductions", () => {
40
41
  });
41
42
 
42
43
  it("skips tenants with zero active bots", async () => {
43
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
44
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
44
45
  const result = await runRuntimeDeductions({
45
46
  ledger,
46
47
  date: TODAY,
@@ -51,7 +52,7 @@ describe("runRuntimeDeductions", () => {
51
52
  });
52
53
 
53
54
  it("deducts full amount when balance is sufficient", async () => {
54
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
55
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
55
56
  const result = await runRuntimeDeductions({
56
57
  ledger,
57
58
  date: TODAY,
@@ -63,7 +64,7 @@ describe("runRuntimeDeductions", () => {
63
64
  });
64
65
 
65
66
  it("partial deduction and suspension when balance is insufficient", async () => {
66
- await ledger.credit("tenant-1", Credit.fromCents(10), "purchase", "top-up");
67
+ await ledger.credit("tenant-1", Credit.fromCents(10), "purchase", { description: "top-up" });
67
68
  const onSuspend = vi.fn();
68
69
  const result = await runRuntimeDeductions({
69
70
  ledger,
@@ -78,9 +79,9 @@ describe("runRuntimeDeductions", () => {
78
79
  });
79
80
 
80
81
  it("suspends with zero partial when balance exactly zero", async () => {
81
- await ledger.credit("tenant-1", Credit.fromCents(100), "purchase", "top-up");
82
- await ledger.debit("tenant-1", Credit.fromCents(100), "bot_runtime", "drain");
83
- await ledger.credit("tenant-1", Credit.fromCents(1), "purchase", "tiny");
82
+ await ledger.credit("tenant-1", Credit.fromCents(100), "purchase", { description: "top-up" });
83
+ await ledger.debit("tenant-1", Credit.fromCents(100), "bot_runtime", { description: "drain" });
84
+ await ledger.credit("tenant-1", Credit.fromCents(1), "purchase", { description: "tiny" });
84
85
 
85
86
  const onSuspend = vi.fn();
86
87
  const result = await runRuntimeDeductions({
@@ -95,7 +96,7 @@ describe("runRuntimeDeductions", () => {
95
96
  });
96
97
 
97
98
  it("suspends without onSuspend callback", async () => {
98
- await ledger.credit("tenant-1", Credit.fromCents(5), "purchase", "top-up");
99
+ await ledger.credit("tenant-1", Credit.fromCents(5), "purchase", { description: "top-up" });
99
100
  const result = await runRuntimeDeductions({
100
101
  ledger,
101
102
  date: TODAY,
@@ -106,7 +107,7 @@ describe("runRuntimeDeductions", () => {
106
107
  });
107
108
 
108
109
  it("handles errors from getActiveBotCount gracefully", async () => {
109
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
110
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
110
111
  const result = await runRuntimeDeductions({
111
112
  ledger,
112
113
  date: TODAY,
@@ -120,8 +121,8 @@ describe("runRuntimeDeductions", () => {
120
121
  });
121
122
 
122
123
  it("handles InsufficientBalanceError from ledger.debit", async () => {
123
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
124
- await ledger.debit("tenant-1", Credit.fromCents(499), "bot_runtime", "drain");
124
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
125
+ await ledger.debit("tenant-1", Credit.fromCents(499), "bot_runtime", { description: "drain" });
125
126
  const onSuspend = vi.fn();
126
127
  const result = await runRuntimeDeductions({
127
128
  ledger,
@@ -134,7 +135,7 @@ describe("runRuntimeDeductions", () => {
134
135
  });
135
136
 
136
137
  it("catches InsufficientBalanceError from debit and suspends", async () => {
137
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
138
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
138
139
  vi.spyOn(ledger, "debit").mockRejectedValue(
139
140
  new InsufficientBalanceError(Credit.fromCents(0), Credit.fromCents(17)),
140
141
  );
@@ -152,7 +153,7 @@ describe("runRuntimeDeductions", () => {
152
153
  });
153
154
 
154
155
  it("catches InsufficientBalanceError without onSuspend callback", async () => {
155
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
156
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
156
157
  vi.spyOn(ledger, "debit").mockRejectedValue(
157
158
  new InsufficientBalanceError(Credit.fromCents(0), Credit.fromCents(17)),
158
159
  );
@@ -167,8 +168,8 @@ describe("runRuntimeDeductions", () => {
167
168
  });
168
169
 
169
170
  it("processes multiple tenants", async () => {
170
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
171
- await ledger.credit("tenant-2", Credit.fromCents(10), "purchase", "top-up");
171
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
172
+ await ledger.credit("tenant-2", Credit.fromCents(10), "purchase", { description: "top-up" });
172
173
  const onSuspend = vi.fn();
173
174
  const result = await runRuntimeDeductions({
174
175
  ledger,
@@ -182,7 +183,7 @@ describe("runRuntimeDeductions", () => {
182
183
  });
183
184
 
184
185
  it("fires onLowBalance when balance drops below 100 cents threshold", async () => {
185
- await ledger.credit("tenant-1", Credit.fromCents(110), "purchase", "top-up");
186
+ await ledger.credit("tenant-1", Credit.fromCents(110), "purchase", { description: "top-up" });
186
187
  const onLowBalance = vi.fn();
187
188
  await runRuntimeDeductions({
188
189
  ledger,
@@ -197,7 +198,7 @@ describe("runRuntimeDeductions", () => {
197
198
  });
198
199
 
199
200
  it("does NOT fire onLowBalance when balance was already below threshold before deduction", async () => {
200
- await ledger.credit("tenant-1", Credit.fromCents(90), "purchase", "top-up");
201
+ await ledger.credit("tenant-1", Credit.fromCents(90), "purchase", { description: "top-up" });
201
202
  const onLowBalance = vi.fn();
202
203
  await runRuntimeDeductions({
203
204
  ledger,
@@ -209,7 +210,7 @@ describe("runRuntimeDeductions", () => {
209
210
  });
210
211
 
211
212
  it("fires onCreditsExhausted when full deduction causes balance to drop to 0", async () => {
212
- await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", "top-up");
213
+ await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", { description: "top-up" });
213
214
  const onCreditsExhausted = vi.fn();
214
215
  await runRuntimeDeductions({
215
216
  ledger,
@@ -223,7 +224,7 @@ describe("runRuntimeDeductions", () => {
223
224
 
224
225
  it("suspends tenant when full deduction causes balance to drop to exactly 0", async () => {
225
226
  // Balance = exactly 1 bot * DAILY_BOT_COST = 17 cents → full deduction → 0
226
- await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", "top-up");
227
+ await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", { description: "top-up" });
227
228
  const onSuspend = vi.fn();
228
229
  const onCreditsExhausted = vi.fn();
229
230
  const result = await runRuntimeDeductions({
@@ -240,7 +241,7 @@ describe("runRuntimeDeductions", () => {
240
241
  });
241
242
 
242
243
  it("fires onCreditsExhausted on partial deduction when balance hits 0", async () => {
243
- await ledger.credit("tenant-1", Credit.fromCents(10), "purchase", "top-up");
244
+ await ledger.credit("tenant-1", Credit.fromCents(10), "purchase", { description: "top-up" });
244
245
  const onCreditsExhausted = vi.fn();
245
246
  await runRuntimeDeductions({
246
247
  ledger,
@@ -253,7 +254,7 @@ describe("runRuntimeDeductions", () => {
253
254
  });
254
255
 
255
256
  it("partially debits resource tier surcharge when balance is positive but insufficient", async () => {
256
- await ledger.credit("tenant-1", Credit.fromCents(30), "purchase", "top-up");
257
+ await ledger.credit("tenant-1", Credit.fromCents(30), "purchase", { description: "top-up" });
257
258
  const result = await runRuntimeDeductions({
258
259
  ledger,
259
260
  date: TODAY,
@@ -265,7 +266,7 @@ describe("runRuntimeDeductions", () => {
265
266
  });
266
267
 
267
268
  it("skips resource tier partial debit when balance is exactly 0 after runtime", async () => {
268
- await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", "top-up");
269
+ await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", { description: "top-up" });
269
270
  const onCreditsExhausted = vi.fn();
270
271
  const result = await runRuntimeDeductions({
271
272
  ledger,
@@ -284,7 +285,7 @@ describe("runRuntimeDeductions", () => {
284
285
  // triggering the zero-crossing suspend in the runtime block.
285
286
  // Storage cost (5 cents) then tries to suspend again via its else-branch (balance 0 < 5).
286
287
  // The !result.suspended.includes(tenantId) guard must prevent onSuspend being called twice.
287
- await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", "top-up");
288
+ await ledger.credit("tenant-1", Credit.fromCents(17), "purchase", { description: "top-up" });
288
289
  const onSuspend = vi.fn();
289
290
  const result = await runRuntimeDeductions({
290
291
  ledger,
@@ -301,7 +302,7 @@ describe("runRuntimeDeductions", () => {
301
302
  it("buildResourceTierCosts: deducts pro tier surcharge via getResourceTierCosts", async () => {
302
303
  const proTierCost = RESOURCE_TIERS.pro.dailyCost.toCents();
303
304
  const startBalance = 17 + proTierCost + 10;
304
- await ledger.credit("tenant-1", Credit.fromCents(startBalance), "purchase", "top-up");
305
+ await ledger.credit("tenant-1", Credit.fromCents(startBalance), "purchase", { description: "top-up" });
305
306
 
306
307
  const mockRepo = {
307
308
  getResourceTier: async (_botId: string): Promise<string | null> => "pro",
@@ -324,7 +325,7 @@ describe("runRuntimeDeductions", () => {
324
325
  });
325
326
 
326
327
  it("treats unique constraint violation from concurrent debit as already-billed (skip, not error)", async () => {
327
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
328
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
328
329
  const uniqueErr = Object.assign(new Error("duplicate key value violates unique constraint"), { code: "23505" });
329
330
  vi.spyOn(ledger, "debit").mockRejectedValueOnce(uniqueErr);
330
331
  const result = await runRuntimeDeductions({
@@ -338,7 +339,7 @@ describe("runRuntimeDeductions", () => {
338
339
  });
339
340
 
340
341
  it("is idempotent — second run on same date does not double-deduct", async () => {
341
- await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", "top-up");
342
+ await ledger.credit("tenant-1", Credit.fromCents(500), "purchase", { description: "top-up" });
342
343
  const cfg = {
343
344
  ledger,
344
345
  getActiveBotCount: async () => 1,
@@ -1,4 +1,4 @@
1
- import type { ICreditLedger } from "@wopr-network/platform-core/credits";
1
+ import type { ILedger } from "@wopr-network/platform-core/credits";
2
2
  import { Credit, InsufficientBalanceError } from "@wopr-network/platform-core/credits";
3
3
  import { logger } from "../../config/logger.js";
4
4
  import type { IBotInstanceRepository } from "../../fleet/bot-instance-repository.js";
@@ -20,7 +20,7 @@ export type GetActiveBotCount = (tenantId: string) => number | Promise<number>;
20
20
  export const LOW_BALANCE_THRESHOLD = Credit.fromCents(100);
21
21
 
22
22
  export interface RuntimeCronConfig {
23
- ledger: ICreditLedger;
23
+ ledger: ILedger;
24
24
  getActiveBotCount: GetActiveBotCount;
25
25
  /** The date being billed, as YYYY-MM-DD. Used for idempotency. */
26
26
  date: string;
@@ -122,13 +122,10 @@ export async function runRuntimeDeductions(cfg: RuntimeCronConfig): Promise<Runt
122
122
 
123
123
  if (!balance.lessThan(totalCost)) {
124
124
  // Full deduction
125
- await cfg.ledger.debit(
126
- tenantId,
127
- totalCost,
128
- "bot_runtime",
129
- `Daily runtime: ${botCount} bot(s) x $${DAILY_BOT_COST.toDollars().toFixed(2)}`,
130
- runtimeRef,
131
- );
125
+ await cfg.ledger.debit(tenantId, totalCost, "bot_runtime", {
126
+ description: `Daily runtime: ${botCount} bot(s) x $${DAILY_BOT_COST.toDollars().toFixed(2)}`,
127
+ referenceId: runtimeRef,
128
+ });
132
129
 
133
130
  // Debit resource tier surcharges (if any)
134
131
  if (cfg.getResourceTierCosts) {
@@ -136,21 +133,15 @@ export async function runRuntimeDeductions(cfg: RuntimeCronConfig): Promise<Runt
136
133
  if (!tierCost.isZero()) {
137
134
  const balanceAfterRuntime = await cfg.ledger.balance(tenantId);
138
135
  if (!balanceAfterRuntime.lessThan(tierCost)) {
139
- await cfg.ledger.debit(
140
- tenantId,
141
- tierCost,
142
- "resource_upgrade",
143
- "Daily resource tier surcharge",
144
- `runtime-tier:${cfg.date}:${tenantId}`,
145
- );
136
+ await cfg.ledger.debit(tenantId, tierCost, "resource_upgrade", {
137
+ description: "Daily resource tier surcharge",
138
+ referenceId: `runtime-tier:${cfg.date}:${tenantId}`,
139
+ });
146
140
  } else if (balanceAfterRuntime.greaterThan(Credit.ZERO)) {
147
- await cfg.ledger.debit(
148
- tenantId,
149
- balanceAfterRuntime,
150
- "resource_upgrade",
151
- "Partial resource tier surcharge (balance exhausted)",
152
- `runtime-tier:${cfg.date}:${tenantId}`,
153
- );
141
+ await cfg.ledger.debit(tenantId, balanceAfterRuntime, "resource_upgrade", {
142
+ description: "Partial resource tier surcharge (balance exhausted)",
143
+ referenceId: `runtime-tier:${cfg.date}:${tenantId}`,
144
+ });
154
145
  }
155
146
  }
156
147
  }
@@ -190,23 +181,17 @@ export async function runRuntimeDeductions(cfg: RuntimeCronConfig): Promise<Runt
190
181
  if (!storageCost.isZero()) {
191
182
  const currentBalance = await cfg.ledger.balance(tenantId);
192
183
  if (!currentBalance.lessThan(storageCost)) {
193
- await cfg.ledger.debit(
194
- tenantId,
195
- storageCost,
196
- "storage_upgrade",
197
- "Daily storage tier surcharge",
198
- `runtime-storage:${cfg.date}:${tenantId}`,
199
- );
184
+ await cfg.ledger.debit(tenantId, storageCost, "storage_upgrade", {
185
+ description: "Daily storage tier surcharge",
186
+ referenceId: `runtime-storage:${cfg.date}:${tenantId}`,
187
+ });
200
188
  } else {
201
189
  // Partial debit — take what's left, then suspend
202
190
  if (currentBalance.greaterThan(Credit.ZERO)) {
203
- await cfg.ledger.debit(
204
- tenantId,
205
- currentBalance,
206
- "storage_upgrade",
207
- "Partial storage tier surcharge (balance exhausted)",
208
- `runtime-storage:${cfg.date}:${tenantId}`,
209
- );
191
+ await cfg.ledger.debit(tenantId, currentBalance, "storage_upgrade", {
192
+ description: "Partial storage tier surcharge (balance exhausted)",
193
+ referenceId: `runtime-storage:${cfg.date}:${tenantId}`,
194
+ });
210
195
  }
211
196
  if (!result.suspended.includes(tenantId)) {
212
197
  result.suspended.push(tenantId);
@@ -222,23 +207,17 @@ export async function runRuntimeDeductions(cfg: RuntimeCronConfig): Promise<Runt
222
207
  if (!addonCost.isZero()) {
223
208
  const currentBalance = await cfg.ledger.balance(tenantId);
224
209
  if (!currentBalance.lessThan(addonCost)) {
225
- await cfg.ledger.debit(
226
- tenantId,
227
- addonCost,
228
- "addon",
229
- "Daily infrastructure add-on charges",
230
- `runtime-addon:${cfg.date}:${tenantId}`,
231
- );
210
+ await cfg.ledger.debit(tenantId, addonCost, "addon", {
211
+ description: "Daily infrastructure add-on charges",
212
+ referenceId: `runtime-addon:${cfg.date}:${tenantId}`,
213
+ });
232
214
  } else {
233
215
  // Partial debit — take what's left, then suspend
234
216
  if (currentBalance.greaterThan(Credit.ZERO)) {
235
- await cfg.ledger.debit(
236
- tenantId,
237
- currentBalance,
238
- "addon",
239
- "Partial add-on charges (balance exhausted)",
240
- `runtime-addon:${cfg.date}:${tenantId}`,
241
- );
217
+ await cfg.ledger.debit(tenantId, currentBalance, "addon", {
218
+ description: "Partial add-on charges (balance exhausted)",
219
+ referenceId: `runtime-addon:${cfg.date}:${tenantId}`,
220
+ });
242
221
  }
243
222
  if (!result.suspended.includes(tenantId)) {
244
223
  result.suspended.push(tenantId);
@@ -250,13 +229,10 @@ export async function runRuntimeDeductions(cfg: RuntimeCronConfig): Promise<Runt
250
229
  } else {
251
230
  // Partial deduction — debit remaining balance, then suspend
252
231
  if (balance.greaterThan(Credit.ZERO)) {
253
- await cfg.ledger.debit(
254
- tenantId,
255
- balance,
256
- "bot_runtime",
257
- `Partial daily runtime (balance exhausted): ${botCount} bot(s)`,
258
- runtimeRef,
259
- );
232
+ await cfg.ledger.debit(tenantId, balance, "bot_runtime", {
233
+ description: `Partial daily runtime (balance exhausted): ${botCount} bot(s)`,
234
+ referenceId: runtimeRef,
235
+ });
260
236
  }
261
237
 
262
238
  if (cfg.onCreditsExhausted) {
@@ -1,7 +1,7 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { RUNTIME_INTERVAL_MS, startRuntimeScheduler } from "./runtime-scheduler.js";
3
3
 
4
- // Minimal ICreditLedger stub — only the methods runRuntimeDeductions calls.
4
+ // Minimal ILedger stub — only the methods runRuntimeDeductions calls.
5
5
  function makeLedger() {
6
6
  return {
7
7
  tenantsWithBalance: vi.fn().mockResolvedValue([]),
@@ -1,4 +1,4 @@
1
- import type { ICreditLedger } from "@wopr-network/platform-core/credits";
1
+ import type { ILedger } from "@wopr-network/platform-core/credits";
2
2
  import { logger } from "../../config/logger.js";
3
3
  import type { IBotInstanceRepository } from "../../fleet/bot-instance-repository.js";
4
4
  import { buildAddonCosts } from "../addons/addon-cron.js";
@@ -6,7 +6,7 @@ import type { ITenantAddonRepository } from "../addons/addon-repository.js";
6
6
  import { buildResourceTierCosts, runRuntimeDeductions } from "./runtime-cron.js";
7
7
 
8
8
  export interface RuntimeSchedulerDeps {
9
- ledger: ICreditLedger;
9
+ ledger: ILedger;
10
10
  botInstanceRepo: IBotInstanceRepository;
11
11
  tenantAddonRepo: ITenantAddonRepository;
12
12
  onSuspend?: (tenantId: string) => void;
@@ -1,5 +1,5 @@
1
1
  import type { PGlite } from "@electric-sql/pglite";
2
- import { CreditLedger, grantSignupCredits, SIGNUP_GRANT } from "@wopr-network/platform-core/credits";
2
+ import { DrizzleLedger, grantSignupCredits, SIGNUP_GRANT } from "@wopr-network/platform-core/credits";
3
3
  import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
4
4
  import type { DrizzleDb } from "../../db/index.js";
5
5
  import { createTestDb, truncateAllTables } from "../../test/db.js";
@@ -7,7 +7,7 @@ import { createTestDb, truncateAllTables } from "../../test/db.js";
7
7
  describe("grantSignupCredits", () => {
8
8
  let pool: PGlite;
9
9
  let db: DrizzleDb;
10
- let ledger: CreditLedger;
10
+ let ledger: DrizzleLedger;
11
11
 
12
12
  beforeAll(async () => {
13
13
  ({ db, pool } = await createTestDb());
@@ -19,7 +19,9 @@ describe("grantSignupCredits", () => {
19
19
 
20
20
  beforeEach(async () => {
21
21
  await truncateAllTables(pool);
22
- ledger = new CreditLedger(db);
22
+ ledger = new DrizzleLedger(db);
23
+
24
+ await ledger.seedSystemAccounts();
23
25
  });
24
26
 
25
27
  it("grants credits to a new tenant and returns true", async () => {
@@ -52,7 +54,8 @@ describe("grantSignupCredits", () => {
52
54
  const uniqueErr = Object.assign(new Error("duplicate key value violates unique constraint"), {
53
55
  code: "23505",
54
56
  });
55
- const racingLedger = new CreditLedger(db);
57
+ const racingLedger = new DrizzleLedger(db);
58
+ await racingLedger.seedSystemAccounts();
56
59
  vi.spyOn(racingLedger, "hasReferenceId").mockResolvedValue(false);
57
60
  vi.spyOn(racingLedger, "credit").mockRejectedValue(uniqueErr);
58
61
 
@@ -1,5 +1,5 @@
1
1
  import type { PGlite } from "@electric-sql/pglite";
2
- import { Credit, CreditLedger } from "@wopr-network/platform-core/credits";
2
+ import { Credit, DrizzleLedger } from "@wopr-network/platform-core/credits";
3
3
  import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
4
4
  import type { DrizzleDb } from "../../db/index.js";
5
5
  import { createTestDb, truncateAllTables } from "../../test/db.js";
@@ -9,7 +9,7 @@ describe("runtime cron with storage tiers", () => {
9
9
  const TODAY = "2025-01-01";
10
10
  let pool: PGlite;
11
11
  let db: DrizzleDb;
12
- let ledger: CreditLedger;
12
+ let ledger: DrizzleLedger;
13
13
 
14
14
  beforeAll(async () => {
15
15
  ({ db, pool } = await createTestDb());
@@ -21,7 +21,9 @@ describe("runtime cron with storage tiers", () => {
21
21
 
22
22
  beforeEach(async () => {
23
23
  await truncateAllTables(pool);
24
- ledger = new CreditLedger(db);
24
+ ledger = new DrizzleLedger(db);
25
+
26
+ await ledger.seedSystemAccounts();
25
27
  });
26
28
 
27
29
  it("debits base cost plus storage surcharge for pro tier", async () => {