@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.
Files changed (44) hide show
  1. package/README.md +226 -2
  2. package/dist/adapters/index.cjs +298 -40
  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 +298 -40
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/core/index.cjs +696 -74
  9. package/dist/core/index.cjs.map +1 -1
  10. package/dist/core/index.d.cts +583 -5
  11. package/dist/core/index.d.ts +583 -5
  12. package/dist/core/index.js +648 -74
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/index.cjs +1762 -365
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +41 -6
  17. package/dist/index.d.ts +41 -6
  18. package/dist/index.js +1706 -365
  19. package/dist/index.js.map +1 -1
  20. package/dist/repository/index.cjs +1399 -183
  21. package/dist/repository/index.cjs.map +1 -1
  22. package/dist/repository/index.d.cts +141 -15
  23. package/dist/repository/index.d.ts +141 -15
  24. package/dist/repository/index.js +1392 -183
  25. package/dist/repository/index.js.map +1 -1
  26. package/dist/sdk/index.cjs +23 -1
  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 +23 -1
  31. package/dist/sdk/index.js.map +1 -1
  32. package/dist/service/index.cjs +480 -104
  33. package/dist/service/index.cjs.map +1 -1
  34. package/dist/service/index.d.cts +68 -10
  35. package/dist/service/index.d.ts +68 -10
  36. package/dist/service/index.js +480 -104
  37. package/dist/service/index.js.map +1 -1
  38. package/dist/types-BmG5Omzj.d.ts +646 -0
  39. package/dist/types-C8hZMe8a.d.cts +646 -0
  40. package/dist/{types-CjLj3GW5.d.cts → types-DJ8yqaVr.d.cts} +39 -1
  41. package/dist/{types-CjLj3GW5.d.ts → types-DJ8yqaVr.d.ts} +39 -1
  42. package/package.json +1 -1
  43. package/dist/types-DFe5BoJY.d.cts +0 -329
  44. 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 CreditSource 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 CreditOperationType as a, type PortableUserCredits as b, type PortableReservation 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 };
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 CreditSource 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 CreditOperationType as a, type PortableUserCredits as b, type PortableReservation 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 };
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@nehorai/credits",
3
- "version": "1.7.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -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 };