@nehorai/credits 2.1.0 → 2.2.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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/index.cjs +2 -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 +2 -2
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/core/index.cjs +102 -2
  9. package/dist/core/index.cjs.map +1 -1
  10. package/dist/core/index.d.cts +92 -5
  11. package/dist/core/index.d.ts +92 -5
  12. package/dist/core/index.js +92 -2
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/index.cjs +272 -39
  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 +260 -39
  19. package/dist/index.js.map +1 -1
  20. package/dist/repository/index.cjs +247 -39
  21. package/dist/repository/index.cjs.map +1 -1
  22. package/dist/repository/index.d.cts +34 -6
  23. package/dist/repository/index.d.ts +34 -6
  24. package/dist/repository/index.js +244 -38
  25. package/dist/repository/index.js.map +1 -1
  26. package/dist/sdk/index.cjs.map +1 -1
  27. package/dist/sdk/index.d.cts +2 -2
  28. package/dist/sdk/index.d.ts +2 -2
  29. package/dist/sdk/index.js.map +1 -1
  30. package/dist/service/index.cjs +8 -4
  31. package/dist/service/index.cjs.map +1 -1
  32. package/dist/service/index.d.cts +2 -2
  33. package/dist/service/index.d.ts +2 -2
  34. package/dist/service/index.js +8 -4
  35. package/dist/service/index.js.map +1 -1
  36. package/dist/{types-BhCdep_t.d.ts → types-3c-IAwZI.d.ts} +38 -3
  37. package/dist/{types-Dzc443vy.d.cts → types-MaViK5tD.d.cts} +18 -0
  38. package/dist/{types-Dzc443vy.d.ts → types-MaViK5tD.d.ts} +18 -0
  39. package/dist/{types-wtksMa4n.d.cts → types-XSjNXO5l.d.cts} +38 -3
  40. package/package.json +70 -71
@@ -1,4 +1,4 @@
1
- import { P as PortableTransaction, a as PortableReservation, R as ReservationStatus, C as CreditOperationType, b as CreditSource, J as JournalReferenceType, A as AIProviderType, S as SubscriptionTier, c as PortableUserCredits, d as PortableUsageLog, M as MonthlyResetResult, e as SubscriptionExpiryResult, f as PortableJournalEntry } from './types-Dzc443vy.js';
1
+ import { P as PortableTransaction, a as PortableReservation, R as ReservationStatus, C as CreditOperationType, b as CreditSource, J as JournalReferenceType, A as AIProviderType, S as SubscriptionTier, c as PortableUserCredits, d as PortableUsageLog, M as MonthlyResetResult, e as SubscriptionExpiryResult, f as PortableJournalEntry } from './types-MaViK5tD.js';
2
2
 
3
3
  /**
4
4
  * Typed outcomes for the V2 reservation boundary.
@@ -375,9 +375,43 @@ interface TierUpdateInput {
375
375
  tier: SubscriptionTier;
376
376
  monthlyLimit: number;
377
377
  balance?: number;
378
+ /**
379
+ * Atomically lowers balance to at most this, only when the account's current tier is not free.
380
+ * Ignored for an account already free. Cannot be combined with `balance`.
381
+ * Like every balance reduction, it stops at the credits backing outstanding holds.
382
+ */
383
+ balanceCap?: number;
378
384
  monthlyUsed?: number;
379
385
  subscriptionExpiresAt?: Date | string | null;
380
386
  }
387
+ /**
388
+ * Free-tier policy an application hands to a repository, for the decisions that
389
+ * have to be made inside the write, from the account's current state.
390
+ */
391
+ interface CreditPolicyOptions {
392
+ /**
393
+ * Decides a due monthly reset, inside the reset transaction, from the account's current state.
394
+ * null: no reset and no write (wasReset false, monthlyResetAt unchanged).
395
+ * Takes precedence over getMonthlyLimit. monthlyLimit is written only when returned.
396
+ * A throw aborts the transaction.
397
+ *
398
+ * Must be synchronous and free of side effects: a contended transaction runs it again.
399
+ * The balance is validated, and floored at the credits backing outstanding holds.
400
+ */
401
+ resolveMonthlyReset?: (credits: {
402
+ tier: SubscriptionTier;
403
+ balance: number;
404
+ }) => {
405
+ balance: number;
406
+ monthlyLimit?: number;
407
+ } | null;
408
+ /**
409
+ * Balance cap and monthlyLimit on a subscription-expiry downgrade.
410
+ * Default: DEFAULT_FREE_CREDITS in the Firestore adapter, the default tier's
411
+ * configured limit in the in-memory adapter.
412
+ */
413
+ getDowngradeBalanceCap?: () => number;
414
+ }
381
415
  /**
382
416
  * Optional journal customization for `addCreditsAtomic`.
383
417
  *
@@ -582,7 +616,8 @@ interface ICreditRepository extends Partial<ICreditRepositoryV2>, Partial<ICredi
582
616
  * Uses optimistic locking to prevent race conditions
583
617
  *
584
618
  * @param userId - User ID
585
- * @param tier - User's current subscription tier (for determining new balance)
619
+ * @param tier - The tier the caller last read. Not trusted: it may be stale by the
620
+ * time the write runs, so implementations must use the tier stored on the account.
586
621
  * @param expectedResetAt - The expected monthlyResetAt value (for optimistic locking)
587
622
  * @returns Result indicating whether reset was performed and updated credits
588
623
  */
@@ -643,4 +678,4 @@ declare function supportsIdempotentCredit(repository: ICreditRepository): reposi
643
678
  */
644
679
  declare function toClientUserCredits(credits: PortableUserCredits): PortableUserCredits;
645
680
 
646
- export { type AddCreditsAtomicOptions as A, type CommitOutcome as C, type ExpireOutcome as E, type ICreditRepository as I, type JournalEntryQuery as J, type ReleaseOutcome as R, type TerminalReservationStatus as T, type UsageLogQuery as U, type AddCreditsOutcome as a, type AddCreditsV2Input as b, type CreateJournalEntryInput as c, type CreateReservationInput as d, type CreateTransactionInput as e, type CreateUsageLogInput as f, type CreditBalanceUpdate as g, type CreditRepositoryFactory as h, type ExpireReservationV2Options as i, type ICreditRepositoryCreditsV2 as j, type ICreditRepositoryV2 as k, type ReservationTransitionOptions as l, type ReserveCreditsV2Input as m, type ReserveOutcome as n, type TierUpdateInput as o, isCreditedOutcome as p, isReservedOutcome as q, isWinningOutcome as r, reservationJournalKey as s, supportsCreditsV2 as t, supportsIdempotentCredit as u, toClientUserCredits as v };
681
+ export { type AddCreditsAtomicOptions as A, type CommitOutcome as C, type ExpireOutcome as E, type ICreditRepository as I, type JournalEntryQuery as J, type ReleaseOutcome as R, type TerminalReservationStatus as T, type UsageLogQuery as U, type AddCreditsOutcome as a, type AddCreditsV2Input as b, type CreateJournalEntryInput as c, type CreateReservationInput as d, type CreateTransactionInput as e, type CreateUsageLogInput as f, type CreditBalanceUpdate as g, type CreditPolicyOptions as h, type CreditRepositoryFactory as i, type ExpireReservationV2Options as j, type ICreditRepositoryCreditsV2 as k, type ICreditRepositoryV2 as l, type ReservationTransitionOptions as m, type ReserveCreditsV2Input as n, type ReserveOutcome as o, type TierUpdateInput as p, isCreditedOutcome as q, isReservedOutcome as r, isWinningOutcome as s, reservationJournalKey as t, supportsCreditsV2 as u, supportsIdempotentCredit as v, toClientUserCredits as w };
@@ -93,6 +93,17 @@ interface PortableUserCredits {
93
93
  monthlyResetAt: string;
94
94
  /** Subscription expiry (null/undefined for free tier) - ISO 8601 or null */
95
95
  subscriptionExpiresAt?: string | null;
96
+ /**
97
+ * The part of `balance` a balance-lowering write kept only to back outstanding
98
+ * holds. A commit consumes it; a release or expiry removes it from `balance`.
99
+ * Absent means 0. See `planBalanceCap`.
100
+ */
101
+ expiredHoldBacking?: number;
102
+ /**
103
+ * Set when the account was created with a signup-grant claim: the amount
104
+ * granted, 0 when the claim was already taken. Absent on any other account.
105
+ */
106
+ signupGrant?: number;
96
107
  /** Creation timestamp - ISO 8601 */
97
108
  createdAt: string;
98
109
  /** Last update timestamp - ISO 8601 */
@@ -136,6 +147,13 @@ interface PortableReservation {
136
147
  * See `assertHoldPlaced` in `core/reservation-integrity.ts`.
137
148
  */
138
149
  holdPlacedAt?: string;
150
+ /**
151
+ * The part of this hold backed by credits that expired while it was open, and so
152
+ * leave the balance when it closes, however it closes. Absent means 0, as on every
153
+ * hold placed after the expiry. Open holds' shares sum to the account's
154
+ * `expiredHoldBacking`.
155
+ */
156
+ expiredBacking?: number;
139
157
  }
140
158
  /**
141
159
  * Result of a credit check operation
@@ -93,6 +93,17 @@ interface PortableUserCredits {
93
93
  monthlyResetAt: string;
94
94
  /** Subscription expiry (null/undefined for free tier) - ISO 8601 or null */
95
95
  subscriptionExpiresAt?: string | null;
96
+ /**
97
+ * The part of `balance` a balance-lowering write kept only to back outstanding
98
+ * holds. A commit consumes it; a release or expiry removes it from `balance`.
99
+ * Absent means 0. See `planBalanceCap`.
100
+ */
101
+ expiredHoldBacking?: number;
102
+ /**
103
+ * Set when the account was created with a signup-grant claim: the amount
104
+ * granted, 0 when the claim was already taken. Absent on any other account.
105
+ */
106
+ signupGrant?: number;
96
107
  /** Creation timestamp - ISO 8601 */
97
108
  createdAt: string;
98
109
  /** Last update timestamp - ISO 8601 */
@@ -136,6 +147,13 @@ interface PortableReservation {
136
147
  * See `assertHoldPlaced` in `core/reservation-integrity.ts`.
137
148
  */
138
149
  holdPlacedAt?: string;
150
+ /**
151
+ * The part of this hold backed by credits that expired while it was open, and so
152
+ * leave the balance when it closes, however it closes. Absent means 0, as on every
153
+ * hold placed after the expiry. Open holds' shares sum to the account's
154
+ * `expiredHoldBacking`.
155
+ */
156
+ expiredBacking?: number;
139
157
  }
140
158
  /**
141
159
  * Result of a credit check operation
@@ -1,4 +1,4 @@
1
- import { P as PortableTransaction, a as PortableReservation, R as ReservationStatus, C as CreditOperationType, b as CreditSource, J as JournalReferenceType, A as AIProviderType, S as SubscriptionTier, c as PortableUserCredits, d as PortableUsageLog, M as MonthlyResetResult, e as SubscriptionExpiryResult, f as PortableJournalEntry } from './types-Dzc443vy.cjs';
1
+ import { P as PortableTransaction, a as PortableReservation, R as ReservationStatus, C as CreditOperationType, b as CreditSource, J as JournalReferenceType, A as AIProviderType, S as SubscriptionTier, c as PortableUserCredits, d as PortableUsageLog, M as MonthlyResetResult, e as SubscriptionExpiryResult, f as PortableJournalEntry } from './types-MaViK5tD.cjs';
2
2
 
3
3
  /**
4
4
  * Typed outcomes for the V2 reservation boundary.
@@ -375,9 +375,43 @@ interface TierUpdateInput {
375
375
  tier: SubscriptionTier;
376
376
  monthlyLimit: number;
377
377
  balance?: number;
378
+ /**
379
+ * Atomically lowers balance to at most this, only when the account's current tier is not free.
380
+ * Ignored for an account already free. Cannot be combined with `balance`.
381
+ * Like every balance reduction, it stops at the credits backing outstanding holds.
382
+ */
383
+ balanceCap?: number;
378
384
  monthlyUsed?: number;
379
385
  subscriptionExpiresAt?: Date | string | null;
380
386
  }
387
+ /**
388
+ * Free-tier policy an application hands to a repository, for the decisions that
389
+ * have to be made inside the write, from the account's current state.
390
+ */
391
+ interface CreditPolicyOptions {
392
+ /**
393
+ * Decides a due monthly reset, inside the reset transaction, from the account's current state.
394
+ * null: no reset and no write (wasReset false, monthlyResetAt unchanged).
395
+ * Takes precedence over getMonthlyLimit. monthlyLimit is written only when returned.
396
+ * A throw aborts the transaction.
397
+ *
398
+ * Must be synchronous and free of side effects: a contended transaction runs it again.
399
+ * The balance is validated, and floored at the credits backing outstanding holds.
400
+ */
401
+ resolveMonthlyReset?: (credits: {
402
+ tier: SubscriptionTier;
403
+ balance: number;
404
+ }) => {
405
+ balance: number;
406
+ monthlyLimit?: number;
407
+ } | null;
408
+ /**
409
+ * Balance cap and monthlyLimit on a subscription-expiry downgrade.
410
+ * Default: DEFAULT_FREE_CREDITS in the Firestore adapter, the default tier's
411
+ * configured limit in the in-memory adapter.
412
+ */
413
+ getDowngradeBalanceCap?: () => number;
414
+ }
381
415
  /**
382
416
  * Optional journal customization for `addCreditsAtomic`.
383
417
  *
@@ -582,7 +616,8 @@ interface ICreditRepository extends Partial<ICreditRepositoryV2>, Partial<ICredi
582
616
  * Uses optimistic locking to prevent race conditions
583
617
  *
584
618
  * @param userId - User ID
585
- * @param tier - User's current subscription tier (for determining new balance)
619
+ * @param tier - The tier the caller last read. Not trusted: it may be stale by the
620
+ * time the write runs, so implementations must use the tier stored on the account.
586
621
  * @param expectedResetAt - The expected monthlyResetAt value (for optimistic locking)
587
622
  * @returns Result indicating whether reset was performed and updated credits
588
623
  */
@@ -643,4 +678,4 @@ declare function supportsIdempotentCredit(repository: ICreditRepository): reposi
643
678
  */
644
679
  declare function toClientUserCredits(credits: PortableUserCredits): PortableUserCredits;
645
680
 
646
- export { type AddCreditsAtomicOptions as A, type CommitOutcome as C, type ExpireOutcome as E, type ICreditRepository as I, type JournalEntryQuery as J, type ReleaseOutcome as R, type TerminalReservationStatus as T, type UsageLogQuery as U, type AddCreditsOutcome as a, type AddCreditsV2Input as b, type CreateJournalEntryInput as c, type CreateReservationInput as d, type CreateTransactionInput as e, type CreateUsageLogInput as f, type CreditBalanceUpdate as g, type CreditRepositoryFactory as h, type ExpireReservationV2Options as i, type ICreditRepositoryCreditsV2 as j, type ICreditRepositoryV2 as k, type ReservationTransitionOptions as l, type ReserveCreditsV2Input as m, type ReserveOutcome as n, type TierUpdateInput as o, isCreditedOutcome as p, isReservedOutcome as q, isWinningOutcome as r, reservationJournalKey as s, supportsCreditsV2 as t, supportsIdempotentCredit as u, toClientUserCredits as v };
681
+ export { type AddCreditsAtomicOptions as A, type CommitOutcome as C, type ExpireOutcome as E, type ICreditRepository as I, type JournalEntryQuery as J, type ReleaseOutcome as R, type TerminalReservationStatus as T, type UsageLogQuery as U, type AddCreditsOutcome as a, type AddCreditsV2Input as b, type CreateJournalEntryInput as c, type CreateReservationInput as d, type CreateTransactionInput as e, type CreateUsageLogInput as f, type CreditBalanceUpdate as g, type CreditPolicyOptions as h, type CreditRepositoryFactory as i, type ExpireReservationV2Options as j, type ICreditRepositoryCreditsV2 as k, type ICreditRepositoryV2 as l, type ReservationTransitionOptions as m, type ReserveCreditsV2Input as n, type ReserveOutcome as o, type TierUpdateInput as p, isCreditedOutcome as q, isReservedOutcome as r, isWinningOutcome as s, reservationJournalKey as t, supportsCreditsV2 as u, supportsIdempotentCredit as v, toClientUserCredits as w };
package/package.json CHANGED
@@ -1,71 +1,70 @@
1
- {
2
- "name": "@nehorai/credits",
3
- "version": "2.1.0",
4
- "type": "module",
5
- "main": "./dist/index.cjs",
6
- "module": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "require": "./dist/index.cjs"
13
- },
14
- "./core": {
15
- "types": "./dist/core/index.d.ts",
16
- "import": "./dist/core/index.js",
17
- "require": "./dist/core/index.cjs"
18
- },
19
- "./repository": {
20
- "types": "./dist/repository/index.d.ts",
21
- "import": "./dist/repository/index.js",
22
- "require": "./dist/repository/index.cjs"
23
- },
24
- "./auth": {
25
- "types": "./dist/auth/index.d.ts",
26
- "import": "./dist/auth/index.js",
27
- "require": "./dist/auth/index.cjs"
28
- },
29
- "./service": {
30
- "types": "./dist/service/index.d.ts",
31
- "import": "./dist/service/index.js",
32
- "require": "./dist/service/index.cjs"
33
- },
34
- "./adapters": {
35
- "types": "./dist/adapters/index.d.ts",
36
- "import": "./dist/adapters/index.js",
37
- "require": "./dist/adapters/index.cjs"
38
- },
39
- "./sdk": {
40
- "types": "./dist/sdk/index.d.ts",
41
- "import": "./dist/sdk/index.js",
42
- "require": "./dist/sdk/index.cjs"
43
- }
44
- },
45
- "files": [
46
- "dist"
47
- ],
48
- "license": "MIT",
49
- "author": "Nehorai Hadad",
50
- "repository": {
51
- "type": "git",
52
- "url": "https://github.com/NehoraiHadad/nehorai-plugins",
53
- "directory": "packages/credits"
54
- },
55
- "scripts": {
56
- "build": "tsup",
57
- "dev": "tsup --watch",
58
- "typecheck": "tsc --noEmit",
59
- "test": "vitest run",
60
- "test:watch": "vitest",
61
- "prepublishOnly": "pnpm build"
62
- },
63
- "dependencies": {
64
- "zod": "^3.24.2"
65
- },
66
- "devDependencies": {
67
- "typescript": "^5.7.3",
68
- "vitest": "^3.0.5",
69
- "@types/node": "^22.13.4"
70
- }
71
- }
1
+ {
2
+ "name": "@nehorai/credits",
3
+ "version": "2.2.0",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/core/index.d.ts",
16
+ "import": "./dist/core/index.js",
17
+ "require": "./dist/core/index.cjs"
18
+ },
19
+ "./repository": {
20
+ "types": "./dist/repository/index.d.ts",
21
+ "import": "./dist/repository/index.js",
22
+ "require": "./dist/repository/index.cjs"
23
+ },
24
+ "./auth": {
25
+ "types": "./dist/auth/index.d.ts",
26
+ "import": "./dist/auth/index.js",
27
+ "require": "./dist/auth/index.cjs"
28
+ },
29
+ "./service": {
30
+ "types": "./dist/service/index.d.ts",
31
+ "import": "./dist/service/index.js",
32
+ "require": "./dist/service/index.cjs"
33
+ },
34
+ "./adapters": {
35
+ "types": "./dist/adapters/index.d.ts",
36
+ "import": "./dist/adapters/index.js",
37
+ "require": "./dist/adapters/index.cjs"
38
+ },
39
+ "./sdk": {
40
+ "types": "./dist/sdk/index.d.ts",
41
+ "import": "./dist/sdk/index.js",
42
+ "require": "./dist/sdk/index.cjs"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "license": "MIT",
49
+ "author": "Nehorai Hadad",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/NehoraiHadad/nehorai-plugins",
53
+ "directory": "packages/credits"
54
+ },
55
+ "dependencies": {
56
+ "zod": "^3.24.2"
57
+ },
58
+ "devDependencies": {
59
+ "typescript": "^5.7.3",
60
+ "vitest": "^3.0.5",
61
+ "@types/node": "^22.13.4"
62
+ },
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "dev": "tsup --watch",
66
+ "typecheck": "tsc --noEmit",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest"
69
+ }
70
+ }