@nehorai/credits 2.1.0 → 3.0.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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/index.cjs +3 -2
  3. package/dist/adapters/index.cjs.map +1 -1
  4. package/dist/adapters/index.d.cts +2 -2
  5. package/dist/adapters/index.d.ts +2 -2
  6. package/dist/adapters/index.js +3 -2
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/core/index.cjs +218 -2
  9. package/dist/core/index.cjs.map +1 -1
  10. package/dist/core/index.d.cts +183 -5
  11. package/dist/core/index.d.ts +183 -5
  12. package/dist/core/index.js +199 -2
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/index.cjs +477 -59
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +6 -6
  17. package/dist/index.d.ts +6 -6
  18. package/dist/index.js +456 -59
  19. package/dist/index.js.map +1 -1
  20. package/dist/repository/index.cjs +394 -44
  21. package/dist/repository/index.cjs.map +1 -1
  22. package/dist/repository/index.d.cts +36 -7
  23. package/dist/repository/index.d.ts +36 -7
  24. package/dist/repository/index.js +391 -43
  25. package/dist/repository/index.js.map +1 -1
  26. package/dist/sdk/index.cjs +1 -0
  27. package/dist/sdk/index.cjs.map +1 -1
  28. package/dist/sdk/index.d.cts +2 -2
  29. package/dist/sdk/index.d.ts +2 -2
  30. package/dist/sdk/index.js +1 -0
  31. package/dist/sdk/index.js.map +1 -1
  32. package/dist/service/index.cjs +33 -20
  33. package/dist/service/index.cjs.map +1 -1
  34. package/dist/service/index.d.cts +2 -2
  35. package/dist/service/index.d.ts +2 -2
  36. package/dist/service/index.js +33 -20
  37. package/dist/service/index.js.map +1 -1
  38. package/dist/{types-Dzc443vy.d.cts → types-C3sxDvNb.d.cts} +43 -2
  39. package/dist/{types-Dzc443vy.d.ts → types-C3sxDvNb.d.ts} +43 -2
  40. package/dist/{types-BhCdep_t.d.ts → types-CY-oHIMA.d.ts} +55 -4
  41. package/dist/{types-wtksMa4n.d.cts → types-DOjguhEX.d.cts} +55 -4
  42. package/package.json +70 -71
@@ -1,5 +1,5 @@
1
- import { c as PortableUserCredits, g as CreditCheckResult, C as CreditOperationType, a as PortableReservation, d as PortableUsageLog, D as DeductCreditsResult, S as SubscriptionTier, j as UsageHistoryResponse, f as PortableJournalEntry } from '../types-Dzc443vy.cjs';
2
- import { I as ICreditRepository, n as ReserveOutcome, l as ReservationTransitionOptions, C as CommitOutcome, R as ReleaseOutcome, A as AddCreditsAtomicOptions, a as AddCreditsOutcome, J as JournalEntryQuery } from '../types-wtksMa4n.cjs';
1
+ import { c as PortableUserCredits, g as CreditCheckResult, C as CreditOperationType, a as PortableReservation, d as PortableUsageLog, D as DeductCreditsResult, S as SubscriptionTier, j as UsageHistoryResponse, f as PortableJournalEntry } from '../types-C3sxDvNb.cjs';
2
+ import { I as ICreditRepository, o as ReserveOutcome, m as ReservationTransitionOptions, C as CommitOutcome, R as ReleaseOutcome, A as AddCreditsAtomicOptions, a as AddCreditsOutcome, J as JournalEntryQuery } from '../types-DOjguhEX.cjs';
3
3
 
4
4
  /**
5
5
  * Notification callback type for low balance notifications
@@ -1,5 +1,5 @@
1
- import { c as PortableUserCredits, g as CreditCheckResult, C as CreditOperationType, a as PortableReservation, d as PortableUsageLog, D as DeductCreditsResult, S as SubscriptionTier, j as UsageHistoryResponse, f as PortableJournalEntry } from '../types-Dzc443vy.js';
2
- import { I as ICreditRepository, n as ReserveOutcome, l as ReservationTransitionOptions, C as CommitOutcome, R as ReleaseOutcome, A as AddCreditsAtomicOptions, a as AddCreditsOutcome, J as JournalEntryQuery } from '../types-BhCdep_t.js';
1
+ import { c as PortableUserCredits, g as CreditCheckResult, C as CreditOperationType, a as PortableReservation, d as PortableUsageLog, D as DeductCreditsResult, S as SubscriptionTier, j as UsageHistoryResponse, f as PortableJournalEntry } from '../types-C3sxDvNb.js';
2
+ import { I as ICreditRepository, o as ReserveOutcome, m as ReservationTransitionOptions, C as CommitOutcome, R as ReleaseOutcome, A as AddCreditsAtomicOptions, a as AddCreditsOutcome, J as JournalEntryQuery } from '../types-CY-oHIMA.js';
3
3
 
4
4
  /**
5
5
  * Notification callback type for low balance notifications
@@ -130,6 +130,7 @@ function floatSum(values) {
130
130
  for (const value of values) total += value;
131
131
  return total;
132
132
  }
133
+ var FLOAT_NOISE_RELATIVE = 64 * Number.EPSILON;
133
134
  function isValidCreditAmount(value) {
134
135
  if (typeof value !== "number") return false;
135
136
  const cents = toCents(value);
@@ -227,9 +228,9 @@ var creditSystemConfigSchema = z.object({
227
228
  */
228
229
  reservationExpiryMs: z.number().positive().default(5 * 60 * 1e3),
229
230
  /**
230
- * Default credits for new users (free tier)
231
+ * Default credits for new users (free tier). 0 means no signup grant.
231
232
  */
232
- defaultFreeCredits: z.number().positive().default(25),
233
+ defaultFreeCredits: z.number().min(0).default(25),
233
234
  /**
234
235
  * Grace period in days after subscription expires before downgrade
235
236
  */
@@ -498,6 +499,8 @@ function toClientUserCredits(credits) {
498
499
  monthlyUsed: credits.monthlyUsed,
499
500
  monthlyResetAt: toISOString(credits.monthlyResetAt),
500
501
  subscriptionExpiresAt: credits.subscriptionExpiresAt ? toISOString(credits.subscriptionExpiresAt) : null,
502
+ ...credits.expiredHoldBacking !== void 0 ? { expiredHoldBacking: credits.expiredHoldBacking } : {},
503
+ ...credits.signupGrant !== void 0 ? { signupGrant: credits.signupGrant } : {},
501
504
  createdAt: toISOString(credits.createdAt),
502
505
  updatedAt: toISOString(credits.updatedAt)
503
506
  };
@@ -695,6 +698,7 @@ var CreditsService = class {
695
698
  entryType: "debit",
696
699
  amount: 0,
697
700
  // No credits deducted, just tier change
701
+ balanceBefore: sumAmounts(data.balance, data.bonusCredits),
698
702
  // The ledger balance, matching every other journal writer: the V2
699
703
  // transitions and add/deduct all record `balance + bonusCredits`, so
700
704
  // recording `balance` alone made the audit trail disagree with itself
@@ -738,6 +742,7 @@ var CreditsService = class {
738
742
  userId,
739
743
  entryType: balanceChange > 0 ? "credit" : "debit",
740
744
  amount: Math.abs(balanceChange),
745
+ balanceBefore: sumAmounts(data.balance, data.bonusCredits),
741
746
  balanceAfter: sumAmounts(
742
747
  resetResult.credits.balance,
743
748
  resetResult.credits.bonusCredits
@@ -745,9 +750,11 @@ var CreditsService = class {
745
750
  source: "monthly_reset",
746
751
  referenceId: `reset-${Date.now()}`,
747
752
  referenceType: "reset",
748
- description: `Monthly credit reset for ${data.tier} tier.`,
753
+ // The tier the reset ran on, which a concurrent downgrade may have
754
+ // changed since `data` was read.
755
+ description: `Monthly credit reset for ${resetResult.credits.tier} tier.`,
749
756
  metadata: {
750
- tier: data.tier,
757
+ tier: resetResult.credits.tier,
751
758
  previousBalance: data.balance,
752
759
  newBalance: resetResult.credits.balance
753
760
  }
@@ -970,9 +977,18 @@ var CreditsService = class {
970
977
  */
971
978
  async deductCredits(userId, amount, options) {
972
979
  assertValidCreditAmount(amount, { userId, operation: "deductCredits" });
980
+ const operationType = options?.operationType;
981
+ const journal = {
982
+ referenceId: options?.requestId ?? `deduct-${Date.now()}`,
983
+ description: operationType ? `Deducted ${amount} credits for ${getOperationLabel(operationType)}` : `Deducted ${amount} credits`,
984
+ metadata: {
985
+ ...options?.metadata,
986
+ ...operationType && { operationType }
987
+ }
988
+ };
973
989
  let deduction;
974
990
  try {
975
- deduction = await this.repository.deductCreditsAtomic(userId, amount);
991
+ deduction = await this.repository.deductCreditsAtomic(userId, amount, journal);
976
992
  } catch (error) {
977
993
  if (isCreditError(error) && error.code === CreditErrorCode.INVALID_AMOUNT) throw error;
978
994
  const credits = await this.repository.getUserCredits(userId);
@@ -988,21 +1004,18 @@ var CreditsService = class {
988
1004
  shortfall: sumAmounts(amount, -available)
989
1005
  };
990
1006
  }
991
- const operationType = options?.operationType;
992
- await this.repository.createJournalEntry({
993
- userId,
994
- entryType: "debit",
995
- amount,
996
- balanceAfter: deduction.newBalance,
997
- source: "operation_commit",
998
- referenceId: options?.requestId ?? `deduct-${Date.now()}`,
999
- referenceType: "adjustment",
1000
- description: operationType ? `Deducted ${amount} credits for ${getOperationLabel(operationType)}` : `Deducted ${amount} credits`,
1001
- metadata: {
1002
- ...options?.metadata,
1003
- ...operationType && { operationType }
1004
- }
1005
- });
1007
+ if (deduction.journalEntryId === void 0) {
1008
+ await this.repository.createJournalEntry({
1009
+ userId,
1010
+ entryType: "debit",
1011
+ amount,
1012
+ balanceBefore: deduction.previousBalance,
1013
+ balanceAfter: deduction.newBalance,
1014
+ source: "operation_commit",
1015
+ referenceType: "adjustment",
1016
+ ...journal
1017
+ });
1018
+ }
1006
1019
  if (operationType) {
1007
1020
  await this.logUsage({
1008
1021
  userId,