@nehorai/credits 1.7.0 → 2.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.
- package/README.md +226 -2
- package/dist/adapters/index.cjs +298 -40
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +298 -40
- package/dist/adapters/index.js.map +1 -1
- package/dist/core/index.cjs +696 -74
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +583 -5
- package/dist/core/index.d.ts +583 -5
- package/dist/core/index.js +648 -74
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +1762 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -6
- package/dist/index.d.ts +41 -6
- package/dist/index.js +1706 -365
- package/dist/index.js.map +1 -1
- package/dist/repository/index.cjs +1399 -183
- package/dist/repository/index.cjs.map +1 -1
- package/dist/repository/index.d.cts +141 -15
- package/dist/repository/index.d.ts +141 -15
- package/dist/repository/index.js +1392 -183
- package/dist/repository/index.js.map +1 -1
- package/dist/sdk/index.cjs +23 -1
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.d.cts +2 -2
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +23 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/service/index.cjs +480 -104
- package/dist/service/index.cjs.map +1 -1
- package/dist/service/index.d.cts +68 -10
- package/dist/service/index.d.ts +68 -10
- package/dist/service/index.js +480 -104
- package/dist/service/index.js.map +1 -1
- package/dist/types-BmG5Omzj.d.ts +646 -0
- package/dist/types-C8hZMe8a.d.cts +646 -0
- package/dist/{types-CjLj3GW5.d.cts → types-DJ8yqaVr.d.cts} +39 -1
- package/dist/{types-CjLj3GW5.d.ts → types-DJ8yqaVr.d.ts} +39 -1
- package/package.json +1 -1
- package/dist/types-DFe5BoJY.d.cts +0 -329
- package/dist/types-_bSybQnb.d.ts +0 -329
|
@@ -122,6 +122,20 @@ interface PortableReservation {
|
|
|
122
122
|
expiresAt: string;
|
|
123
123
|
/** When reservation was committed/released - ISO 8601 or undefined */
|
|
124
124
|
completedAt?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Caller-supplied idempotency key (V2). Absent on legacy reservations.
|
|
127
|
+
* Unique per user; a replay with the same key returns this same reservation.
|
|
128
|
+
*/
|
|
129
|
+
idempotencyKey?: string;
|
|
130
|
+
/**
|
|
131
|
+
* When the atomic reserve placed this hold - ISO 8601, or absent.
|
|
132
|
+
*
|
|
133
|
+
* Written by `reserveCreditsV2` inside the same transaction that increases
|
|
134
|
+
* `reserved`, so its presence is proof that the hold exists. `createReservation`
|
|
135
|
+
* never sets it, and the V2 transitions refuse to move a row without it.
|
|
136
|
+
* See `assertHoldPlaced` in `core/reservation-integrity.ts`.
|
|
137
|
+
*/
|
|
138
|
+
holdPlacedAt?: string;
|
|
125
139
|
}
|
|
126
140
|
/**
|
|
127
141
|
* Result of a credit check operation
|
|
@@ -165,6 +179,15 @@ interface MonthlyResetResult {
|
|
|
165
179
|
wasReset: boolean;
|
|
166
180
|
/** The user credits after the operation */
|
|
167
181
|
credits: PortableUserCredits;
|
|
182
|
+
/**
|
|
183
|
+
* `true` when the repository wrote the reset's journal entry inside the same
|
|
184
|
+
* atomic step as the balance write. The service then skips its own journal
|
|
185
|
+
* call — a separate call sits outside the reset's atomicity, and if it fails
|
|
186
|
+
* after the CAS was consumed, the line is lost for good (no retry ever sees
|
|
187
|
+
* the reset again). Absent/`false` means the repository did not journal and
|
|
188
|
+
* the service falls back to the legacy non-atomic write.
|
|
189
|
+
*/
|
|
190
|
+
journaled?: boolean;
|
|
168
191
|
}
|
|
169
192
|
/**
|
|
170
193
|
* Result of subscription expiry check
|
|
@@ -178,6 +201,16 @@ interface SubscriptionExpiryResult {
|
|
|
178
201
|
graceDaysRemaining: number;
|
|
179
202
|
/** The user credits after the operation */
|
|
180
203
|
credits: PortableUserCredits;
|
|
204
|
+
/**
|
|
205
|
+
* `true` when the repository wrote the downgrade's journal entry inside the
|
|
206
|
+
* same atomic step as the tier write. The service then skips its own journal
|
|
207
|
+
* call — a separate call sits outside the downgrade's atomicity, and if it
|
|
208
|
+
* fails after the tier write committed, the account is downgraded with no
|
|
209
|
+
* audit line and no retry ever fires (the row is no longer eligible).
|
|
210
|
+
* Absent/`false` means the repository did not journal and the service falls
|
|
211
|
+
* back to the legacy non-atomic write.
|
|
212
|
+
*/
|
|
213
|
+
journaled?: boolean;
|
|
181
214
|
}
|
|
182
215
|
/**
|
|
183
216
|
* Credit transaction type
|
|
@@ -229,6 +262,11 @@ interface PortableJournalEntry {
|
|
|
229
262
|
description: string;
|
|
230
263
|
/** Additional metadata */
|
|
231
264
|
metadata?: Record<string, unknown>;
|
|
265
|
+
/**
|
|
266
|
+
* Deterministic key that makes this entry unique per user (V2). Absent on
|
|
267
|
+
* legacy entries; present entries cannot be written twice.
|
|
268
|
+
*/
|
|
269
|
+
idempotencyKey?: string;
|
|
232
270
|
/** When this entry was created - ISO 8601 */
|
|
233
271
|
createdAt: string;
|
|
234
272
|
}
|
|
@@ -308,4 +346,4 @@ interface WithCreditsOptions {
|
|
|
308
346
|
resourceType?: ResourceType;
|
|
309
347
|
}
|
|
310
348
|
|
|
311
|
-
export { type AIProviderType as A, type BuiltinTier as B, type
|
|
349
|
+
export { type AIProviderType as A, type BuiltinTier as B, type CreditOperationType as C, type DeductCreditsResult as D, type JournalReferenceType as J, type MonthlyResetResult as M, type PortableTransaction as P, type ReservationStatus as R, type SubscriptionTier as S, type TierConfig as T, type UsageHistoryEntry as U, type WithCreditsOptions as W, type PortableReservation as a, type CreditSource as b, type PortableUserCredits as c, type PortableUsageLog as d, type SubscriptionExpiryResult as e, type PortableJournalEntry as f, type CreditCheckResult as g, type ResourceType as h, type TransactionType as i, type UsageHistoryResponse as j, calculateAvailableCredits as k, toPortableTimestamp as l, toDate as t };
|
|
@@ -122,6 +122,20 @@ interface PortableReservation {
|
|
|
122
122
|
expiresAt: string;
|
|
123
123
|
/** When reservation was committed/released - ISO 8601 or undefined */
|
|
124
124
|
completedAt?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Caller-supplied idempotency key (V2). Absent on legacy reservations.
|
|
127
|
+
* Unique per user; a replay with the same key returns this same reservation.
|
|
128
|
+
*/
|
|
129
|
+
idempotencyKey?: string;
|
|
130
|
+
/**
|
|
131
|
+
* When the atomic reserve placed this hold - ISO 8601, or absent.
|
|
132
|
+
*
|
|
133
|
+
* Written by `reserveCreditsV2` inside the same transaction that increases
|
|
134
|
+
* `reserved`, so its presence is proof that the hold exists. `createReservation`
|
|
135
|
+
* never sets it, and the V2 transitions refuse to move a row without it.
|
|
136
|
+
* See `assertHoldPlaced` in `core/reservation-integrity.ts`.
|
|
137
|
+
*/
|
|
138
|
+
holdPlacedAt?: string;
|
|
125
139
|
}
|
|
126
140
|
/**
|
|
127
141
|
* Result of a credit check operation
|
|
@@ -165,6 +179,15 @@ interface MonthlyResetResult {
|
|
|
165
179
|
wasReset: boolean;
|
|
166
180
|
/** The user credits after the operation */
|
|
167
181
|
credits: PortableUserCredits;
|
|
182
|
+
/**
|
|
183
|
+
* `true` when the repository wrote the reset's journal entry inside the same
|
|
184
|
+
* atomic step as the balance write. The service then skips its own journal
|
|
185
|
+
* call — a separate call sits outside the reset's atomicity, and if it fails
|
|
186
|
+
* after the CAS was consumed, the line is lost for good (no retry ever sees
|
|
187
|
+
* the reset again). Absent/`false` means the repository did not journal and
|
|
188
|
+
* the service falls back to the legacy non-atomic write.
|
|
189
|
+
*/
|
|
190
|
+
journaled?: boolean;
|
|
168
191
|
}
|
|
169
192
|
/**
|
|
170
193
|
* Result of subscription expiry check
|
|
@@ -178,6 +201,16 @@ interface SubscriptionExpiryResult {
|
|
|
178
201
|
graceDaysRemaining: number;
|
|
179
202
|
/** The user credits after the operation */
|
|
180
203
|
credits: PortableUserCredits;
|
|
204
|
+
/**
|
|
205
|
+
* `true` when the repository wrote the downgrade's journal entry inside the
|
|
206
|
+
* same atomic step as the tier write. The service then skips its own journal
|
|
207
|
+
* call — a separate call sits outside the downgrade's atomicity, and if it
|
|
208
|
+
* fails after the tier write committed, the account is downgraded with no
|
|
209
|
+
* audit line and no retry ever fires (the row is no longer eligible).
|
|
210
|
+
* Absent/`false` means the repository did not journal and the service falls
|
|
211
|
+
* back to the legacy non-atomic write.
|
|
212
|
+
*/
|
|
213
|
+
journaled?: boolean;
|
|
181
214
|
}
|
|
182
215
|
/**
|
|
183
216
|
* Credit transaction type
|
|
@@ -229,6 +262,11 @@ interface PortableJournalEntry {
|
|
|
229
262
|
description: string;
|
|
230
263
|
/** Additional metadata */
|
|
231
264
|
metadata?: Record<string, unknown>;
|
|
265
|
+
/**
|
|
266
|
+
* Deterministic key that makes this entry unique per user (V2). Absent on
|
|
267
|
+
* legacy entries; present entries cannot be written twice.
|
|
268
|
+
*/
|
|
269
|
+
idempotencyKey?: string;
|
|
232
270
|
/** When this entry was created - ISO 8601 */
|
|
233
271
|
createdAt: string;
|
|
234
272
|
}
|
|
@@ -308,4 +346,4 @@ interface WithCreditsOptions {
|
|
|
308
346
|
resourceType?: ResourceType;
|
|
309
347
|
}
|
|
310
348
|
|
|
311
|
-
export { type AIProviderType as A, type BuiltinTier as B, type
|
|
349
|
+
export { type AIProviderType as A, type BuiltinTier as B, type CreditOperationType as C, type DeductCreditsResult as D, type JournalReferenceType as J, type MonthlyResetResult as M, type PortableTransaction as P, type ReservationStatus as R, type SubscriptionTier as S, type TierConfig as T, type UsageHistoryEntry as U, type WithCreditsOptions as W, type PortableReservation as a, type CreditSource as b, type PortableUserCredits as c, type PortableUsageLog as d, type SubscriptionExpiryResult as e, type PortableJournalEntry as f, type CreditCheckResult as g, type ResourceType as h, type TransactionType as i, type UsageHistoryResponse as j, calculateAvailableCredits as k, toPortableTimestamp as l, toDate as t };
|
package/package.json
CHANGED
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import { C as CreditSource, J as JournalReferenceType, a as CreditOperationType, P as PortableTransaction, A as AIProviderType, S as SubscriptionTier, b as PortableUserCredits, c as PortableReservation, R as ReservationStatus, d as PortableUsageLog, M as MonthlyResetResult, e as SubscriptionExpiryResult, f as PortableJournalEntry } from './types-CjLj3GW5.cjs';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Input for creating a credit reservation
|
|
5
|
-
*/
|
|
6
|
-
interface CreateReservationInput {
|
|
7
|
-
userId: string;
|
|
8
|
-
amount: number;
|
|
9
|
-
operationType: CreditOperationType;
|
|
10
|
-
expiresAt: Date;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Input for creating a credit transaction
|
|
14
|
-
*/
|
|
15
|
-
interface CreateTransactionInput {
|
|
16
|
-
userId: string;
|
|
17
|
-
type: PortableTransaction["type"];
|
|
18
|
-
amount: number;
|
|
19
|
-
description: string;
|
|
20
|
-
paymentRef?: string;
|
|
21
|
-
previousBalance: number;
|
|
22
|
-
newBalance: number;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Input for logging usage
|
|
26
|
-
*/
|
|
27
|
-
interface CreateUsageLogInput {
|
|
28
|
-
userId: string;
|
|
29
|
-
operationType: CreditOperationType;
|
|
30
|
-
provider: AIProviderType;
|
|
31
|
-
creditsUsed: number;
|
|
32
|
-
success: boolean;
|
|
33
|
-
errorMessage?: string;
|
|
34
|
-
resourceId?: string;
|
|
35
|
-
resourceType?: string;
|
|
36
|
-
requestId?: string;
|
|
37
|
-
metadata?: Record<string, unknown>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Query options for usage logs
|
|
41
|
-
*/
|
|
42
|
-
interface UsageLogQuery {
|
|
43
|
-
userId?: string;
|
|
44
|
-
operationType?: CreditOperationType;
|
|
45
|
-
success?: boolean;
|
|
46
|
-
limit?: number;
|
|
47
|
-
offset?: number;
|
|
48
|
-
startDate?: Date;
|
|
49
|
-
endDate?: Date;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Input for creating a journal entry
|
|
53
|
-
*/
|
|
54
|
-
interface CreateJournalEntryInput {
|
|
55
|
-
userId: string;
|
|
56
|
-
entryType: "debit" | "credit";
|
|
57
|
-
amount: number;
|
|
58
|
-
balanceAfter: number;
|
|
59
|
-
source: CreditSource;
|
|
60
|
-
referenceId: string;
|
|
61
|
-
referenceType: JournalReferenceType;
|
|
62
|
-
description: string;
|
|
63
|
-
metadata?: Record<string, unknown>;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Query options for journal entries
|
|
67
|
-
*/
|
|
68
|
-
interface JournalEntryQuery {
|
|
69
|
-
userId: string;
|
|
70
|
-
source?: CreditSource;
|
|
71
|
-
referenceType?: JournalReferenceType;
|
|
72
|
-
limit?: number;
|
|
73
|
-
offset?: number;
|
|
74
|
-
startDate?: Date;
|
|
75
|
-
endDate?: Date;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Partial update for user credits balance
|
|
79
|
-
*/
|
|
80
|
-
interface CreditBalanceUpdate {
|
|
81
|
-
balance?: number;
|
|
82
|
-
bonusCredits?: number;
|
|
83
|
-
reserved?: number;
|
|
84
|
-
tier?: SubscriptionTier;
|
|
85
|
-
monthlyLimit?: number;
|
|
86
|
-
monthlyUsed?: number;
|
|
87
|
-
monthlyResetAt?: Date | string;
|
|
88
|
-
subscriptionExpiresAt?: Date | string | null;
|
|
89
|
-
/** Increment balance by this amount (alternative to absolute value) */
|
|
90
|
-
balanceIncrement?: number;
|
|
91
|
-
/** Increment bonusCredits by this amount (alternative to absolute value) */
|
|
92
|
-
bonusCreditsIncrement?: number;
|
|
93
|
-
/** Increment reserved by this amount (alternative to absolute value) */
|
|
94
|
-
reservedIncrement?: number;
|
|
95
|
-
/** Increment monthlyUsed by this amount */
|
|
96
|
-
monthlyUsedIncrement?: number;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Input for tier update
|
|
100
|
-
*/
|
|
101
|
-
interface TierUpdateInput {
|
|
102
|
-
tier: SubscriptionTier;
|
|
103
|
-
monthlyLimit: number;
|
|
104
|
-
balance?: number;
|
|
105
|
-
monthlyUsed?: number;
|
|
106
|
-
subscriptionExpiresAt?: Date | string | null;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Optional journal customization for `addCreditsAtomic`.
|
|
110
|
-
*
|
|
111
|
-
* By default a credit add records a journal entry with `source: "purchase"`,
|
|
112
|
-
* `referenceType: "transaction"`, and `{ paymentRef }` metadata. These options
|
|
113
|
-
* let callers override that — e.g. tag a signup grant as `source: "bonus"`, or
|
|
114
|
-
* carry revenue-attribution fields (gross amount, credits granted) so a single
|
|
115
|
-
* journal can serve as the app's revenue ledger.
|
|
116
|
-
*/
|
|
117
|
-
interface AddCreditsAtomicOptions {
|
|
118
|
-
/** Journal entry source (defaults to `"purchase"`). */
|
|
119
|
-
source?: CreditSource;
|
|
120
|
-
/** Journal reference type (defaults to `"transaction"`). */
|
|
121
|
-
referenceType?: JournalReferenceType;
|
|
122
|
-
/**
|
|
123
|
-
* Extra metadata merged onto the journal entry. When `paymentRef` is present
|
|
124
|
-
* it is merged in too (explicit keys here win on collision).
|
|
125
|
-
*/
|
|
126
|
-
metadata?: Record<string, unknown>;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Repository interface for credits database operations
|
|
130
|
-
*
|
|
131
|
-
* Implementations can use any database (Firestore, PostgreSQL, etc.)
|
|
132
|
-
* All methods should handle their own error handling and transactions
|
|
133
|
-
*/
|
|
134
|
-
interface ICreditRepository {
|
|
135
|
-
/**
|
|
136
|
-
* Get user credits balance
|
|
137
|
-
* @param userId - User ID
|
|
138
|
-
* @returns User credits or null if not found
|
|
139
|
-
*/
|
|
140
|
-
getUserCredits(userId: string): Promise<PortableUserCredits | null>;
|
|
141
|
-
/**
|
|
142
|
-
* Initialize credits for a new user
|
|
143
|
-
* @param userId - User ID
|
|
144
|
-
* @param tier - Initial subscription tier
|
|
145
|
-
* @param initialBalance - Initial credit balance
|
|
146
|
-
* @returns Initialized user credits
|
|
147
|
-
*/
|
|
148
|
-
initializeUserCredits(userId: string, tier: SubscriptionTier, initialBalance: number): Promise<PortableUserCredits>;
|
|
149
|
-
/**
|
|
150
|
-
* Update user credits balance
|
|
151
|
-
* @param userId - User ID
|
|
152
|
-
* @param updates - Partial updates to apply
|
|
153
|
-
*/
|
|
154
|
-
updateUserCredits(userId: string, updates: CreditBalanceUpdate): Promise<void>;
|
|
155
|
-
/**
|
|
156
|
-
* Update user subscription tier
|
|
157
|
-
* @param userId - User ID
|
|
158
|
-
* @param input - Tier update data
|
|
159
|
-
*/
|
|
160
|
-
updateUserTier(userId: string, input: TierUpdateInput): Promise<void>;
|
|
161
|
-
/**
|
|
162
|
-
* Create a credit reservation (phase 1 of two-phase commit)
|
|
163
|
-
* @param input - Reservation data
|
|
164
|
-
* @returns Created reservation
|
|
165
|
-
*/
|
|
166
|
-
createReservation(input: CreateReservationInput): Promise<PortableReservation>;
|
|
167
|
-
/**
|
|
168
|
-
* Get a reservation by ID
|
|
169
|
-
* @param userId - User ID
|
|
170
|
-
* @param reservationId - Reservation ID
|
|
171
|
-
* @returns Reservation or null
|
|
172
|
-
*/
|
|
173
|
-
getReservation(userId: string, reservationId: string): Promise<PortableReservation | null>;
|
|
174
|
-
/**
|
|
175
|
-
* Update reservation status
|
|
176
|
-
* @param userId - User ID
|
|
177
|
-
* @param reservationId - Reservation ID
|
|
178
|
-
* @param status - New status
|
|
179
|
-
* @param completedAt - Completion timestamp
|
|
180
|
-
*/
|
|
181
|
-
updateReservationStatus(userId: string, reservationId: string, status: ReservationStatus, completedAt?: Date): Promise<void>;
|
|
182
|
-
/**
|
|
183
|
-
* Reserve credits atomically (creates reservation + updates balance in transaction)
|
|
184
|
-
* @param userId - User ID
|
|
185
|
-
* @param amount - Credits to reserve
|
|
186
|
-
* @param operationType - Operation type for tracking
|
|
187
|
-
* @param expiresAt - Reservation expiry time
|
|
188
|
-
* @returns Created reservation
|
|
189
|
-
* @throws Error if insufficient credits
|
|
190
|
-
*/
|
|
191
|
-
reserveCreditsAtomic(userId: string, amount: number, operationType: CreditOperationType, expiresAt: Date): Promise<PortableReservation>;
|
|
192
|
-
/**
|
|
193
|
-
* Commit a reservation atomically (deducts credits + marks reservation committed)
|
|
194
|
-
* @param userId - User ID
|
|
195
|
-
* @param reservationId - Reservation ID
|
|
196
|
-
* @throws Error if reservation not found or not in reserved state
|
|
197
|
-
*/
|
|
198
|
-
commitReservationAtomic(userId: string, reservationId: string): Promise<void>;
|
|
199
|
-
/**
|
|
200
|
-
* Release a reservation atomically (releases reserved credits + marks reservation released)
|
|
201
|
-
* @param userId - User ID
|
|
202
|
-
* @param reservationId - Reservation ID
|
|
203
|
-
*/
|
|
204
|
-
releaseReservationAtomic(userId: string, reservationId: string): Promise<void>;
|
|
205
|
-
/**
|
|
206
|
-
* Add credits atomically (creates transaction + updates balance)
|
|
207
|
-
* @param userId - User ID
|
|
208
|
-
* @param amount - Credits to add
|
|
209
|
-
* @param description - Transaction description
|
|
210
|
-
* @param paymentRef - Optional payment reference
|
|
211
|
-
* @param options - Optional journal source / reference type / extra metadata
|
|
212
|
-
* for the credit journal entry (e.g. revenue attribution fields). Lets
|
|
213
|
-
* callers record a purchase's gross amount, a bonus/refund source, etc.,
|
|
214
|
-
* instead of the default `source: "purchase"` + `{ paymentRef }` metadata.
|
|
215
|
-
*/
|
|
216
|
-
addCreditsAtomic(userId: string, amount: number, description: string, paymentRef?: string, options?: AddCreditsAtomicOptions): Promise<void>;
|
|
217
|
-
/**
|
|
218
|
-
* Deduct credits from a user's balance atomically.
|
|
219
|
-
*
|
|
220
|
-
* Splits the deduction across `balance` and `bonusCredits`, draining
|
|
221
|
-
* `balance` (monthly, resets each cycle) first so persistent bonus
|
|
222
|
-
* credits survive longer. Runs in a single atomic transaction so
|
|
223
|
-
* concurrent deducts cannot drive either field negative.
|
|
224
|
-
*
|
|
225
|
-
* Callers are responsible for writing any audit record (journal /
|
|
226
|
-
* transaction) — this method only moves credits.
|
|
227
|
-
*
|
|
228
|
-
* @param userId - User ID
|
|
229
|
-
* @param amount - Credits to deduct (positive)
|
|
230
|
-
* @returns Combined totals (balance + bonusCredits) before and after.
|
|
231
|
-
* @throws If user has no credits doc or insufficient credits
|
|
232
|
-
*/
|
|
233
|
-
deductCreditsAtomic(userId: string, amount: number): Promise<{
|
|
234
|
-
previousBalance: number;
|
|
235
|
-
newBalance: number;
|
|
236
|
-
}>;
|
|
237
|
-
/**
|
|
238
|
-
* Create a credit transaction record
|
|
239
|
-
* @param input - Transaction data
|
|
240
|
-
* @returns Created transaction
|
|
241
|
-
*/
|
|
242
|
-
createTransaction(input: CreateTransactionInput): Promise<PortableTransaction>;
|
|
243
|
-
/**
|
|
244
|
-
* Get user's transaction history
|
|
245
|
-
* @param userId - User ID
|
|
246
|
-
* @param limit - Max results
|
|
247
|
-
* @param offset - Skip results
|
|
248
|
-
* @returns List of transactions
|
|
249
|
-
*/
|
|
250
|
-
getTransactions(userId: string, limit?: number, offset?: number): Promise<PortableTransaction[]>;
|
|
251
|
-
/**
|
|
252
|
-
* Log a usage event
|
|
253
|
-
* @param input - Usage log data
|
|
254
|
-
* @returns Created usage log
|
|
255
|
-
*/
|
|
256
|
-
logUsage(input: CreateUsageLogInput): Promise<PortableUsageLog>;
|
|
257
|
-
/**
|
|
258
|
-
* Query usage logs
|
|
259
|
-
* @param query - Query parameters
|
|
260
|
-
* @returns List of usage logs
|
|
261
|
-
*/
|
|
262
|
-
getUsageLogs(query: UsageLogQuery): Promise<PortableUsageLog[]>;
|
|
263
|
-
/**
|
|
264
|
-
* Get usage log count (for pagination)
|
|
265
|
-
* @param query - Query parameters (without limit/offset)
|
|
266
|
-
* @returns Count of matching logs
|
|
267
|
-
*/
|
|
268
|
-
getUsageLogsCount(query: Omit<UsageLogQuery, "limit" | "offset">): Promise<number>;
|
|
269
|
-
/**
|
|
270
|
-
* Find and expire reservations past their expiration time
|
|
271
|
-
* Used by cron job to clean up stale reservations
|
|
272
|
-
* @param batchSize - Maximum number of reservations to process per batch (default: 100)
|
|
273
|
-
* @param maxIterations - Maximum number of pagination iterations to prevent infinite loops (default: 100)
|
|
274
|
-
* @returns Cleanup results with counts and errors
|
|
275
|
-
*/
|
|
276
|
-
findAndExpireReservations(batchSize?: number, maxIterations?: number): Promise<{
|
|
277
|
-
expiredCount: number;
|
|
278
|
-
creditsReleased: number;
|
|
279
|
-
errors: string[];
|
|
280
|
-
}>;
|
|
281
|
-
/**
|
|
282
|
-
* Atomically perform monthly reset if needed
|
|
283
|
-
* Uses optimistic locking to prevent race conditions
|
|
284
|
-
*
|
|
285
|
-
* @param userId - User ID
|
|
286
|
-
* @param tier - User's current subscription tier (for determining new balance)
|
|
287
|
-
* @param expectedResetAt - The expected monthlyResetAt value (for optimistic locking)
|
|
288
|
-
* @returns Result indicating whether reset was performed and updated credits
|
|
289
|
-
*/
|
|
290
|
-
atomicMonthlyReset(userId: string, tier: SubscriptionTier, expectedResetAt: Date | string): Promise<MonthlyResetResult>;
|
|
291
|
-
/**
|
|
292
|
-
* Check and handle subscription expiry with grace period
|
|
293
|
-
* Auto-downgrades expired subscriptions after grace period
|
|
294
|
-
*
|
|
295
|
-
* @param userId - User ID
|
|
296
|
-
* @param gracePeriodDays - Days to allow after expiry before downgrade (default: 3)
|
|
297
|
-
* @returns Result indicating whether downgrade occurred
|
|
298
|
-
*/
|
|
299
|
-
checkAndHandleSubscriptionExpiry(userId: string, gracePeriodDays?: number): Promise<SubscriptionExpiryResult>;
|
|
300
|
-
/**
|
|
301
|
-
* Create a journal entry for audit trail
|
|
302
|
-
* @param input - Journal entry data
|
|
303
|
-
* @returns Created journal entry
|
|
304
|
-
*/
|
|
305
|
-
createJournalEntry(input: CreateJournalEntryInput): Promise<PortableJournalEntry>;
|
|
306
|
-
/**
|
|
307
|
-
* Get journal entries for a user
|
|
308
|
-
* @param query - Query parameters
|
|
309
|
-
* @returns List of journal entries
|
|
310
|
-
*/
|
|
311
|
-
getJournalEntries(query: JournalEntryQuery): Promise<PortableJournalEntry[]>;
|
|
312
|
-
/**
|
|
313
|
-
* Get journal entry count for pagination
|
|
314
|
-
* @param query - Query parameters (without limit/offset)
|
|
315
|
-
* @returns Count of matching entries
|
|
316
|
-
*/
|
|
317
|
-
getJournalEntriesCount(query: Omit<JournalEntryQuery, "limit" | "offset">): Promise<number>;
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Factory type for creating repository instances
|
|
321
|
-
*/
|
|
322
|
-
type CreditRepositoryFactory = () => ICreditRepository;
|
|
323
|
-
/**
|
|
324
|
-
* Convert PortableUserCredits to client-safe format
|
|
325
|
-
* Utility function that implementations can use
|
|
326
|
-
*/
|
|
327
|
-
declare function toClientUserCredits(credits: PortableUserCredits): PortableUserCredits;
|
|
328
|
-
|
|
329
|
-
export { type AddCreditsAtomicOptions as A, type CreateJournalEntryInput as C, type ICreditRepository as I, type JournalEntryQuery as J, type TierUpdateInput as T, type UsageLogQuery as U, type CreateReservationInput as a, type CreateTransactionInput as b, type CreateUsageLogInput as c, type CreditBalanceUpdate as d, type CreditRepositoryFactory as e, toClientUserCredits as t };
|