@wopr-network/platform-core 1.13.3 → 1.14.1
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/.github/workflows/dependabot-auto-merge.yml +1 -2
- package/dist/api/routes/admin-credits.d.ts +2 -2
- package/dist/api/routes/admin-credits.js +9 -4
- package/dist/api/routes/quota.d.ts +2 -2
- package/dist/api/routes/verify-email.d.ts +3 -3
- package/dist/backup/on-demand-snapshot-service.d.ts +2 -2
- package/dist/billing/payram/webhook.d.ts +3 -3
- package/dist/billing/payram/webhook.js +5 -1
- package/dist/billing/payram/webhook.test.js +5 -4
- package/dist/billing/stripe/stripe-payment-processor.d.ts +2 -2
- package/dist/billing/stripe/stripe-payment-processor.test.js +7 -0
- package/dist/billing/stripe/tenant-store.d.ts +1 -1
- package/dist/billing/stripe/tenant-store.js +1 -1
- package/dist/credits/auto-topup-charge.d.ts +2 -2
- package/dist/credits/auto-topup-charge.js +5 -1
- package/dist/credits/auto-topup-charge.test.js +5 -4
- package/dist/credits/auto-topup-usage.d.ts +2 -2
- package/dist/credits/auto-topup-usage.test.js +53 -12
- package/dist/credits/credit-expiry-cron.d.ts +2 -2
- package/dist/credits/credit-expiry-cron.js +7 -4
- package/dist/credits/credit-expiry-cron.test.js +25 -8
- package/dist/credits/credit-ledger.d.ts +2 -2
- package/dist/credits/credit-ledger.js +1 -1
- package/dist/credits/dividend-cron.d.ts +4 -6
- package/dist/credits/dividend-cron.js +10 -16
- package/dist/credits/dividend-cron.test.js +31 -44
- package/dist/credits/dividend-repository.js +19 -22
- package/dist/credits/dividend-repository.test.js +4 -3
- package/dist/credits/index.d.ts +4 -2
- package/dist/credits/index.js +2 -1
- package/dist/credits/ledger.d.ts +195 -0
- package/dist/credits/ledger.js +561 -0
- package/dist/credits/ledger.test.js +418 -0
- package/dist/credits/signup-grant.d.ts +2 -2
- package/dist/credits/signup-grant.js +4 -4
- package/dist/credits/signup-grant.test.js +5 -3
- package/dist/credits/trial-balance-cron.d.ts +19 -0
- package/dist/credits/trial-balance-cron.js +30 -0
- package/dist/credits/trial-balance-cron.test.js +55 -0
- package/dist/db/schema/index.d.ts +1 -0
- package/dist/db/schema/index.js +1 -0
- package/dist/db/schema/ledger.d.ts +442 -0
- package/dist/db/schema/ledger.js +76 -0
- package/dist/gateway/credit-gate.d.ts +2 -2
- package/dist/gateway/credit-gate.js +5 -1
- package/dist/gateway/credit-gate.test.js +35 -33
- package/dist/gateway/protocol/deps.d.ts +2 -2
- package/dist/gateway/protocol/handlers.test.js +461 -0
- package/dist/gateway/proxy.d.ts +2 -2
- package/dist/gateway/types.d.ts +2 -2
- package/dist/metering/reconciliation-cron.test.js +9 -8
- package/dist/metering/reconciliation-repository.js +12 -10
- package/dist/metering/reconciliation-repository.test.js +9 -8
- package/dist/monetization/affiliate/affiliate-admin-repository.js +10 -8
- package/dist/monetization/affiliate/affiliate-admin-repository.test.js +32 -13
- package/dist/monetization/affiliate/credit-match.d.ts +2 -2
- package/dist/monetization/affiliate/credit-match.js +4 -1
- package/dist/monetization/affiliate/credit-match.test.js +58 -13
- package/dist/monetization/affiliate/new-user-bonus.d.ts +2 -2
- package/dist/monetization/affiliate/new-user-bonus.js +4 -1
- package/dist/monetization/affiliate/new-user-bonus.test.js +4 -3
- package/dist/monetization/credits/auto-topup-charge.d.ts +2 -2
- package/dist/monetization/credits/auto-topup-charge.js +5 -1
- package/dist/monetization/credits/auto-topup-charge.test.js +5 -4
- package/dist/monetization/credits/auto-topup-usage.d.ts +2 -2
- package/dist/monetization/credits/auto-topup-usage.test.js +53 -12
- package/dist/monetization/credits/bot-billing.d.ts +3 -3
- package/dist/monetization/credits/bot-billing.test.js +18 -5
- package/dist/monetization/credits/credit-expiry-cron.test.js +25 -8
- package/dist/monetization/credits/dividend-cron.d.ts +2 -4
- package/dist/monetization/credits/dividend-cron.js +7 -4
- package/dist/monetization/credits/dividend-cron.test.js +26 -46
- package/dist/monetization/credits/dividend-repository.js +15 -24
- package/dist/monetization/credits/dividend-repository.test.js +4 -3
- package/dist/monetization/credits/index.d.ts +2 -2
- package/dist/monetization/credits/index.js +1 -1
- package/dist/monetization/credits/member-usage.test.js +23 -10
- package/dist/monetization/credits/phone-billing.d.ts +2 -2
- package/dist/monetization/credits/phone-billing.js +5 -1
- package/dist/monetization/credits/phone-billing.test.js +9 -12
- package/dist/monetization/credits/runtime-cron.d.ts +2 -2
- package/dist/monetization/credits/runtime-cron.js +32 -8
- package/dist/monetization/credits/runtime-cron.test.js +28 -27
- package/dist/monetization/credits/runtime-scheduler.d.ts +2 -2
- package/dist/monetization/credits/runtime-scheduler.test.js +1 -1
- package/dist/monetization/credits/signup-grant.test.js +5 -3
- package/dist/monetization/credits/storage-tier-cron.test.js +3 -2
- package/dist/monetization/credits/trial-balance-cron.test.js +42 -0
- package/dist/monetization/feature-gate.d.ts +3 -3
- package/dist/monetization/index.d.ts +3 -3
- package/dist/monetization/index.js +1 -1
- package/dist/monetization/metering/reconciliation-cron.test.js +9 -8
- package/dist/monetization/metering/reconciliation-repository.js +11 -10
- package/dist/monetization/metering/reconciliation-repository.test.js +9 -8
- package/dist/monetization/payram/webhook.d.ts +2 -2
- package/dist/monetization/payram/webhook.js +5 -1
- package/dist/monetization/payram/webhook.test.js +5 -4
- package/dist/monetization/promotions/engine.d.ts +2 -2
- package/dist/monetization/promotions/engine.js +4 -1
- package/dist/monetization/promotions/engine.test.js +3 -1
- package/dist/monetization/repository-types.d.ts +1 -1
- package/dist/monetization/stripe/stripe-payment-processor.d.ts +2 -2
- package/dist/monetization/stripe/stripe-payment-processor.test.js +7 -0
- package/dist/monetization/stripe/webhook.d.ts +2 -2
- package/dist/monetization/stripe/webhook.js +70 -6
- package/dist/monetization/stripe/webhook.test.js +20 -15
- package/dist/onboarding/onboarding-service.d.ts +2 -2
- package/dist/onboarding/onboarding-service.js +6 -2
- package/drizzle/migrations/0003_double_entry_ledger.sql +82 -0
- package/drizzle/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/src/api/routes/admin-credits.ts +11 -14
- package/src/api/routes/quota.ts +2 -2
- package/src/api/routes/verify-email.ts +4 -4
- package/src/backup/on-demand-snapshot-service.test.ts +3 -3
- package/src/backup/on-demand-snapshot-service.ts +3 -3
- package/src/billing/payram/webhook.test.ts +7 -5
- package/src/billing/payram/webhook.ts +8 -11
- package/src/billing/stripe/stripe-payment-processor.test.ts +10 -3
- package/src/billing/stripe/stripe-payment-processor.ts +3 -3
- package/src/billing/stripe/tenant-store.ts +1 -1
- package/src/credits/auto-topup-charge.test.ts +7 -5
- package/src/credits/auto-topup-charge.ts +7 -10
- package/src/credits/auto-topup-usage.test.ts +55 -13
- package/src/credits/auto-topup-usage.ts +2 -2
- package/src/credits/credit-expiry-cron.test.ts +26 -45
- package/src/credits/credit-expiry-cron.ts +9 -12
- package/src/credits/credit-ledger.ts +3 -3
- package/src/credits/dividend-cron.test.ts +38 -45
- package/src/credits/dividend-cron.ts +12 -26
- package/src/credits/dividend-repository.test.ts +4 -3
- package/src/credits/dividend-repository.ts +21 -23
- package/src/credits/index.ts +23 -4
- package/src/credits/ledger.test.ts +514 -0
- package/src/credits/ledger.ts +851 -0
- package/src/credits/signup-grant.test.ts +7 -4
- package/src/credits/signup-grant.ts +6 -12
- package/src/credits/trial-balance-cron.test.ts +68 -0
- package/src/credits/trial-balance-cron.ts +46 -0
- package/src/db/schema/index.ts +1 -0
- package/src/db/schema/ledger.ts +94 -0
- package/src/gateway/credit-gate-wiring.test.ts +3 -3
- package/src/gateway/credit-gate.test.ts +35 -33
- package/src/gateway/credit-gate.ts +6 -10
- package/src/gateway/gateway-routes.test.ts +5 -5
- package/src/gateway/protocol/deps.ts +2 -2
- package/src/gateway/protocol/handlers.test.ts +549 -1
- package/src/gateway/proxy.ts +2 -2
- package/src/gateway/route-mounting.test.ts +2 -2
- package/src/gateway/types.ts +2 -2
- package/src/metering/reconciliation-cron.test.ts +10 -9
- package/src/metering/reconciliation-repository.test.ts +10 -9
- package/src/metering/reconciliation-repository.ts +14 -11
- package/src/monetization/affiliate/affiliate-admin-repository.test.ts +32 -19
- package/src/monetization/affiliate/affiliate-admin-repository.ts +16 -8
- package/src/monetization/affiliate/credit-match.test.ts +60 -14
- package/src/monetization/affiliate/credit-match.ts +6 -9
- package/src/monetization/affiliate/new-user-bonus.test.ts +6 -4
- package/src/monetization/affiliate/new-user-bonus.ts +6 -9
- package/src/monetization/credits/auto-topup-charge.test.ts +7 -5
- package/src/monetization/credits/auto-topup-charge.ts +7 -10
- package/src/monetization/credits/auto-topup-usage.test.ts +55 -13
- package/src/monetization/credits/auto-topup-usage.ts +2 -2
- package/src/monetization/credits/bot-billing.test.ts +20 -6
- package/src/monetization/credits/bot-billing.ts +3 -3
- package/src/monetization/credits/credit-expiry-cron.test.ts +26 -45
- package/src/monetization/credits/dividend-cron.test.ts +34 -48
- package/src/monetization/credits/dividend-cron.ts +9 -14
- package/src/monetization/credits/dividend-repository.test.ts +4 -3
- package/src/monetization/credits/dividend-repository.ts +19 -25
- package/src/monetization/credits/index.ts +4 -4
- package/src/monetization/credits/member-usage.test.ts +25 -11
- package/src/monetization/credits/phone-billing.test.ts +18 -26
- package/src/monetization/credits/phone-billing.ts +7 -10
- package/src/monetization/credits/runtime-cron.test.ts +29 -28
- package/src/monetization/credits/runtime-cron.ts +34 -58
- package/src/monetization/credits/runtime-scheduler.test.ts +1 -1
- package/src/monetization/credits/runtime-scheduler.ts +2 -2
- package/src/monetization/credits/signup-grant.test.ts +7 -4
- package/src/monetization/credits/storage-tier-cron.test.ts +5 -3
- package/src/monetization/credits/trial-balance-cron.test.ts +52 -0
- package/src/monetization/feature-gate.ts +3 -3
- package/src/monetization/index.ts +4 -4
- package/src/monetization/metering/reconciliation-cron.test.ts +10 -9
- package/src/monetization/metering/reconciliation-repository.test.ts +11 -9
- package/src/monetization/metering/reconciliation-repository.ts +13 -11
- package/src/monetization/payram/webhook.test.ts +7 -5
- package/src/monetization/payram/webhook.ts +7 -10
- package/src/monetization/promotions/engine.test.ts +6 -5
- package/src/monetization/promotions/engine.ts +6 -3
- package/src/monetization/repository-types.ts +1 -1
- package/src/monetization/stripe/stripe-payment-processor.test.ts +10 -3
- package/src/monetization/stripe/stripe-payment-processor.ts +3 -3
- package/src/monetization/stripe/webhook.test.ts +22 -16
- package/src/monetization/stripe/webhook.ts +75 -50
- package/src/onboarding/onboarding-service.ts +8 -11
- package/dist/credits/credit-ledger-extra.test.js +0 -40
- package/dist/credits/credit-ledger.bench.js +0 -33
- package/dist/credits/credit-ledger.test.d.ts +0 -4
- package/dist/credits/credit-ledger.test.js +0 -203
- package/dist/credits/credit-transaction-repository.test.js +0 -232
- package/dist/monetization/credits/credit-ledger-extra.test.d.ts +0 -1
- package/dist/monetization/credits/credit-ledger-extra.test.js +0 -39
- package/dist/monetization/credits/credit-ledger.bench.d.ts +0 -1
- package/dist/monetization/credits/credit-ledger.bench.js +0 -32
- package/dist/monetization/credits/credit-ledger.test.d.ts +0 -4
- package/dist/monetization/credits/credit-ledger.test.js +0 -202
- package/dist/monetization/credits/credit-transaction-repository.test.d.ts +0 -1
- package/dist/monetization/credits/credit-transaction-repository.test.js +0 -232
- package/src/credits/credit-ledger-extra.test.ts +0 -57
- package/src/credits/credit-ledger.bench.ts +0 -56
- package/src/credits/credit-ledger.test.ts +0 -276
- package/src/credits/credit-transaction-repository.test.ts +0 -274
- package/src/monetization/credits/credit-ledger-extra.test.ts +0 -56
- package/src/monetization/credits/credit-ledger.bench.ts +0 -55
- package/src/monetization/credits/credit-ledger.test.ts +0 -275
- package/src/monetization/credits/credit-transaction-repository.test.ts +0 -274
- /package/dist/credits/{credit-ledger-extra.test.d.ts → ledger.test.d.ts} +0 -0
- /package/dist/credits/{credit-ledger.bench.d.ts → trial-balance-cron.test.d.ts} +0 -0
- /package/dist/{credits/credit-transaction-repository.test.d.ts → monetization/credits/trial-balance-cron.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for gateway credit gate — grace buffer and credits_exhausted behavior (WOP-821).
|
|
3
3
|
*/
|
|
4
|
-
import { Credit,
|
|
4
|
+
import { Credit, DrizzleLedger } from "@wopr-network/platform-core/credits";
|
|
5
5
|
import { Hono } from "hono";
|
|
6
6
|
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
7
|
import { createTestDb, truncateAllTables } from "../test/db.js";
|
|
@@ -39,35 +39,36 @@ afterAll(async () => {
|
|
|
39
39
|
describe("creditBalanceCheck grace buffer", () => {
|
|
40
40
|
beforeEach(async () => {
|
|
41
41
|
await truncateAllTables(pool);
|
|
42
|
+
await new DrizzleLedger(db).seedSystemAccounts();
|
|
42
43
|
});
|
|
43
44
|
it("returns null when balance is above estimated cost (passes)", async () => {
|
|
44
|
-
const ledger = new
|
|
45
|
-
await ledger.credit("t1", Credit.fromCents(500), "purchase", "setup");
|
|
45
|
+
const ledger = new DrizzleLedger(db);
|
|
46
|
+
await ledger.credit("t1", Credit.fromCents(500), "purchase", { description: "setup" });
|
|
46
47
|
const c = await buildHonoContext("t1");
|
|
47
48
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
48
49
|
expect(await creditBalanceCheck(c, deps, 1)).toBeNull();
|
|
49
50
|
});
|
|
50
51
|
it("returns null when balance is zero but within default grace buffer (passes)", async () => {
|
|
51
52
|
// Balance at exactly 0 — within the -50 grace buffer
|
|
52
|
-
const ledger = new
|
|
53
|
-
await ledger.credit("t1", Credit.fromCents(10), "purchase", "setup");
|
|
54
|
-
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", "drain");
|
|
53
|
+
const ledger = new DrizzleLedger(db);
|
|
54
|
+
await ledger.credit("t1", Credit.fromCents(10), "purchase", { description: "setup" });
|
|
55
|
+
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", { description: "drain" });
|
|
55
56
|
const c = await buildHonoContext("t1");
|
|
56
57
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
57
58
|
expect(await creditBalanceCheck(c, deps, 0)).toBeNull();
|
|
58
59
|
});
|
|
59
60
|
it("returns null when balance is -49 (within 50-cent grace buffer)", async () => {
|
|
60
|
-
const ledger = new
|
|
61
|
-
await ledger.credit("t1", Credit.fromCents(1), "purchase", "setup");
|
|
62
|
-
await ledger.debit("t1", Credit.fromCents(50), "adapter_usage", "drain",
|
|
61
|
+
const ledger = new DrizzleLedger(db);
|
|
62
|
+
await ledger.credit("t1", Credit.fromCents(1), "purchase", { description: "setup" });
|
|
63
|
+
await ledger.debit("t1", Credit.fromCents(50), "adapter_usage", { description: "drain", allowNegative: true }); // balance = -49
|
|
63
64
|
const c = await buildHonoContext("t1");
|
|
64
65
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
65
66
|
expect(await creditBalanceCheck(c, deps, 0)).toBeNull();
|
|
66
67
|
});
|
|
67
68
|
it("returns credits_exhausted when balance is at -50 (at grace buffer limit)", async () => {
|
|
68
|
-
const ledger = new
|
|
69
|
-
await ledger.credit("t1", Credit.fromCents(1), "purchase", "setup");
|
|
70
|
-
await ledger.debit("t1", Credit.fromCents(51), "adapter_usage", "drain",
|
|
69
|
+
const ledger = new DrizzleLedger(db);
|
|
70
|
+
await ledger.credit("t1", Credit.fromCents(1), "purchase", { description: "setup" });
|
|
71
|
+
await ledger.debit("t1", Credit.fromCents(51), "adapter_usage", { description: "drain", allowNegative: true }); // balance = -50
|
|
71
72
|
const c = await buildHonoContext("t1");
|
|
72
73
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
73
74
|
const result = await creditBalanceCheck(c, deps, 0);
|
|
@@ -75,9 +76,9 @@ describe("creditBalanceCheck grace buffer", () => {
|
|
|
75
76
|
expect(result?.code).toBe("credits_exhausted");
|
|
76
77
|
});
|
|
77
78
|
it("returns credits_exhausted when balance is at -51 (beyond grace buffer)", async () => {
|
|
78
|
-
const ledger = new
|
|
79
|
-
await ledger.credit("t1", Credit.fromCents(1), "purchase", "setup");
|
|
80
|
-
await ledger.debit("t1", Credit.fromCents(52), "adapter_usage", "drain",
|
|
79
|
+
const ledger = new DrizzleLedger(db);
|
|
80
|
+
await ledger.credit("t1", Credit.fromCents(1), "purchase", { description: "setup" });
|
|
81
|
+
await ledger.debit("t1", Credit.fromCents(52), "adapter_usage", { description: "drain", allowNegative: true }); // balance = -51
|
|
81
82
|
const c = await buildHonoContext("t1");
|
|
82
83
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
83
84
|
const result = await creditBalanceCheck(c, deps, 0);
|
|
@@ -85,9 +86,9 @@ describe("creditBalanceCheck grace buffer", () => {
|
|
|
85
86
|
expect(result?.code).toBe("credits_exhausted");
|
|
86
87
|
});
|
|
87
88
|
it("returns credits_exhausted when custom graceBufferCents=0 and balance is 0", async () => {
|
|
88
|
-
const ledger = new
|
|
89
|
-
await ledger.credit("t1", Credit.fromCents(10), "purchase", "setup");
|
|
90
|
-
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", "drain"); // balance = 0
|
|
89
|
+
const ledger = new DrizzleLedger(db);
|
|
90
|
+
await ledger.credit("t1", Credit.fromCents(10), "purchase", { description: "setup" });
|
|
91
|
+
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", { description: "drain" }); // balance = 0
|
|
91
92
|
const c = await buildHonoContext("t1");
|
|
92
93
|
const deps = { creditLedger: ledger, topUpUrl: "/billing", graceBufferCents: 0 };
|
|
93
94
|
const result = await creditBalanceCheck(c, deps, 0);
|
|
@@ -95,8 +96,8 @@ describe("creditBalanceCheck grace buffer", () => {
|
|
|
95
96
|
expect(result?.code).toBe("credits_exhausted");
|
|
96
97
|
});
|
|
97
98
|
it("returns insufficient_credits when balance positive but below estimated cost", async () => {
|
|
98
|
-
const ledger = new
|
|
99
|
-
await ledger.credit("t1", Credit.fromCents(5), "purchase", "setup");
|
|
99
|
+
const ledger = new DrizzleLedger(db);
|
|
100
|
+
await ledger.credit("t1", Credit.fromCents(5), "purchase", { description: "setup" });
|
|
100
101
|
const c = await buildHonoContext("t1");
|
|
101
102
|
const deps = { creditLedger: ledger, topUpUrl: "/billing" };
|
|
102
103
|
const result = await creditBalanceCheck(c, deps, 10);
|
|
@@ -110,26 +111,27 @@ describe("creditBalanceCheck grace buffer", () => {
|
|
|
110
111
|
describe("debitCredits with allowNegative and onBalanceExhausted", () => {
|
|
111
112
|
beforeEach(async () => {
|
|
112
113
|
await truncateAllTables(pool);
|
|
114
|
+
await new DrizzleLedger(db).seedSystemAccounts();
|
|
113
115
|
});
|
|
114
116
|
it("debit with cost that would exceed balance succeeds (allowNegative=true)", async () => {
|
|
115
|
-
const ledger = new
|
|
116
|
-
await ledger.credit("t1", Credit.fromCents(5), "purchase", "setup"); // balance = 5 cents
|
|
117
|
+
const ledger = new DrizzleLedger(db);
|
|
118
|
+
await ledger.credit("t1", Credit.fromCents(5), "purchase", { description: "setup" }); // balance = 5 cents
|
|
117
119
|
// costUsd = $0.10 = 10 cents, margin = 1.0
|
|
118
120
|
// This should push balance negative without throwing
|
|
119
121
|
await expect(debitCredits({ creditLedger: ledger, topUpUrl: "/billing" }, "t1", 0.1, 1.0, "chat-completions", "openrouter")).resolves.not.toThrow();
|
|
120
122
|
expect((await ledger.balance("t1")).isNegative()).toBe(true);
|
|
121
123
|
});
|
|
122
124
|
it("fires onBalanceExhausted when debit causes balance to cross zero", async () => {
|
|
123
|
-
const ledger = new
|
|
124
|
-
await ledger.credit("t1", Credit.fromCents(5), "purchase", "setup"); // balance = 5 cents
|
|
125
|
+
const ledger = new DrizzleLedger(db);
|
|
126
|
+
await ledger.credit("t1", Credit.fromCents(5), "purchase", { description: "setup" }); // balance = 5 cents
|
|
125
127
|
const onBalanceExhausted = vi.fn();
|
|
126
128
|
// costUsd = $0.10 = 10 cents with margin 1.0 → chargeCents = 10, pushes balance to -5
|
|
127
129
|
await debitCredits({ creditLedger: ledger, topUpUrl: "/billing", onBalanceExhausted }, "t1", 0.1, 1.0, "chat-completions", "openrouter");
|
|
128
130
|
expect(onBalanceExhausted).toHaveBeenCalledWith("t1", -5);
|
|
129
131
|
});
|
|
130
132
|
it("does NOT fire onBalanceExhausted when balance stays positive after debit", async () => {
|
|
131
|
-
const ledger = new
|
|
132
|
-
await ledger.credit("t1", Credit.fromCents(500), "purchase", "setup"); // balance = 500 cents
|
|
133
|
+
const ledger = new DrizzleLedger(db);
|
|
134
|
+
await ledger.credit("t1", Credit.fromCents(500), "purchase", { description: "setup" }); // balance = 500 cents
|
|
133
135
|
const onBalanceExhausted = vi.fn();
|
|
134
136
|
// costUsd = $0.01 = 1 cent → balance stays at 499
|
|
135
137
|
await debitCredits({ creditLedger: ledger, topUpUrl: "/billing", onBalanceExhausted }, "t1", 0.01, 1.0, "chat-completions", "openrouter");
|
|
@@ -137,8 +139,8 @@ describe("debitCredits with allowNegative and onBalanceExhausted", () => {
|
|
|
137
139
|
expect((await ledger.balance("t1")).greaterThan(Credit.ZERO)).toBe(true);
|
|
138
140
|
});
|
|
139
141
|
it("onBalanceExhausted callback receives correct tenantId and negative balance", async () => {
|
|
140
|
-
const ledger = new
|
|
141
|
-
await ledger.credit("t1", Credit.fromCents(3), "purchase", "setup"); // balance = 3 cents
|
|
142
|
+
const ledger = new DrizzleLedger(db);
|
|
143
|
+
await ledger.credit("t1", Credit.fromCents(3), "purchase", { description: "setup" }); // balance = 3 cents
|
|
142
144
|
const onBalanceExhausted = vi.fn();
|
|
143
145
|
// costUsd = $0.05 = 5 cents with margin 1.0 → pushes balance to -2
|
|
144
146
|
await debitCredits({ creditLedger: ledger, topUpUrl: "/billing", onBalanceExhausted }, "t1", 0.05, 1.0, "chat-completions", "openrouter");
|
|
@@ -146,17 +148,17 @@ describe("debitCredits with allowNegative and onBalanceExhausted", () => {
|
|
|
146
148
|
expect(onBalanceExhausted).toHaveBeenCalledWith("t1", -2);
|
|
147
149
|
});
|
|
148
150
|
it("calls onSpendAlertCrossed after successful debit", async () => {
|
|
149
|
-
const ledger = new
|
|
150
|
-
await ledger.credit("t1", Credit.fromCents(500), "purchase", "setup");
|
|
151
|
+
const ledger = new DrizzleLedger(db);
|
|
152
|
+
await ledger.credit("t1", Credit.fromCents(500), "purchase", { description: "setup" });
|
|
151
153
|
const onSpendAlertCrossed = vi.fn();
|
|
152
154
|
await debitCredits({ creditLedger: ledger, topUpUrl: "/billing", onSpendAlertCrossed }, "t1", 0.05, 1.0, "chat-completions", "openrouter");
|
|
153
155
|
expect(onSpendAlertCrossed).toHaveBeenCalledWith("t1");
|
|
154
156
|
});
|
|
155
157
|
it("does NOT fire onBalanceExhausted when balance was already negative before debit", async () => {
|
|
156
|
-
const ledger = new
|
|
158
|
+
const ledger = new DrizzleLedger(db);
|
|
157
159
|
// Start with negative balance: credit 5, debit 10 → balance = -5
|
|
158
|
-
await ledger.credit("t1", Credit.fromCents(5), "purchase", "setup");
|
|
159
|
-
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", "drain",
|
|
160
|
+
await ledger.credit("t1", Credit.fromCents(5), "purchase", { description: "setup" });
|
|
161
|
+
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", { description: "drain", allowNegative: true });
|
|
160
162
|
const onBalanceExhausted = vi.fn();
|
|
161
163
|
// Another debit of 1 cent — balance goes from -5 to -6, but was already negative
|
|
162
164
|
await debitCredits({ creditLedger: ledger, topUpUrl: "/billing", onBalanceExhausted }, "t1", 0.01, 1.0, "chat-completions", "openrouter");
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Both the Anthropic and OpenAI handlers need the same set of services:
|
|
5
5
|
* budget checking, metering, provider configs, fetch, and service key resolution.
|
|
6
6
|
*/
|
|
7
|
-
import type { Credit,
|
|
7
|
+
import type { Credit, ILedger } from "@wopr-network/platform-core/credits";
|
|
8
8
|
import type { MeterEmitter } from "@wopr-network/platform-core/metering";
|
|
9
9
|
import type { IRateLimitRepository } from "../../api/rate-limit-repository.js";
|
|
10
10
|
import type { IBudgetChecker } from "../../monetization/budget/budget-checker.js";
|
|
@@ -16,7 +16,7 @@ import type { FetchFn, GatewayTenant, ProviderConfig } from "../types.js";
|
|
|
16
16
|
export interface ProtocolDeps {
|
|
17
17
|
meter: MeterEmitter;
|
|
18
18
|
budgetChecker: IBudgetChecker;
|
|
19
|
-
creditLedger?:
|
|
19
|
+
creditLedger?: ILedger;
|
|
20
20
|
topUpUrl: string;
|
|
21
21
|
graceBufferCents?: number;
|
|
22
22
|
providers: ProviderConfig;
|