@nehorai/credits 1.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/LICENSE +21 -0
- package/dist/adapters/generic.d.ts +18 -0
- package/dist/adapters/generic.d.ts.map +1 -0
- package/dist/adapters/generic.js +147 -0
- package/dist/adapters/generic.js.map +1 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +45 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +8 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/auth/api-key.d.ts +37 -0
- package/dist/auth/api-key.d.ts.map +1 -0
- package/dist/auth/api-key.js +94 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +31 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/config/costs.d.ts +61 -0
- package/dist/config/costs.d.ts.map +1 -0
- package/dist/config/costs.js +86 -0
- package/dist/config/costs.js.map +1 -0
- package/dist/config/index.d.ts +165 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +286 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/deferred.d.ts +65 -0
- package/dist/core/deferred.d.ts.map +1 -0
- package/dist/core/deferred.js +72 -0
- package/dist/core/deferred.js.map +1 -0
- package/dist/core/errors.d.ts +78 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +110 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +28 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/operations.d.ts +36 -0
- package/dist/core/operations.d.ts.map +1 -0
- package/dist/core/operations.js +87 -0
- package/dist/core/operations.js.map +1 -0
- package/dist/core/types.d.ts +287 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +93 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/index.d.ts +76 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +182 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/repository/index.d.ts +10 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +11 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/memory/index.d.ts +70 -0
- package/dist/repository/memory/index.d.ts.map +1 -0
- package/dist/repository/memory/index.js +518 -0
- package/dist/repository/memory/index.js.map +1 -0
- package/dist/repository/types.d.ts +283 -0
- package/dist/repository/types.d.ts.map +1 -0
- package/dist/repository/types.js +39 -0
- package/dist/repository/types.js.map +1 -0
- package/dist/repository/utils.d.ts +22 -0
- package/dist/repository/utils.d.ts.map +1 -0
- package/dist/repository/utils.js +40 -0
- package/dist/repository/utils.js.map +1 -0
- package/dist/sdk/admin-client.d.ts +146 -0
- package/dist/sdk/admin-client.d.ts.map +1 -0
- package/dist/sdk/admin-client.js +196 -0
- package/dist/sdk/admin-client.js.map +1 -0
- package/dist/sdk/client.d.ts +144 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +247 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/errors.d.ts +91 -0
- package/dist/sdk/errors.d.ts.map +1 -0
- package/dist/sdk/errors.js +185 -0
- package/dist/sdk/errors.js.map +1 -0
- package/dist/sdk/index.d.ts +13 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +13 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/types.d.ts +110 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +20 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/service/credits-service.d.ts +139 -0
- package/dist/service/credits-service.d.ts.map +1 -0
- package/dist/service/credits-service.js +372 -0
- package/dist/service/credits-service.js.map +1 -0
- package/dist/service/index.d.ts +3 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +2 -0
- package/dist/service/index.js.map +1 -0
- package/dist/utils/error-utils.d.ts +48 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +57 -0
- package/dist/utils/error-utils.js.map +1 -0
- package/dist/utils/index.d.ts +54 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +72 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portable credits types - framework and database agnostic
|
|
3
|
+
*
|
|
4
|
+
* These types use standard JavaScript types (string, Date) instead of
|
|
5
|
+
* Firebase-specific types (Timestamp). This makes the credits system
|
|
6
|
+
* portable to other environments without Firebase dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Note: Firestore Timestamp is handled by the credits-firestore adapter.
|
|
9
|
+
*/
|
|
10
|
+
// ==================== Utility Functions ====================
|
|
11
|
+
/**
|
|
12
|
+
* Calculate available credits from balance, bonus, and reserved amounts.
|
|
13
|
+
*
|
|
14
|
+
* Available = balance + bonusCredits - reserved
|
|
15
|
+
*
|
|
16
|
+
* @param balance - Regular monthly credits
|
|
17
|
+
* @param bonusCredits - Purchased/admin credits
|
|
18
|
+
* @param reserved - Credits locked for in-flight operations
|
|
19
|
+
* @returns Available credits for new operations
|
|
20
|
+
*/
|
|
21
|
+
export function calculateAvailableCredits(balance, bonusCredits, reserved) {
|
|
22
|
+
return balance + bonusCredits - reserved;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert various timestamp formats to ISO string.
|
|
26
|
+
*
|
|
27
|
+
* Handles:
|
|
28
|
+
* - Date objects
|
|
29
|
+
* - ISO string (returned as-is)
|
|
30
|
+
* - Timestamp-like objects with toDate() method (Firebase)
|
|
31
|
+
* - undefined/null (returns current time)
|
|
32
|
+
*
|
|
33
|
+
* @param value - Value to convert
|
|
34
|
+
* @returns ISO 8601 string
|
|
35
|
+
*/
|
|
36
|
+
export function toPortableTimestamp(value) {
|
|
37
|
+
if (!value) {
|
|
38
|
+
return new Date().toISOString();
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "string") {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
if (value instanceof Date) {
|
|
44
|
+
return value.toISOString();
|
|
45
|
+
}
|
|
46
|
+
if (typeof value === "object" &&
|
|
47
|
+
value !== null &&
|
|
48
|
+
"toDate" in value &&
|
|
49
|
+
typeof value.toDate === "function") {
|
|
50
|
+
return value.toDate().toISOString();
|
|
51
|
+
}
|
|
52
|
+
return new Date().toISOString();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Convert various timestamp formats to Date object.
|
|
56
|
+
*
|
|
57
|
+
* Handles:
|
|
58
|
+
* - Date objects (returned as-is)
|
|
59
|
+
* - ISO string
|
|
60
|
+
* - Timestamp-like objects with toDate() method (Firebase)
|
|
61
|
+
* - Invalid values (returns current date)
|
|
62
|
+
*
|
|
63
|
+
* @param value - Value to convert
|
|
64
|
+
* @returns Date object
|
|
65
|
+
*/
|
|
66
|
+
export function toDate(value) {
|
|
67
|
+
if (value instanceof Date) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === "string") {
|
|
71
|
+
return new Date(value);
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === "object" &&
|
|
74
|
+
value !== null &&
|
|
75
|
+
"toDate" in value &&
|
|
76
|
+
typeof value.toDate === "function") {
|
|
77
|
+
return value.toDate();
|
|
78
|
+
}
|
|
79
|
+
return new Date();
|
|
80
|
+
}
|
|
81
|
+
// ==================== Constants ====================
|
|
82
|
+
/**
|
|
83
|
+
* Constants for credit system configuration
|
|
84
|
+
*/
|
|
85
|
+
export const CREDIT_CONSTANTS = {
|
|
86
|
+
/** Grace period in days after subscription expires before downgrade */
|
|
87
|
+
SUBSCRIPTION_GRACE_PERIOD_DAYS: 3,
|
|
88
|
+
/** Low balance notification threshold */
|
|
89
|
+
LOW_BALANCE_THRESHOLD: 10,
|
|
90
|
+
/** Cooldown in hours between low balance notifications */
|
|
91
|
+
LOW_BALANCE_NOTIFICATION_COOLDOWN_HOURS: 24,
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8DAA8D;AAE9D;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAe,EACf,YAAoB,EACpB,QAAgB;IAEhB,OAAO,OAAO,GAAG,YAAY,GAAG,QAAQ,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;IAC7B,CAAC;IAED,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,QAAQ,IAAI,KAAK;QACjB,OAAQ,KAAgC,CAAC,MAAM,KAAK,UAAU,EAC9D,CAAC;QACD,OAAQ,KAAgC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IAClE,CAAC;IAED,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,QAAQ,IAAI,KAAK;QACjB,OAAQ,KAAgC,CAAC,MAAM,KAAK,UAAU,EAC9D,CAAC;QACD,OAAQ,KAAgC,CAAC,MAAM,EAAE,CAAC;IACpD,CAAC;IAED,OAAO,IAAI,IAAI,EAAE,CAAC;AACpB,CAAC;AAgSD,sDAAsD;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,uEAAuE;IACvE,8BAA8B,EAAE,CAAC;IACjC,yCAAyC;IACzC,qBAAqB,EAAE,EAAE;IACzB,0DAA0D;IAC1D,uCAAuC,EAAE,EAAE;CACnC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nehorai/credits - Framework-agnostic credits system
|
|
3
|
+
*
|
|
4
|
+
* Provides a complete credits/billing system with:
|
|
5
|
+
* - Two-phase commit for safe credit deduction
|
|
6
|
+
* - Journal-based audit trail
|
|
7
|
+
* - Subscription tier management
|
|
8
|
+
* - Notification hooks
|
|
9
|
+
* - REST API SDK
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {
|
|
14
|
+
* CreditsService,
|
|
15
|
+
* createInMemoryCreditRepository,
|
|
16
|
+
* CreditError,
|
|
17
|
+
* } from '@nehorai/credits';
|
|
18
|
+
*
|
|
19
|
+
* const repository = createInMemoryCreditRepository();
|
|
20
|
+
* const service = new CreditsService(repository);
|
|
21
|
+
*
|
|
22
|
+
* // Check credits
|
|
23
|
+
* const check = await service.checkCredits(userId, 10);
|
|
24
|
+
* if (!check.hasCredits) {
|
|
25
|
+
* throw new Error(`Need ${check.shortfall} more credits`);
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // Reserve and execute
|
|
29
|
+
* const reservation = await service.reserveCredits(userId, 10, 'story_generation');
|
|
30
|
+
* try {
|
|
31
|
+
* await doWork();
|
|
32
|
+
* await service.commitCredits(userId, reservation.id);
|
|
33
|
+
* } catch (error) {
|
|
34
|
+
* await service.releaseCredits(userId, reservation.id);
|
|
35
|
+
* throw error;
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export * from "./core";
|
|
40
|
+
export { getConfig, initializeConfig, loadConfigFromEnv, getValidOperationTypes, isValidOperationType, getConfigOperationCost, getConfigTierConfig, getConfigMonthlyLimit, isFeatureEnabled, resetConfig, type CreditSystemConfig, } from "./config";
|
|
41
|
+
export { getOperationCosts, getOperationCost, getTierConfig, getMonthlyLimit, getDefaultFreeCredits, getReservationExpiryMs, TIER_CONFIGS, DEFAULT_FREE_CREDITS, RESERVATION_EXPIRY_MS, } from "./config/costs";
|
|
42
|
+
export type { ICreditRepository, CreditRepositoryFactory, CreateReservationInput, CreateTransactionInput, CreateUsageLogInput, CreateJournalEntryInput, UsageLogQuery, JournalEntryQuery, CreditBalanceUpdate, TierUpdateInput, } from "./repository/types";
|
|
43
|
+
export { toClientUserCredits } from "./repository/types";
|
|
44
|
+
export { generateId, getNextMonthlyReset } from "./repository/utils";
|
|
45
|
+
export { InMemoryCreditRepository, createInMemoryCreditRepository, } from "./repository/memory";
|
|
46
|
+
export * from "./auth";
|
|
47
|
+
export * from "./service";
|
|
48
|
+
export * from "./adapters";
|
|
49
|
+
export { registerNotificationHandler, clearNotificationHandlers, clearCooldownState, checkAndNotifyLowBalance, notifySubscriptionExpiring, notifySubscriptionExpired, ConsoleNotificationHandler, type CreditNotificationEvent, type ICreditNotificationHandler, } from "./notifications";
|
|
50
|
+
export { CreditsClient } from "./sdk/client";
|
|
51
|
+
export { AdminCreditsClient } from "./sdk/admin-client";
|
|
52
|
+
export type { CreditsClientConfig, AdminCreditsClientConfig, UserCredits, CreditReservation, CreditCheckResult as SDKCreditCheckResult, ReservationResult, PaginationOptions, UsageHistoryEntry as SDKUsageHistoryEntry, UsageHistoryResponse as SDKUsageHistoryResponse, ApiResponse, SDKErrorCodeType, SubscriptionTier as SDKSubscriptionTier, } from "./sdk/types";
|
|
53
|
+
export type { CreditsConfig, ListUsersResponse, ListUsersOptions, } from "./sdk/admin-client";
|
|
54
|
+
export { SDKErrorCode } from "./sdk/types";
|
|
55
|
+
export { CreditsSDKError, NetworkError, AuthenticationError, AuthorizationError, InsufficientCreditsError as SDKInsufficientCreditsError, ReservationNotFoundError as SDKReservationNotFoundError, ReservationExpiredError as SDKReservationExpiredError, ValidationError, ServerError, parseApiError, } from "./sdk/errors";
|
|
56
|
+
export { getTotalCredits, generateRequestId, parseCreditError, isCreditErrorMessage, isPreviewMode, createDummyReservation, type CreditErrorInfo, } from "./utils";
|
|
57
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,cAAc,QAAQ,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAG7B,cAAc,QAAQ,CAAC;AAGvB,cAAc,WAAW,CAAC;AAG1B,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,GAChC,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,IAAI,oBAAoB,EACzC,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,IAAI,oBAAoB,EACzC,oBAAoB,IAAI,uBAAuB,EAC/C,WAAW,EACX,gBAAgB,EAChB,gBAAgB,IAAI,mBAAmB,GACxC,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,IAAI,2BAA2B,EACvD,wBAAwB,IAAI,2BAA2B,EACvD,uBAAuB,IAAI,0BAA0B,EACrD,eAAe,EACf,WAAW,EACX,aAAa,GACd,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,sBAAsB,EACtB,KAAK,eAAe,GACrB,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nehorai/credits - Framework-agnostic credits system
|
|
3
|
+
*
|
|
4
|
+
* Provides a complete credits/billing system with:
|
|
5
|
+
* - Two-phase commit for safe credit deduction
|
|
6
|
+
* - Journal-based audit trail
|
|
7
|
+
* - Subscription tier management
|
|
8
|
+
* - Notification hooks
|
|
9
|
+
* - REST API SDK
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {
|
|
14
|
+
* CreditsService,
|
|
15
|
+
* createInMemoryCreditRepository,
|
|
16
|
+
* CreditError,
|
|
17
|
+
* } from '@nehorai/credits';
|
|
18
|
+
*
|
|
19
|
+
* const repository = createInMemoryCreditRepository();
|
|
20
|
+
* const service = new CreditsService(repository);
|
|
21
|
+
*
|
|
22
|
+
* // Check credits
|
|
23
|
+
* const check = await service.checkCredits(userId, 10);
|
|
24
|
+
* if (!check.hasCredits) {
|
|
25
|
+
* throw new Error(`Need ${check.shortfall} more credits`);
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // Reserve and execute
|
|
29
|
+
* const reservation = await service.reserveCredits(userId, 10, 'story_generation');
|
|
30
|
+
* try {
|
|
31
|
+
* await doWork();
|
|
32
|
+
* await service.commitCredits(userId, reservation.id);
|
|
33
|
+
* } catch (error) {
|
|
34
|
+
* await service.releaseCredits(userId, reservation.id);
|
|
35
|
+
* throw error;
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
// ==================== Core ====================
|
|
40
|
+
export * from "./core";
|
|
41
|
+
// ==================== Config ====================
|
|
42
|
+
export { getConfig, initializeConfig, loadConfigFromEnv, getValidOperationTypes, isValidOperationType, getConfigOperationCost, getConfigTierConfig, getConfigMonthlyLimit, isFeatureEnabled, resetConfig, } from "./config";
|
|
43
|
+
export { getOperationCosts, getOperationCost, getTierConfig, getMonthlyLimit, getDefaultFreeCredits, getReservationExpiryMs, TIER_CONFIGS, DEFAULT_FREE_CREDITS, RESERVATION_EXPIRY_MS, } from "./config/costs";
|
|
44
|
+
export { toClientUserCredits } from "./repository/types";
|
|
45
|
+
export { generateId, getNextMonthlyReset } from "./repository/utils";
|
|
46
|
+
export { InMemoryCreditRepository, createInMemoryCreditRepository, } from "./repository/memory";
|
|
47
|
+
// ==================== Auth ====================
|
|
48
|
+
export * from "./auth";
|
|
49
|
+
// ==================== Service ====================
|
|
50
|
+
export * from "./service";
|
|
51
|
+
// ==================== Adapters ====================
|
|
52
|
+
export * from "./adapters";
|
|
53
|
+
// ==================== Notifications ====================
|
|
54
|
+
export { registerNotificationHandler, clearNotificationHandlers, clearCooldownState, checkAndNotifyLowBalance, notifySubscriptionExpiring, notifySubscriptionExpired, ConsoleNotificationHandler, } from "./notifications";
|
|
55
|
+
// ==================== SDK ====================
|
|
56
|
+
// Export SDK (excluding types that conflict with core)
|
|
57
|
+
export { CreditsClient } from "./sdk/client";
|
|
58
|
+
export { AdminCreditsClient } from "./sdk/admin-client";
|
|
59
|
+
export { SDKErrorCode } from "./sdk/types";
|
|
60
|
+
export { CreditsSDKError, NetworkError, AuthenticationError, AuthorizationError, InsufficientCreditsError as SDKInsufficientCreditsError, ReservationNotFoundError as SDKReservationNotFoundError, ReservationExpiredError as SDKReservationExpiredError, ValidationError, ServerError, parseApiError, } from "./sdk/errors";
|
|
61
|
+
// ==================== Utils ====================
|
|
62
|
+
export { getTotalCredits, generateRequestId, parseCreditError, isCreditErrorMessage, isPreviewMode, createDummyReservation, } from "./utils";
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,iDAAiD;AACjD,cAAc,QAAQ,CAAC;AAEvB,mDAAmD;AACnD,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,GAEZ,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAgBxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAE7B,iDAAiD;AACjD,cAAc,QAAQ,CAAC;AAEvB,oDAAoD;AACpD,cAAc,WAAW,CAAC;AAE1B,qDAAqD;AACrD,cAAc,YAAY,CAAC;AAE3B,0DAA0D;AAC1D,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,GAG3B,MAAM,iBAAiB,CAAC;AAEzB,gDAAgD;AAChD,uDAAuD;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAoBxD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,IAAI,2BAA2B,EACvD,wBAAwB,IAAI,2BAA2B,EACvD,uBAAuB,IAAI,0BAA0B,EACrD,eAAe,EACf,WAAW,EACX,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,kDAAkD;AAClD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,sBAAsB,GAEvB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification event types
|
|
3
|
+
*/
|
|
4
|
+
export type CreditNotificationEvent = {
|
|
5
|
+
type: "low_balance";
|
|
6
|
+
userId: string;
|
|
7
|
+
balance: number;
|
|
8
|
+
threshold: number;
|
|
9
|
+
} | {
|
|
10
|
+
type: "balance_depleted";
|
|
11
|
+
userId: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: "subscription_expiring";
|
|
14
|
+
userId: string;
|
|
15
|
+
expiresAt: Date;
|
|
16
|
+
daysRemaining: number;
|
|
17
|
+
} | {
|
|
18
|
+
type: "subscription_expired";
|
|
19
|
+
userId: string;
|
|
20
|
+
wasDowngraded: boolean;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Notification handler interface
|
|
24
|
+
* Implementations can send emails, push notifications, etc.
|
|
25
|
+
*/
|
|
26
|
+
export interface ICreditNotificationHandler {
|
|
27
|
+
/**
|
|
28
|
+
* Handle a notification event
|
|
29
|
+
* @param event - The notification event
|
|
30
|
+
*/
|
|
31
|
+
handleNotification(event: CreditNotificationEvent): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register a notification handler
|
|
35
|
+
*/
|
|
36
|
+
export declare function registerNotificationHandler(handler: ICreditNotificationHandler): void;
|
|
37
|
+
/**
|
|
38
|
+
* Clear all notification handlers (for testing)
|
|
39
|
+
*/
|
|
40
|
+
export declare function clearNotificationHandlers(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Clear cooldown state (for testing)
|
|
43
|
+
*/
|
|
44
|
+
export declare function clearCooldownState(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Check and trigger low balance notification if needed
|
|
47
|
+
* Call this after commit operations
|
|
48
|
+
*
|
|
49
|
+
* @param userId - User ID
|
|
50
|
+
* @param newBalance - Balance after the operation
|
|
51
|
+
* @param threshold - Custom threshold (defaults to 10)
|
|
52
|
+
*/
|
|
53
|
+
export declare function checkAndNotifyLowBalance(userId: string, newBalance: number, threshold?: 10): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Trigger subscription expiring notification
|
|
56
|
+
*
|
|
57
|
+
* @param userId - User ID
|
|
58
|
+
* @param expiresAt - When subscription expires
|
|
59
|
+
* @param daysRemaining - Days until expiry
|
|
60
|
+
*/
|
|
61
|
+
export declare function notifySubscriptionExpiring(userId: string, expiresAt: Date, daysRemaining: number): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Trigger subscription expired notification
|
|
64
|
+
*
|
|
65
|
+
* @param userId - User ID
|
|
66
|
+
* @param wasDowngraded - Whether the user was downgraded to free tier
|
|
67
|
+
*/
|
|
68
|
+
export declare function notifySubscriptionExpired(userId: string, wasDowngraded: boolean): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Console notification handler for development/testing
|
|
71
|
+
* Logs notifications to console
|
|
72
|
+
*/
|
|
73
|
+
export declare class ConsoleNotificationHandler implements ICreditNotificationHandler {
|
|
74
|
+
handleNotification(event: CreditNotificationEvent): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC;AAEN;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE;AAyFD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,0BAA0B,GAClC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAyBD;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,KAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,IAAI,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;GAGG;AACH,qBAAa,0BAA2B,YAAW,0BAA0B;IACrE,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BxE"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { CREDIT_CONSTANTS } from "../core/types";
|
|
2
|
+
/**
|
|
3
|
+
* In-memory cooldown tracker
|
|
4
|
+
* In production, this should be stored in a persistent store
|
|
5
|
+
*/
|
|
6
|
+
const cooldownState = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Default notification threshold for low balance
|
|
9
|
+
*/
|
|
10
|
+
const LOW_BALANCE_THRESHOLD = CREDIT_CONSTANTS.LOW_BALANCE_THRESHOLD;
|
|
11
|
+
/**
|
|
12
|
+
* Cooldown period in milliseconds (24 hours)
|
|
13
|
+
*/
|
|
14
|
+
const NOTIFICATION_COOLDOWN_MS = CREDIT_CONSTANTS.LOW_BALANCE_NOTIFICATION_COOLDOWN_HOURS * 60 * 60 * 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a notification is allowed (not in cooldown)
|
|
17
|
+
*/
|
|
18
|
+
function isNotificationAllowed(userId, eventType) {
|
|
19
|
+
const state = cooldownState.get(userId);
|
|
20
|
+
if (!state)
|
|
21
|
+
return true;
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
let lastNotification;
|
|
24
|
+
switch (eventType) {
|
|
25
|
+
case "lowBalance":
|
|
26
|
+
lastNotification = state.lastLowBalanceNotification;
|
|
27
|
+
break;
|
|
28
|
+
case "depleted":
|
|
29
|
+
lastNotification = state.lastDepletedNotification;
|
|
30
|
+
break;
|
|
31
|
+
case "expiring":
|
|
32
|
+
lastNotification = state.lastExpiringNotification;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (!lastNotification)
|
|
36
|
+
return true;
|
|
37
|
+
return now - lastNotification.getTime() > NOTIFICATION_COOLDOWN_MS;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Record that a notification was sent
|
|
41
|
+
*/
|
|
42
|
+
function recordNotification(userId, eventType) {
|
|
43
|
+
const state = cooldownState.get(userId) || {};
|
|
44
|
+
const now = new Date();
|
|
45
|
+
switch (eventType) {
|
|
46
|
+
case "lowBalance":
|
|
47
|
+
state.lastLowBalanceNotification = now;
|
|
48
|
+
break;
|
|
49
|
+
case "depleted":
|
|
50
|
+
state.lastDepletedNotification = now;
|
|
51
|
+
break;
|
|
52
|
+
case "expiring":
|
|
53
|
+
state.lastExpiringNotification = now;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
cooldownState.set(userId, state);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Default notification handlers registry
|
|
60
|
+
* Handlers can be registered at application startup
|
|
61
|
+
*/
|
|
62
|
+
const notificationHandlers = [];
|
|
63
|
+
/**
|
|
64
|
+
* Register a notification handler
|
|
65
|
+
*/
|
|
66
|
+
export function registerNotificationHandler(handler) {
|
|
67
|
+
notificationHandlers.push(handler);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Clear all notification handlers (for testing)
|
|
71
|
+
*/
|
|
72
|
+
export function clearNotificationHandlers() {
|
|
73
|
+
notificationHandlers.length = 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Clear cooldown state (for testing)
|
|
77
|
+
*/
|
|
78
|
+
export function clearCooldownState() {
|
|
79
|
+
cooldownState.clear();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Dispatch a notification event to all handlers
|
|
83
|
+
* Runs asynchronously without blocking
|
|
84
|
+
*/
|
|
85
|
+
async function dispatchNotification(event) {
|
|
86
|
+
if (notificationHandlers.length === 0) {
|
|
87
|
+
// No handlers registered - log for debugging
|
|
88
|
+
console.debug(`[Credits] No notification handlers registered for: ${event.type}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Run handlers in parallel
|
|
92
|
+
await Promise.allSettled(notificationHandlers.map((handler) => handler.handleNotification(event).catch((error) => {
|
|
93
|
+
console.error(`[Credits] Notification handler error:`, error);
|
|
94
|
+
})));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check and trigger low balance notification if needed
|
|
98
|
+
* Call this after commit operations
|
|
99
|
+
*
|
|
100
|
+
* @param userId - User ID
|
|
101
|
+
* @param newBalance - Balance after the operation
|
|
102
|
+
* @param threshold - Custom threshold (defaults to 10)
|
|
103
|
+
*/
|
|
104
|
+
export async function checkAndNotifyLowBalance(userId, newBalance, threshold = LOW_BALANCE_THRESHOLD) {
|
|
105
|
+
// Check if balance is depleted
|
|
106
|
+
if (newBalance <= 0 && isNotificationAllowed(userId, "depleted")) {
|
|
107
|
+
recordNotification(userId, "depleted");
|
|
108
|
+
await dispatchNotification({
|
|
109
|
+
type: "balance_depleted",
|
|
110
|
+
userId,
|
|
111
|
+
});
|
|
112
|
+
return; // Don't also send low balance notification
|
|
113
|
+
}
|
|
114
|
+
// Check if balance is below threshold
|
|
115
|
+
if (newBalance > 0 && newBalance <= threshold && isNotificationAllowed(userId, "lowBalance")) {
|
|
116
|
+
recordNotification(userId, "lowBalance");
|
|
117
|
+
await dispatchNotification({
|
|
118
|
+
type: "low_balance",
|
|
119
|
+
userId,
|
|
120
|
+
balance: newBalance,
|
|
121
|
+
threshold,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Trigger subscription expiring notification
|
|
127
|
+
*
|
|
128
|
+
* @param userId - User ID
|
|
129
|
+
* @param expiresAt - When subscription expires
|
|
130
|
+
* @param daysRemaining - Days until expiry
|
|
131
|
+
*/
|
|
132
|
+
export async function notifySubscriptionExpiring(userId, expiresAt, daysRemaining) {
|
|
133
|
+
if (!isNotificationAllowed(userId, "expiring")) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
recordNotification(userId, "expiring");
|
|
137
|
+
await dispatchNotification({
|
|
138
|
+
type: "subscription_expiring",
|
|
139
|
+
userId,
|
|
140
|
+
expiresAt,
|
|
141
|
+
daysRemaining,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Trigger subscription expired notification
|
|
146
|
+
*
|
|
147
|
+
* @param userId - User ID
|
|
148
|
+
* @param wasDowngraded - Whether the user was downgraded to free tier
|
|
149
|
+
*/
|
|
150
|
+
export async function notifySubscriptionExpired(userId, wasDowngraded) {
|
|
151
|
+
await dispatchNotification({
|
|
152
|
+
type: "subscription_expired",
|
|
153
|
+
userId,
|
|
154
|
+
wasDowngraded,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Console notification handler for development/testing
|
|
159
|
+
* Logs notifications to console
|
|
160
|
+
*/
|
|
161
|
+
export class ConsoleNotificationHandler {
|
|
162
|
+
async handleNotification(event) {
|
|
163
|
+
switch (event.type) {
|
|
164
|
+
case "low_balance":
|
|
165
|
+
console.log(`[Credits Notification] Low balance alert for user ${event.userId}: ` +
|
|
166
|
+
`${event.balance} credits remaining (threshold: ${event.threshold})`);
|
|
167
|
+
break;
|
|
168
|
+
case "balance_depleted":
|
|
169
|
+
console.log(`[Credits Notification] Balance depleted for user ${event.userId}`);
|
|
170
|
+
break;
|
|
171
|
+
case "subscription_expiring":
|
|
172
|
+
console.log(`[Credits Notification] Subscription expiring for user ${event.userId}: ` +
|
|
173
|
+
`${event.daysRemaining} days remaining`);
|
|
174
|
+
break;
|
|
175
|
+
case "subscription_expired":
|
|
176
|
+
console.log(`[Credits Notification] Subscription expired for user ${event.userId}: ` +
|
|
177
|
+
`downgraded=${event.wasDowngraded}`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credits repository - barrel exports
|
|
3
|
+
*
|
|
4
|
+
* Provides database-agnostic interface for credits storage
|
|
5
|
+
*/
|
|
6
|
+
export type { ICreditRepository, CreditRepositoryFactory, CreateReservationInput, CreateTransactionInput, CreateUsageLogInput, CreateJournalEntryInput, UsageLogQuery, JournalEntryQuery, CreditBalanceUpdate, TierUpdateInput, } from "./types";
|
|
7
|
+
export { toClientUserCredits } from "./types";
|
|
8
|
+
export { generateId, toDate, getNextMonthlyReset } from "./utils";
|
|
9
|
+
export { InMemoryCreditRepository, createInMemoryCreditRepository, } from "./memory";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repository/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGlE,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credits repository - barrel exports
|
|
3
|
+
*
|
|
4
|
+
* Provides database-agnostic interface for credits storage
|
|
5
|
+
*/
|
|
6
|
+
export { toClientUserCredits } from "./types";
|
|
7
|
+
// Shared utilities
|
|
8
|
+
export { generateId, toDate, getNextMonthlyReset } from "./utils";
|
|
9
|
+
// In-memory implementation (for testing and prototyping)
|
|
10
|
+
export { InMemoryCreditRepository, createInMemoryCreditRepository, } from "./memory";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repository/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,mBAAmB;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAElE,yDAAyD;AACzD,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-Memory Credit Repository Implementation
|
|
3
|
+
*
|
|
4
|
+
* A database-agnostic implementation of ICreditRepository for testing and prototyping.
|
|
5
|
+
* All data is stored in memory and lost when the process restarts.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* - Unit tests without database dependency
|
|
9
|
+
* - Local development and prototyping
|
|
10
|
+
* - Reference implementation for custom repositories
|
|
11
|
+
*/
|
|
12
|
+
import type { PortableUserCredits, PortableReservation, PortableTransaction, PortableJournalEntry, PortableUsageLog, SubscriptionTier, ReservationStatus, MonthlyResetResult, SubscriptionExpiryResult } from "../../core/types";
|
|
13
|
+
import type { ICreditRepository, CreateReservationInput, CreateTransactionInput, CreateUsageLogInput, CreateJournalEntryInput, UsageLogQuery, JournalEntryQuery, CreditBalanceUpdate, TierUpdateInput } from "../types";
|
|
14
|
+
/**
|
|
15
|
+
* In-Memory implementation of ICreditRepository
|
|
16
|
+
*
|
|
17
|
+
* Implements all repository methods using Map-based storage.
|
|
18
|
+
* Useful for testing and as a reference implementation.
|
|
19
|
+
*/
|
|
20
|
+
export declare class InMemoryCreditRepository implements ICreditRepository {
|
|
21
|
+
private users;
|
|
22
|
+
private reservations;
|
|
23
|
+
private transactions;
|
|
24
|
+
private usageLogs;
|
|
25
|
+
private journalEntries;
|
|
26
|
+
getUserCredits(userId: string): Promise<PortableUserCredits | null>;
|
|
27
|
+
initializeUserCredits(userId: string, tier: SubscriptionTier, initialBalance: number): Promise<PortableUserCredits>;
|
|
28
|
+
updateUserCredits(userId: string, updates: CreditBalanceUpdate): Promise<void>;
|
|
29
|
+
updateUserTier(userId: string, input: TierUpdateInput): Promise<void>;
|
|
30
|
+
createReservation(input: CreateReservationInput): Promise<PortableReservation>;
|
|
31
|
+
getReservation(userId: string, reservationId: string): Promise<PortableReservation | null>;
|
|
32
|
+
updateReservationStatus(userId: string, reservationId: string, status: ReservationStatus, completedAt?: Date): Promise<void>;
|
|
33
|
+
reserveCreditsAtomic(userId: string, amount: number, operationType: string, expiresAt: Date): Promise<PortableReservation>;
|
|
34
|
+
commitReservationAtomic(userId: string, reservationId: string): Promise<void>;
|
|
35
|
+
releaseReservationAtomic(userId: string, reservationId: string): Promise<void>;
|
|
36
|
+
addCreditsAtomic(userId: string, amount: number, description: string, paymentRef?: string): Promise<void>;
|
|
37
|
+
createTransaction(input: CreateTransactionInput): Promise<PortableTransaction>;
|
|
38
|
+
getTransactions(userId: string, limit?: number, offset?: number): Promise<PortableTransaction[]>;
|
|
39
|
+
logUsage(input: CreateUsageLogInput): Promise<PortableUsageLog>;
|
|
40
|
+
getUsageLogs(query: UsageLogQuery): Promise<PortableUsageLog[]>;
|
|
41
|
+
getUsageLogsCount(query: Omit<UsageLogQuery, "limit" | "offset">): Promise<number>;
|
|
42
|
+
createJournalEntry(input: CreateJournalEntryInput): Promise<PortableJournalEntry>;
|
|
43
|
+
getJournalEntries(query: JournalEntryQuery): Promise<PortableJournalEntry[]>;
|
|
44
|
+
getJournalEntriesCount(query: Omit<JournalEntryQuery, "limit" | "offset">): Promise<number>;
|
|
45
|
+
findAndExpireReservations(_batchSize?: number, _maxIterations?: number): Promise<{
|
|
46
|
+
expiredCount: number;
|
|
47
|
+
creditsReleased: number;
|
|
48
|
+
errors: string[];
|
|
49
|
+
}>;
|
|
50
|
+
atomicMonthlyReset(userId: string, tier: SubscriptionTier, expectedResetAt: Date | string): Promise<MonthlyResetResult>;
|
|
51
|
+
checkAndHandleSubscriptionExpiry(userId: string, gracePeriodDays?: number): Promise<SubscriptionExpiryResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Clear all data (useful for testing)
|
|
54
|
+
*/
|
|
55
|
+
clear(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Get all users (useful for testing/debugging)
|
|
58
|
+
*/
|
|
59
|
+
getAllUsers(): PortableUserCredits[];
|
|
60
|
+
/**
|
|
61
|
+
* Get all reservations for a user (useful for testing)
|
|
62
|
+
*/
|
|
63
|
+
getAllReservations(userId: string): PortableReservation[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a new in-memory repository instance
|
|
67
|
+
* Each call creates a fresh, isolated instance
|
|
68
|
+
*/
|
|
69
|
+
export declare function createInMemoryCreditRepository(): InMemoryCreditRepository;
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/repository/memory/index.ts"],"names":[],"mappings":"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"}
|