@sudobility/ratelimit_service 1.0.25 → 1.0.26
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/dist/helpers/EntitlementHelper.d.ts +17 -2
- package/dist/helpers/EntitlementHelper.d.ts.map +1 -1
- package/dist/helpers/EntitlementHelper.js +10 -1
- package/dist/helpers/EntitlementHelper.js.map +1 -1
- package/dist/helpers/RateLimitChecker.d.ts +79 -4
- package/dist/helpers/RateLimitChecker.d.ts.map +1 -1
- package/dist/helpers/RateLimitChecker.js +79 -4
- package/dist/helpers/RateLimitChecker.js.map +1 -1
- package/dist/helpers/RateLimitRouteHandler.d.ts +51 -2
- package/dist/helpers/RateLimitRouteHandler.d.ts.map +1 -1
- package/dist/helpers/RateLimitRouteHandler.js +51 -2
- package/dist/helpers/RateLimitRouteHandler.js.map +1 -1
- package/dist/helpers/RevenueCatHelper.d.ts +6 -0
- package/dist/helpers/RevenueCatHelper.d.ts.map +1 -1
- package/dist/helpers/RevenueCatHelper.js +6 -0
- package/dist/helpers/RevenueCatHelper.js.map +1 -1
- package/dist/middleware/hono.d.ts +18 -5
- package/dist/middleware/hono.d.ts.map +1 -1
- package/dist/middleware/hono.js +18 -5
- package/dist/middleware/hono.js.map +1 -1
- package/dist/utils/time.d.ts +62 -7
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +62 -7
- package/dist/utils/time.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,16 +23,28 @@ import type { RateLimits, RateLimitsConfig } from "../types/rate-limits";
|
|
|
23
23
|
*/
|
|
24
24
|
export declare class EntitlementHelper {
|
|
25
25
|
private readonly config;
|
|
26
|
+
/**
|
|
27
|
+
* Create a new EntitlementHelper.
|
|
28
|
+
*
|
|
29
|
+
* @param config - Rate limits configuration mapping entitlement names to their limits.
|
|
30
|
+
* Must include a "none" key as the required fallback for users without subscriptions.
|
|
31
|
+
*/
|
|
26
32
|
constructor(config: RateLimitsConfig);
|
|
27
33
|
/**
|
|
28
34
|
* Get rate limits for a single entitlement.
|
|
29
35
|
* Falls back to "none" limits if entitlement not found in config.
|
|
36
|
+
*
|
|
37
|
+
* @param entitlement - The entitlement name to look up
|
|
38
|
+
* @returns The rate limits for the entitlement, or "none" limits if not found
|
|
30
39
|
*/
|
|
31
40
|
getRateLimits(entitlement: string): RateLimits;
|
|
32
41
|
/**
|
|
33
42
|
* Get rate limits for multiple entitlements.
|
|
34
43
|
* Returns the upper bound (most permissive) of all entitlements.
|
|
35
|
-
* undefined (unlimited) always wins over any number.
|
|
44
|
+
* `undefined` (unlimited) always wins over any number.
|
|
45
|
+
*
|
|
46
|
+
* @param entitlements - Array of entitlement names to resolve. Empty array returns "none" limits.
|
|
47
|
+
* @returns The most permissive rate limits across all provided entitlements
|
|
36
48
|
*/
|
|
37
49
|
getRateLimits(entitlements: string[]): RateLimits;
|
|
38
50
|
/**
|
|
@@ -45,7 +57,10 @@ export declare class EntitlementHelper {
|
|
|
45
57
|
private computeUpperBound;
|
|
46
58
|
/**
|
|
47
59
|
* Get the maximum (most permissive) limit from an array.
|
|
48
|
-
* undefined (unlimited) always wins.
|
|
60
|
+
* `undefined` (unlimited) always wins.
|
|
61
|
+
*
|
|
62
|
+
* @param values - Array of limit values, where `undefined` means unlimited
|
|
63
|
+
* @returns The most permissive limit: `undefined` if any value is unlimited, otherwise the maximum number
|
|
49
64
|
*/
|
|
50
65
|
private maxLimit;
|
|
51
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntitlementHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntitlementHelper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGzE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,iBAAiB;
|
|
1
|
+
{"version":3,"file":"EntitlementHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntitlementHelper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGzE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,iBAAiB;IAOhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC;;;;;OAKG;gBAC0B,MAAM,EAAE,gBAAgB;IAErD;;;;;;OAMG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU;IAE9C;;;;;;;OAOG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,UAAU;IAoBjD;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;CAUjB"}
|
|
@@ -22,6 +22,12 @@ import { NONE_ENTITLEMENT } from "@sudobility/types";
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
export class EntitlementHelper {
|
|
25
|
+
/**
|
|
26
|
+
* Create a new EntitlementHelper.
|
|
27
|
+
*
|
|
28
|
+
* @param config - Rate limits configuration mapping entitlement names to their limits.
|
|
29
|
+
* Must include a "none" key as the required fallback for users without subscriptions.
|
|
30
|
+
*/
|
|
25
31
|
constructor(config) {
|
|
26
32
|
this.config = config;
|
|
27
33
|
}
|
|
@@ -56,7 +62,10 @@ export class EntitlementHelper {
|
|
|
56
62
|
}
|
|
57
63
|
/**
|
|
58
64
|
* Get the maximum (most permissive) limit from an array.
|
|
59
|
-
* undefined (unlimited) always wins.
|
|
65
|
+
* `undefined` (unlimited) always wins.
|
|
66
|
+
*
|
|
67
|
+
* @param values - Array of limit values, where `undefined` means unlimited
|
|
68
|
+
* @returns The most permissive limit: `undefined` if any value is unlimited, otherwise the maximum number
|
|
60
69
|
*/
|
|
61
70
|
maxLimit(values) {
|
|
62
71
|
// If any value is undefined, result is unlimited
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntitlementHelper.js","sourceRoot":"","sources":["../../src/helpers/EntitlementHelper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,iBAAiB;IAC5B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"EntitlementHelper.js","sourceRoot":"","sources":["../../src/helpers/EntitlementHelper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,iBAAiB;IAC5B;;;;;OAKG;IACH,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAqBzD,aAAa,CAAC,kBAAqC;QACjD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;YACpD,CAAC,CAAC,kBAAkB;YACpB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAEzB,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC3D,CAAC;QAED,8CAA8C;QAC9C,OAAO,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;OAMG;IACK,iBAAiB,CAAC,YAAsB;QAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAC7B,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CACzD,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAChD,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC9C,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;SACnD,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACK,QAAQ,CAAC,MAA8B;QAC7C,iDAAiD;QACjD,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC;YACtC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,6CAA6C;QAC7C,MAAM,aAAa,GAAG,MAAkB,CAAC;QACzC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;IACpC,CAAC;CACF"}
|
|
@@ -34,18 +34,40 @@ export interface RateLimitCheckerConfig {
|
|
|
34
34
|
export declare class RateLimitChecker {
|
|
35
35
|
private readonly db;
|
|
36
36
|
private readonly table;
|
|
37
|
+
/**
|
|
38
|
+
* Create a new RateLimitChecker.
|
|
39
|
+
*
|
|
40
|
+
* @param config - Configuration containing the Drizzle database instance and table reference
|
|
41
|
+
*/
|
|
37
42
|
constructor(config: RateLimitCheckerConfig);
|
|
38
43
|
/**
|
|
39
44
|
* Check if request is within rate limits and increment counters.
|
|
40
45
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
46
|
+
* Checks hourly, daily, and monthly limits in order. If all checks pass,
|
|
47
|
+
* increments the corresponding counters in the database. If any limit is
|
|
48
|
+
* exceeded, returns immediately without incrementing.
|
|
49
|
+
*
|
|
50
|
+
* @param userId - The user's ID (e.g., Firebase UID)
|
|
51
|
+
* @param limits - The rate limits to apply. Use `undefined` for unlimited periods.
|
|
52
|
+
* @param subscriptionStartedAt - When the subscription started (for monthly period calculation).
|
|
53
|
+
* If null, monthly periods fall back to calendar months (1st of each month).
|
|
54
|
+
* @returns Result indicating if request is allowed, remaining limits, and which limit was exceeded (if any)
|
|
55
|
+
* @throws Will propagate database errors if the underlying Drizzle queries fail
|
|
45
56
|
*/
|
|
46
57
|
checkAndIncrement(userId: string, limits: RateLimits, subscriptionStartedAt?: Date | null): Promise<RateLimitCheckResult>;
|
|
47
58
|
/**
|
|
48
59
|
* Get current usage without incrementing (for status queries).
|
|
60
|
+
*
|
|
61
|
+
* Unlike {@link checkAndIncrement}, this method only reads the current counters
|
|
62
|
+
* and does not modify any database state. Useful for displaying usage dashboards
|
|
63
|
+
* or status endpoints.
|
|
64
|
+
*
|
|
65
|
+
* @param userId - The user's ID (e.g., Firebase UID)
|
|
66
|
+
* @param limits - The rate limits to check against. Use `undefined` for unlimited periods.
|
|
67
|
+
* @param subscriptionStartedAt - When the subscription started (for monthly period calculation).
|
|
68
|
+
* If null, monthly periods fall back to calendar months.
|
|
69
|
+
* @returns Result indicating if request would be allowed and remaining limits
|
|
70
|
+
* @throws Will propagate database errors if the underlying Drizzle queries fail
|
|
49
71
|
*/
|
|
50
72
|
checkOnly(userId: string, limits: RateLimits, subscriptionStartedAt?: Date | null): Promise<RateLimitCheckResult>;
|
|
51
73
|
/**
|
|
@@ -60,30 +82,83 @@ export declare class RateLimitChecker {
|
|
|
60
82
|
getHistory(userId: string, periodType: PeriodType, subscriptionStartedAt?: Date | null, limit?: number): Promise<UsageHistory>;
|
|
61
83
|
/**
|
|
62
84
|
* Get current counts for each period type.
|
|
85
|
+
*
|
|
86
|
+
* Runs three parallel queries to fetch the current counter values for
|
|
87
|
+
* hourly, daily, and monthly periods.
|
|
88
|
+
*
|
|
89
|
+
* @param userId - The user's ID
|
|
90
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period calculation
|
|
91
|
+
* @param now - Current timestamp used for period boundary calculation
|
|
92
|
+
* @returns Object with hourly, daily, and monthly count values (0 if no counter exists)
|
|
63
93
|
*/
|
|
64
94
|
private getCurrentCounts;
|
|
65
95
|
/**
|
|
66
96
|
* Get the counter value for a specific period.
|
|
97
|
+
*
|
|
98
|
+
* @param userId - The user's ID
|
|
99
|
+
* @param periodType - The rate limit period type (hourly, daily, monthly)
|
|
100
|
+
* @param periodStart - The start timestamp of the current period window
|
|
101
|
+
* @returns The current request count, or 0 if no counter exists for this period
|
|
67
102
|
*/
|
|
68
103
|
private getCountForPeriod;
|
|
69
104
|
/**
|
|
70
105
|
* Increment counters for enabled limit types.
|
|
106
|
+
*
|
|
107
|
+
* Only increments counters for periods that have defined (non-undefined) limits.
|
|
108
|
+
* Runs all increments in parallel for performance.
|
|
109
|
+
*
|
|
110
|
+
* @param userId - The user's ID
|
|
111
|
+
* @param limits - Rate limits configuration; only periods with defined limits are incremented
|
|
112
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period calculation
|
|
113
|
+
* @param now - Current timestamp used for period boundary calculation
|
|
71
114
|
*/
|
|
72
115
|
private incrementCounters;
|
|
73
116
|
/**
|
|
74
117
|
* Increment a specific period counter (upsert).
|
|
118
|
+
*
|
|
119
|
+
* If a counter row already exists for the given user/period/start combination,
|
|
120
|
+
* increments its request_count by 1. Otherwise, inserts a new row with
|
|
121
|
+
* request_count of 1.
|
|
122
|
+
*
|
|
123
|
+
* @param userId - The user's ID
|
|
124
|
+
* @param periodType - The rate limit period type
|
|
125
|
+
* @param periodStart - The start timestamp of the current period window
|
|
126
|
+
* @param now - Current timestamp used for the updated_at field
|
|
75
127
|
*/
|
|
76
128
|
private incrementPeriodCounter;
|
|
77
129
|
/**
|
|
78
130
|
* Check limits and return result.
|
|
131
|
+
*
|
|
132
|
+
* Checks hourly, daily, and monthly limits in order. Returns the first
|
|
133
|
+
* exceeded limit encountered, or an allowed result if all checks pass.
|
|
134
|
+
*
|
|
135
|
+
* @param counts - Current usage counts for each period
|
|
136
|
+
* @param limits - Rate limits to check against. Periods with `undefined` are skipped (unlimited).
|
|
137
|
+
* @returns Check result with allowed status, remaining counts, and exceeded limit info
|
|
79
138
|
*/
|
|
80
139
|
private checkLimits;
|
|
81
140
|
/**
|
|
82
141
|
* Calculate remaining requests for each period.
|
|
142
|
+
*
|
|
143
|
+
* For defined limits, returns `max(0, limit - count)` to avoid negative values.
|
|
144
|
+
* For undefined (unlimited) limits, returns `undefined`.
|
|
145
|
+
*
|
|
146
|
+
* @param counts - Current usage counts for each period
|
|
147
|
+
* @param limits - Rate limits to calculate remaining against
|
|
148
|
+
* @returns Remaining request counts for each period
|
|
83
149
|
*/
|
|
84
150
|
private calculateRemaining;
|
|
85
151
|
/**
|
|
86
152
|
* Get the end of a period for history entries.
|
|
153
|
+
*
|
|
154
|
+
* Calculates the exclusive end timestamp for a given period, based on the
|
|
155
|
+
* period type and start date. For monthly periods, uses subscription start
|
|
156
|
+
* date for accurate billing cycle boundaries.
|
|
157
|
+
*
|
|
158
|
+
* @param periodType - The rate limit period type
|
|
159
|
+
* @param periodStart - The start timestamp of the period
|
|
160
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period end calculation
|
|
161
|
+
* @returns The exclusive end timestamp of the period
|
|
87
162
|
*/
|
|
88
163
|
private getPeriodEnd;
|
|
89
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitChecker.d.ts","sourceRoot":"","sources":["../../src/helpers/RateLimitChecker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EACL,UAAU,EACV,KAAK,UAAU,EACf,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAElB,MAAM,UAAU,CAAC;AAUlB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;
|
|
1
|
+
{"version":3,"file":"RateLimitChecker.d.ts","sourceRoot":"","sources":["../../src/helpers/RateLimitChecker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EACL,UAAU,EACV,KAAK,UAAU,EACf,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAElB,MAAM,UAAU,CAAC;AAUlB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAE7C;;;;OAIG;gBACS,MAAM,EAAE,sBAAsB;IAK1C;;;;;;;;;;;;;OAaG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,qBAAqB,GAAE,IAAI,GAAG,IAAW,GACxC,OAAO,CAAC,oBAAoB,CAAC;IAsChC;;;;;;;;;;;;;OAaG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,qBAAqB,GAAE,IAAI,GAAG,IAAW,GACxC,OAAO,CAAC,oBAAoB,CAAC;IAiBhC;;;;;;;;OAQG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,qBAAqB,GAAE,IAAI,GAAG,IAAW,EACzC,KAAK,GAAE,MAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IAgCxB;;;;;;;;;;OAUG;YACW,gBAAgB;IA0B9B;;;;;;;OAOG;YACW,iBAAiB;IA2B/B;;;;;;;;;;OAUG;YACW,iBAAiB;IA4C/B;;;;;;;;;;;OAWG;YACW,sBAAsB;IA4CpC;;;;;;;;;OASG;IACH,OAAO,CAAC,WAAW;IA+CnB;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;CAiBrB"}
|
|
@@ -23,6 +23,11 @@ import { getCurrentHourStart, getNextHourStart, getCurrentDayStart, getNextDaySt
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
export class RateLimitChecker {
|
|
26
|
+
/**
|
|
27
|
+
* Create a new RateLimitChecker.
|
|
28
|
+
*
|
|
29
|
+
* @param config - Configuration containing the Drizzle database instance and table reference
|
|
30
|
+
*/
|
|
26
31
|
constructor(config) {
|
|
27
32
|
this.db = config.db;
|
|
28
33
|
this.table = config.table;
|
|
@@ -30,10 +35,16 @@ export class RateLimitChecker {
|
|
|
30
35
|
/**
|
|
31
36
|
* Check if request is within rate limits and increment counters.
|
|
32
37
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
38
|
+
* Checks hourly, daily, and monthly limits in order. If all checks pass,
|
|
39
|
+
* increments the corresponding counters in the database. If any limit is
|
|
40
|
+
* exceeded, returns immediately without incrementing.
|
|
41
|
+
*
|
|
42
|
+
* @param userId - The user's ID (e.g., Firebase UID)
|
|
43
|
+
* @param limits - The rate limits to apply. Use `undefined` for unlimited periods.
|
|
44
|
+
* @param subscriptionStartedAt - When the subscription started (for monthly period calculation).
|
|
45
|
+
* If null, monthly periods fall back to calendar months (1st of each month).
|
|
46
|
+
* @returns Result indicating if request is allowed, remaining limits, and which limit was exceeded (if any)
|
|
47
|
+
* @throws Will propagate database errors if the underlying Drizzle queries fail
|
|
37
48
|
*/
|
|
38
49
|
async checkAndIncrement(userId, limits, subscriptionStartedAt = null) {
|
|
39
50
|
const now = new Date();
|
|
@@ -61,6 +72,17 @@ export class RateLimitChecker {
|
|
|
61
72
|
}
|
|
62
73
|
/**
|
|
63
74
|
* Get current usage without incrementing (for status queries).
|
|
75
|
+
*
|
|
76
|
+
* Unlike {@link checkAndIncrement}, this method only reads the current counters
|
|
77
|
+
* and does not modify any database state. Useful for displaying usage dashboards
|
|
78
|
+
* or status endpoints.
|
|
79
|
+
*
|
|
80
|
+
* @param userId - The user's ID (e.g., Firebase UID)
|
|
81
|
+
* @param limits - The rate limits to check against. Use `undefined` for unlimited periods.
|
|
82
|
+
* @param subscriptionStartedAt - When the subscription started (for monthly period calculation).
|
|
83
|
+
* If null, monthly periods fall back to calendar months.
|
|
84
|
+
* @returns Result indicating if request would be allowed and remaining limits
|
|
85
|
+
* @throws Will propagate database errors if the underlying Drizzle queries fail
|
|
64
86
|
*/
|
|
65
87
|
async checkOnly(userId, limits, subscriptionStartedAt = null) {
|
|
66
88
|
const now = new Date();
|
|
@@ -106,6 +128,14 @@ export class RateLimitChecker {
|
|
|
106
128
|
}
|
|
107
129
|
/**
|
|
108
130
|
* Get current counts for each period type.
|
|
131
|
+
*
|
|
132
|
+
* Runs three parallel queries to fetch the current counter values for
|
|
133
|
+
* hourly, daily, and monthly periods.
|
|
134
|
+
*
|
|
135
|
+
* @param userId - The user's ID
|
|
136
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period calculation
|
|
137
|
+
* @param now - Current timestamp used for period boundary calculation
|
|
138
|
+
* @returns Object with hourly, daily, and monthly count values (0 if no counter exists)
|
|
109
139
|
*/
|
|
110
140
|
async getCurrentCounts(userId, subscriptionStartedAt, now) {
|
|
111
141
|
const [hourlyCount, dailyCount, monthlyCount] = await Promise.all([
|
|
@@ -121,6 +151,11 @@ export class RateLimitChecker {
|
|
|
121
151
|
}
|
|
122
152
|
/**
|
|
123
153
|
* Get the counter value for a specific period.
|
|
154
|
+
*
|
|
155
|
+
* @param userId - The user's ID
|
|
156
|
+
* @param periodType - The rate limit period type (hourly, daily, monthly)
|
|
157
|
+
* @param periodStart - The start timestamp of the current period window
|
|
158
|
+
* @returns The current request count, or 0 if no counter exists for this period
|
|
124
159
|
*/
|
|
125
160
|
async getCountForPeriod(userId, periodType, periodStart) {
|
|
126
161
|
const tableAny = this.table;
|
|
@@ -137,6 +172,14 @@ export class RateLimitChecker {
|
|
|
137
172
|
}
|
|
138
173
|
/**
|
|
139
174
|
* Increment counters for enabled limit types.
|
|
175
|
+
*
|
|
176
|
+
* Only increments counters for periods that have defined (non-undefined) limits.
|
|
177
|
+
* Runs all increments in parallel for performance.
|
|
178
|
+
*
|
|
179
|
+
* @param userId - The user's ID
|
|
180
|
+
* @param limits - Rate limits configuration; only periods with defined limits are incremented
|
|
181
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period calculation
|
|
182
|
+
* @param now - Current timestamp used for period boundary calculation
|
|
140
183
|
*/
|
|
141
184
|
async incrementCounters(userId, limits, subscriptionStartedAt, now) {
|
|
142
185
|
const updates = [];
|
|
@@ -153,6 +196,15 @@ export class RateLimitChecker {
|
|
|
153
196
|
}
|
|
154
197
|
/**
|
|
155
198
|
* Increment a specific period counter (upsert).
|
|
199
|
+
*
|
|
200
|
+
* If a counter row already exists for the given user/period/start combination,
|
|
201
|
+
* increments its request_count by 1. Otherwise, inserts a new row with
|
|
202
|
+
* request_count of 1.
|
|
203
|
+
*
|
|
204
|
+
* @param userId - The user's ID
|
|
205
|
+
* @param periodType - The rate limit period type
|
|
206
|
+
* @param periodStart - The start timestamp of the current period window
|
|
207
|
+
* @param now - Current timestamp used for the updated_at field
|
|
156
208
|
*/
|
|
157
209
|
async incrementPeriodCounter(userId, periodType, periodStart, now) {
|
|
158
210
|
const tableAny = this.table;
|
|
@@ -187,6 +239,13 @@ export class RateLimitChecker {
|
|
|
187
239
|
}
|
|
188
240
|
/**
|
|
189
241
|
* Check limits and return result.
|
|
242
|
+
*
|
|
243
|
+
* Checks hourly, daily, and monthly limits in order. Returns the first
|
|
244
|
+
* exceeded limit encountered, or an allowed result if all checks pass.
|
|
245
|
+
*
|
|
246
|
+
* @param counts - Current usage counts for each period
|
|
247
|
+
* @param limits - Rate limits to check against. Periods with `undefined` are skipped (unlimited).
|
|
248
|
+
* @returns Check result with allowed status, remaining counts, and exceeded limit info
|
|
190
249
|
*/
|
|
191
250
|
checkLimits(counts, limits) {
|
|
192
251
|
const remaining = this.calculateRemaining(counts, limits);
|
|
@@ -229,6 +288,13 @@ export class RateLimitChecker {
|
|
|
229
288
|
}
|
|
230
289
|
/**
|
|
231
290
|
* Calculate remaining requests for each period.
|
|
291
|
+
*
|
|
292
|
+
* For defined limits, returns `max(0, limit - count)` to avoid negative values.
|
|
293
|
+
* For undefined (unlimited) limits, returns `undefined`.
|
|
294
|
+
*
|
|
295
|
+
* @param counts - Current usage counts for each period
|
|
296
|
+
* @param limits - Rate limits to calculate remaining against
|
|
297
|
+
* @returns Remaining request counts for each period
|
|
232
298
|
*/
|
|
233
299
|
calculateRemaining(counts, limits) {
|
|
234
300
|
return {
|
|
@@ -245,6 +311,15 @@ export class RateLimitChecker {
|
|
|
245
311
|
}
|
|
246
312
|
/**
|
|
247
313
|
* Get the end of a period for history entries.
|
|
314
|
+
*
|
|
315
|
+
* Calculates the exclusive end timestamp for a given period, based on the
|
|
316
|
+
* period type and start date. For monthly periods, uses subscription start
|
|
317
|
+
* date for accurate billing cycle boundaries.
|
|
318
|
+
*
|
|
319
|
+
* @param periodType - The rate limit period type
|
|
320
|
+
* @param periodStart - The start timestamp of the period
|
|
321
|
+
* @param subscriptionStartedAt - Subscription start date for monthly period end calculation
|
|
322
|
+
* @returns The exclusive end timestamp of the period
|
|
248
323
|
*/
|
|
249
324
|
getPeriodEnd(periodType, periodStart, subscriptionStartedAt) {
|
|
250
325
|
switch (periodType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitChecker.js","sourceRoot":"","sources":["../../src/helpers/RateLimitChecker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EACL,UAAU,GAOX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAYvB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,gBAAgB;IAI3B,YAAY,MAA8B;QACxC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"RateLimitChecker.js","sourceRoot":"","sources":["../../src/helpers/RateLimitChecker.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,30 @@ export interface RateLimitRouteHandlerConfig {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Helper for rate limit API endpoints.
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
|
+
* Provides structured data for rate limit status and history endpoints.
|
|
24
|
+
* Combines RevenueCat subscription info, entitlement-based limit resolution,
|
|
25
|
+
* and database counter data into API-ready response formats.
|
|
26
|
+
*
|
|
27
|
+
* Used by consuming APIs to implement:
|
|
28
|
+
* - `GET /ratelimits` - Current limits, usage, and tier info
|
|
29
|
+
* - `GET /ratelimits/history/:periodType` - Historical usage data
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const handler = new RateLimitRouteHandler({
|
|
34
|
+
* revenueCatApiKey: process.env.REVENUECAT_API_KEY!,
|
|
35
|
+
* rateLimitsConfig: config,
|
|
36
|
+
* db,
|
|
37
|
+
* rateLimitsTable: rateLimitCounters,
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // In a Hono route:
|
|
41
|
+
* app.get("/ratelimits", async (c) => {
|
|
42
|
+
* const data = await handler.getRateLimitsConfigData(userId);
|
|
43
|
+
* return c.json({ success: true, data });
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
23
46
|
*/
|
|
24
47
|
export declare class RateLimitRouteHandler {
|
|
25
48
|
private readonly rcHelper;
|
|
@@ -27,6 +50,12 @@ export declare class RateLimitRouteHandler {
|
|
|
27
50
|
private readonly rateLimitChecker;
|
|
28
51
|
private readonly rateLimitsConfig;
|
|
29
52
|
private readonly displayNames;
|
|
53
|
+
/**
|
|
54
|
+
* Create a new RateLimitRouteHandler.
|
|
55
|
+
*
|
|
56
|
+
* @param config - Configuration including RevenueCat API key, rate limits config,
|
|
57
|
+
* database instance, table reference, and optional display name mappings.
|
|
58
|
+
*/
|
|
30
59
|
constructor(config: RateLimitRouteHandlerConfig);
|
|
31
60
|
/**
|
|
32
61
|
* Get rate limits configuration data for /ratelimits endpoint.
|
|
@@ -48,24 +77,44 @@ export declare class RateLimitRouteHandler {
|
|
|
48
77
|
getRateLimitHistoryData(userId: string, periodType: RateLimitPeriodType, limit?: number, testMode?: boolean): Promise<RateLimitHistoryData>;
|
|
49
78
|
/**
|
|
50
79
|
* Get display name for an entitlement.
|
|
80
|
+
*
|
|
81
|
+
* Checks custom display names first, then defaults, then falls back
|
|
82
|
+
* to capitalizing the first letter of the entitlement name.
|
|
83
|
+
*
|
|
84
|
+
* @param entitlement - The entitlement identifier
|
|
85
|
+
* @returns Human-readable display name for the entitlement
|
|
51
86
|
*/
|
|
52
87
|
private getDisplayName;
|
|
53
88
|
/**
|
|
54
89
|
* Get the primary entitlement from a list.
|
|
55
90
|
* Returns the first entitlement that has configured limits, or "none".
|
|
91
|
+
*
|
|
92
|
+
* @param entitlements - Array of entitlement names from RevenueCat
|
|
93
|
+
* @returns The first non-"none" entitlement with configured limits, or "none"
|
|
56
94
|
*/
|
|
57
95
|
private getPrimaryEntitlement;
|
|
58
96
|
/**
|
|
59
97
|
* Convert internal RateLimits to API RateLimits.
|
|
60
|
-
* Internal uses undefined for unlimited, API uses null
|
|
98
|
+
* Internal uses `undefined` for unlimited, API uses `null`.
|
|
99
|
+
*
|
|
100
|
+
* @param limits - Internal rate limits with undefined for unlimited
|
|
101
|
+
* @returns API rate limits with null for unlimited
|
|
61
102
|
*/
|
|
62
103
|
private convertLimits;
|
|
63
104
|
/**
|
|
64
105
|
* Convert API period type to internal period type.
|
|
106
|
+
*
|
|
107
|
+
* @param periodType - API period type string ("hour", "day", "month")
|
|
108
|
+
* @returns Internal PeriodType enum value
|
|
109
|
+
* @throws Error if an invalid period type is provided
|
|
65
110
|
*/
|
|
66
111
|
private convertPeriodType;
|
|
67
112
|
/**
|
|
68
113
|
* Get the limit for a specific period type.
|
|
114
|
+
*
|
|
115
|
+
* @param limits - Internal rate limits
|
|
116
|
+
* @param periodType - API period type string ("hour", "day", "month")
|
|
117
|
+
* @returns The limit number for the period, or null if unlimited
|
|
69
118
|
*/
|
|
70
119
|
private getLimitForPeriod;
|
|
71
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitRouteHandler.d.ts","sourceRoot":"","sources":["../../src/helpers/RateLimitRouteHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAEL,KAAK,oBAAoB,EAKzB,KAAK,oBAAoB,EAEzB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,UAAU,CAAC;AAOlB;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,uDAAuD;IACvD,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAYD
|
|
1
|
+
{"version":3,"file":"RateLimitRouteHandler.d.ts","sourceRoot":"","sources":["../../src/helpers/RateLimitRouteHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAEL,KAAK,oBAAoB,EAKzB,KAAK,oBAAoB,EAEzB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,UAAU,CAAC;AAOlB;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,uDAAuD;IACvD,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAEtD;;;;;OAKG;gBACS,MAAM,EAAE,2BAA2B;IAc/C;;;;;;OAMG;IACG,uBAAuB,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,oBAAoB,CAAC;IAuEhC;;;;;;;;OAQG;IACG,uBAAuB,CAC3B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,mBAAmB,EAC/B,KAAK,GAAE,MAAY,EACnB,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,oBAAoB,CAAC;IA6ChC;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAY7B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAQrB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;CAe1B"}
|
|
@@ -15,9 +15,38 @@ const DEFAULT_DISPLAY_NAMES = {
|
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
17
|
* Helper for rate limit API endpoints.
|
|
18
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* Provides structured data for rate limit status and history endpoints.
|
|
20
|
+
* Combines RevenueCat subscription info, entitlement-based limit resolution,
|
|
21
|
+
* and database counter data into API-ready response formats.
|
|
22
|
+
*
|
|
23
|
+
* Used by consuming APIs to implement:
|
|
24
|
+
* - `GET /ratelimits` - Current limits, usage, and tier info
|
|
25
|
+
* - `GET /ratelimits/history/:periodType` - Historical usage data
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const handler = new RateLimitRouteHandler({
|
|
30
|
+
* revenueCatApiKey: process.env.REVENUECAT_API_KEY!,
|
|
31
|
+
* rateLimitsConfig: config,
|
|
32
|
+
* db,
|
|
33
|
+
* rateLimitsTable: rateLimitCounters,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // In a Hono route:
|
|
37
|
+
* app.get("/ratelimits", async (c) => {
|
|
38
|
+
* const data = await handler.getRateLimitsConfigData(userId);
|
|
39
|
+
* return c.json({ success: true, data });
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
19
42
|
*/
|
|
20
43
|
export class RateLimitRouteHandler {
|
|
44
|
+
/**
|
|
45
|
+
* Create a new RateLimitRouteHandler.
|
|
46
|
+
*
|
|
47
|
+
* @param config - Configuration including RevenueCat API key, rate limits config,
|
|
48
|
+
* database instance, table reference, and optional display name mappings.
|
|
49
|
+
*/
|
|
21
50
|
constructor(config) {
|
|
22
51
|
this.rcHelper = new RevenueCatHelper({ apiKey: config.revenueCatApiKey });
|
|
23
52
|
this.entitlementHelper = new EntitlementHelper(config.rateLimitsConfig);
|
|
@@ -133,6 +162,12 @@ export class RateLimitRouteHandler {
|
|
|
133
162
|
}
|
|
134
163
|
/**
|
|
135
164
|
* Get display name for an entitlement.
|
|
165
|
+
*
|
|
166
|
+
* Checks custom display names first, then defaults, then falls back
|
|
167
|
+
* to capitalizing the first letter of the entitlement name.
|
|
168
|
+
*
|
|
169
|
+
* @param entitlement - The entitlement identifier
|
|
170
|
+
* @returns Human-readable display name for the entitlement
|
|
136
171
|
*/
|
|
137
172
|
getDisplayName(entitlement) {
|
|
138
173
|
if (this.displayNames[entitlement]) {
|
|
@@ -144,6 +179,9 @@ export class RateLimitRouteHandler {
|
|
|
144
179
|
/**
|
|
145
180
|
* Get the primary entitlement from a list.
|
|
146
181
|
* Returns the first entitlement that has configured limits, or "none".
|
|
182
|
+
*
|
|
183
|
+
* @param entitlements - Array of entitlement names from RevenueCat
|
|
184
|
+
* @returns The first non-"none" entitlement with configured limits, or "none"
|
|
147
185
|
*/
|
|
148
186
|
getPrimaryEntitlement(entitlements) {
|
|
149
187
|
for (const entitlement of entitlements) {
|
|
@@ -156,7 +194,10 @@ export class RateLimitRouteHandler {
|
|
|
156
194
|
}
|
|
157
195
|
/**
|
|
158
196
|
* Convert internal RateLimits to API RateLimits.
|
|
159
|
-
* Internal uses undefined for unlimited, API uses null
|
|
197
|
+
* Internal uses `undefined` for unlimited, API uses `null`.
|
|
198
|
+
*
|
|
199
|
+
* @param limits - Internal rate limits with undefined for unlimited
|
|
200
|
+
* @returns API rate limits with null for unlimited
|
|
160
201
|
*/
|
|
161
202
|
convertLimits(limits) {
|
|
162
203
|
return {
|
|
@@ -167,6 +208,10 @@ export class RateLimitRouteHandler {
|
|
|
167
208
|
}
|
|
168
209
|
/**
|
|
169
210
|
* Convert API period type to internal period type.
|
|
211
|
+
*
|
|
212
|
+
* @param periodType - API period type string ("hour", "day", "month")
|
|
213
|
+
* @returns Internal PeriodType enum value
|
|
214
|
+
* @throws Error if an invalid period type is provided
|
|
170
215
|
*/
|
|
171
216
|
convertPeriodType(periodType) {
|
|
172
217
|
switch (periodType) {
|
|
@@ -182,6 +227,10 @@ export class RateLimitRouteHandler {
|
|
|
182
227
|
}
|
|
183
228
|
/**
|
|
184
229
|
* Get the limit for a specific period type.
|
|
230
|
+
*
|
|
231
|
+
* @param limits - Internal rate limits
|
|
232
|
+
* @param periodType - API period type string ("hour", "day", "month")
|
|
233
|
+
* @returns The limit number for the period, or null if unlimited
|
|
185
234
|
*/
|
|
186
235
|
getLimitForPeriod(limits, periodType) {
|
|
187
236
|
switch (periodType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitRouteHandler.js","sourceRoot":"","sources":["../../src/helpers/RateLimitRouteHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,GASjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EACL,UAAU,GAGX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAkBvB;;GAEG;AACH,MAAM,qBAAqB,GAA2B;IACpD,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;IACV,UAAU,EAAE,YAAY;CACzB,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"RateLimitRouteHandler.js","sourceRoot":"","sources":["../../src/helpers/RateLimitRouteHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,12 @@ export interface RevenueCatHelperConfig {
|
|
|
34
34
|
export declare class RevenueCatHelper {
|
|
35
35
|
private readonly apiKey;
|
|
36
36
|
private readonly baseUrl;
|
|
37
|
+
/**
|
|
38
|
+
* Create a new RevenueCatHelper.
|
|
39
|
+
*
|
|
40
|
+
* @param config - Configuration containing the API key and optional base URL.
|
|
41
|
+
* The API key should be a RevenueCat secret key suitable for server-side use.
|
|
42
|
+
*/
|
|
37
43
|
constructor(config: RevenueCatHelperConfig);
|
|
38
44
|
/**
|
|
39
45
|
* Get active entitlement names for a user.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevenueCatHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/RevenueCatHelper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"RevenueCatHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/RevenueCatHelper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;;;;OAKG;gBACS,MAAM,EAAE,sBAAsB;IAK1C;;;;;;;OAOG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAKpB;;;;;;;OAOG;IACG,mBAAmB,CACvB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,gBAAgB,CAAC;CAwE7B"}
|
|
@@ -23,6 +23,12 @@ import { NONE_ENTITLEMENT } from "@sudobility/types";
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
export class RevenueCatHelper {
|
|
26
|
+
/**
|
|
27
|
+
* Create a new RevenueCatHelper.
|
|
28
|
+
*
|
|
29
|
+
* @param config - Configuration containing the API key and optional base URL.
|
|
30
|
+
* The API key should be a RevenueCat secret key suitable for server-side use.
|
|
31
|
+
*/
|
|
26
32
|
constructor(config) {
|
|
27
33
|
this.apiKey = config.apiKey;
|
|
28
34
|
this.baseUrl = config.baseUrl ?? "https://api.revenuecat.com/v1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevenueCatHelper.js","sourceRoot":"","sources":["../../src/helpers/RevenueCatHelper.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RevenueCatHelper.js","sourceRoot":"","sources":["../../src/helpers/RevenueCatHelper.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,11 +25,24 @@ export interface RateLimitMiddlewareConfig {
|
|
|
25
25
|
* Create a Hono middleware for rate limiting based on RevenueCat entitlements.
|
|
26
26
|
*
|
|
27
27
|
* This middleware:
|
|
28
|
-
* 1.
|
|
29
|
-
* 2.
|
|
30
|
-
* 3.
|
|
31
|
-
* 4.
|
|
32
|
-
* 5.
|
|
28
|
+
* 1. Optionally skips rate limiting via the `shouldSkip` callback
|
|
29
|
+
* 2. Extracts the user ID via the `getUserId` callback
|
|
30
|
+
* 3. Fetches user's subscription info from RevenueCat (falls back to "none" on error)
|
|
31
|
+
* 4. Resolves rate limits based on entitlements using the most permissive limits
|
|
32
|
+
* 5. Checks and increments counters in the database
|
|
33
|
+
* 6. Sets `X-RateLimit-Hourly-Remaining`, `X-RateLimit-Daily-Remaining`,
|
|
34
|
+
* and `X-RateLimit-Monthly-Remaining` response headers
|
|
35
|
+
* 7. Returns 429 JSON response if rate limit exceeded, otherwise calls `next()`
|
|
36
|
+
*
|
|
37
|
+
* @param config - Middleware configuration options
|
|
38
|
+
* @param config.revenueCatApiKey - RevenueCat secret API key for server-side use
|
|
39
|
+
* @param config.rateLimitsConfig - Mapping of entitlement names to rate limits (must include "none")
|
|
40
|
+
* @param config.db - Drizzle PostgresJs database instance
|
|
41
|
+
* @param config.rateLimitsTable - The rate_limit_counters Drizzle table reference
|
|
42
|
+
* @param config.getUserId - Function to extract user ID from Hono context (sync or async)
|
|
43
|
+
* @param config.shouldSkip - Optional function to skip rate limiting (e.g., for admin tokens)
|
|
44
|
+
* @param config.getTestMode - Optional function to determine if sandbox purchases should be accepted
|
|
45
|
+
* @returns A Hono middleware function `(c: Context, next: Next) => Promise<Response | void>`
|
|
33
46
|
*
|
|
34
47
|
* @example
|
|
35
48
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,+CAA+C;IAC/C,SAAS,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,mHAAmH;IACnH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AAED
|
|
1
|
+
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gCAAgC;IAChC,EAAE,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,qDAAqD;IACrD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,+CAA+C;IAC/C,SAAS,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,mHAAmH;IACnH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,IAQ3D,GAAG,OAAO,EAAE,MAAM,IAAI;;;;;;;;;;;8BA+ErC"}
|
package/dist/middleware/hono.js
CHANGED
|
@@ -6,11 +6,24 @@ import { NONE_ENTITLEMENT } from "@sudobility/types";
|
|
|
6
6
|
* Create a Hono middleware for rate limiting based on RevenueCat entitlements.
|
|
7
7
|
*
|
|
8
8
|
* This middleware:
|
|
9
|
-
* 1.
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
12
|
-
* 4.
|
|
13
|
-
* 5.
|
|
9
|
+
* 1. Optionally skips rate limiting via the `shouldSkip` callback
|
|
10
|
+
* 2. Extracts the user ID via the `getUserId` callback
|
|
11
|
+
* 3. Fetches user's subscription info from RevenueCat (falls back to "none" on error)
|
|
12
|
+
* 4. Resolves rate limits based on entitlements using the most permissive limits
|
|
13
|
+
* 5. Checks and increments counters in the database
|
|
14
|
+
* 6. Sets `X-RateLimit-Hourly-Remaining`, `X-RateLimit-Daily-Remaining`,
|
|
15
|
+
* and `X-RateLimit-Monthly-Remaining` response headers
|
|
16
|
+
* 7. Returns 429 JSON response if rate limit exceeded, otherwise calls `next()`
|
|
17
|
+
*
|
|
18
|
+
* @param config - Middleware configuration options
|
|
19
|
+
* @param config.revenueCatApiKey - RevenueCat secret API key for server-side use
|
|
20
|
+
* @param config.rateLimitsConfig - Mapping of entitlement names to rate limits (must include "none")
|
|
21
|
+
* @param config.db - Drizzle PostgresJs database instance
|
|
22
|
+
* @param config.rateLimitsTable - The rate_limit_counters Drizzle table reference
|
|
23
|
+
* @param config.getUserId - Function to extract user ID from Hono context (sync or async)
|
|
24
|
+
* @param config.shouldSkip - Optional function to skip rate limiting (e.g., for admin tokens)
|
|
25
|
+
* @param config.getTestMode - Optional function to determine if sandbox purchases should be accepted
|
|
26
|
+
* @returns A Hono middleware function `(c: Context, next: Next) => Promise<Response | void>`
|
|
14
27
|
*
|
|
15
28
|
* @example
|
|
16
29
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAuBrD
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/time.d.ts
CHANGED
|
@@ -9,32 +9,68 @@
|
|
|
9
9
|
*/
|
|
10
10
|
/**
|
|
11
11
|
* Get the start of the current hour in UTC.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* Truncates minutes, seconds, and milliseconds to zero.
|
|
14
|
+
*
|
|
15
|
+
* @param now - Reference date (defaults to current time)
|
|
16
|
+
* @returns Date object representing the top of the current hour in UTC
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* getCurrentHourStart(new Date("2025-06-15T14:35:22Z"))
|
|
20
|
+
* // Returns: 2025-06-15T14:00:00.000Z
|
|
21
|
+
* ```
|
|
13
22
|
*/
|
|
14
23
|
export declare function getCurrentHourStart(now?: Date): Date;
|
|
15
24
|
/**
|
|
16
25
|
* Get the start of the next hour in UTC.
|
|
17
|
-
*
|
|
26
|
+
*
|
|
27
|
+
* @param now - Reference date (defaults to current time)
|
|
28
|
+
* @returns Date object representing the top of the next hour in UTC
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* getNextHourStart(new Date("2025-06-15T14:35:22Z"))
|
|
32
|
+
* // Returns: 2025-06-15T15:00:00.000Z
|
|
33
|
+
* ```
|
|
18
34
|
*/
|
|
19
35
|
export declare function getNextHourStart(now?: Date): Date;
|
|
20
36
|
/**
|
|
21
37
|
* Get the next hour reset timestamp.
|
|
22
|
-
*
|
|
38
|
+
*
|
|
39
|
+
* @param now - Reference date (defaults to current time)
|
|
40
|
+
* @returns Date object representing the next hour boundary
|
|
41
|
+
* @deprecated Use {@link getNextHourStart} instead
|
|
23
42
|
*/
|
|
24
43
|
export declare function getNextHourReset(now?: Date): Date;
|
|
25
44
|
/**
|
|
26
45
|
* Get the start of the current day in UTC (midnight).
|
|
27
|
-
*
|
|
46
|
+
*
|
|
47
|
+
* @param now - Reference date (defaults to current time)
|
|
48
|
+
* @returns Date object representing midnight UTC of the current day
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* getCurrentDayStart(new Date("2025-01-15T14:35:22Z"))
|
|
52
|
+
* // Returns: 2025-01-15T00:00:00.000Z
|
|
53
|
+
* ```
|
|
28
54
|
*/
|
|
29
55
|
export declare function getCurrentDayStart(now?: Date): Date;
|
|
30
56
|
/**
|
|
31
57
|
* Get the start of the next day in UTC (midnight).
|
|
32
|
-
*
|
|
58
|
+
*
|
|
59
|
+
* @param now - Reference date (defaults to current time)
|
|
60
|
+
* @returns Date object representing midnight UTC of the next day
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* getNextDayStart(new Date("2025-01-15T14:35:22Z"))
|
|
64
|
+
* // Returns: 2025-01-16T00:00:00.000Z
|
|
65
|
+
* ```
|
|
33
66
|
*/
|
|
34
67
|
export declare function getNextDayStart(now?: Date): Date;
|
|
35
68
|
/**
|
|
36
69
|
* Get the next day reset timestamp.
|
|
37
|
-
*
|
|
70
|
+
*
|
|
71
|
+
* @param now - Reference date (defaults to current time)
|
|
72
|
+
* @returns Date object representing the next day boundary
|
|
73
|
+
* @deprecated Use {@link getNextDayStart} instead
|
|
38
74
|
*/
|
|
39
75
|
export declare function getNextDayReset(now?: Date): Date;
|
|
40
76
|
/**
|
|
@@ -70,11 +106,30 @@ export declare function getSubscriptionMonthStart(subscriptionStartedAt: Date |
|
|
|
70
106
|
export declare function getNextSubscriptionMonthStart(subscriptionStartedAt: Date | null, now?: Date): Date;
|
|
71
107
|
/**
|
|
72
108
|
* Get the next month reset timestamp (calendar month).
|
|
73
|
-
*
|
|
109
|
+
*
|
|
110
|
+
* Returns the first day of the next calendar month at midnight UTC.
|
|
111
|
+
*
|
|
112
|
+
* @param now - Reference date (defaults to current time)
|
|
113
|
+
* @returns Date object representing the first day of the next calendar month
|
|
114
|
+
* @deprecated Use {@link getNextSubscriptionMonthStart} for subscription-based months
|
|
74
115
|
*/
|
|
75
116
|
export declare function getNextMonthReset(now?: Date): Date;
|
|
76
117
|
/**
|
|
77
118
|
* Get time until reset in human-readable format.
|
|
119
|
+
*
|
|
120
|
+
* Formats the duration between now and the reset timestamp into a compact
|
|
121
|
+
* human-readable string. Uses the largest meaningful units.
|
|
122
|
+
*
|
|
123
|
+
* @param resetAt - The reset timestamp
|
|
124
|
+
* @param now - Current time (defaults to `new Date()`)
|
|
125
|
+
* @returns Formatted string like "now", "30s", "45m", "2h 30m", or "3d 2h"
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const now = new Date("2025-06-15T12:00:00Z");
|
|
130
|
+
* getTimeUntilReset(new Date("2025-06-15T14:30:00Z"), now) // "2h 30m"
|
|
131
|
+
* getTimeUntilReset(new Date("2025-06-15T11:00:00Z"), now) // "now" (past)
|
|
132
|
+
* ```
|
|
78
133
|
*/
|
|
79
134
|
export declare function getTimeUntilReset(resetAt: Date, now?: Date): string;
|
|
80
135
|
//# sourceMappingURL=time.d.ts.map
|
package/dist/utils/time.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAYhE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAI7D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAE7D;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAY/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAI5D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAE5D;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,qBAAqB,EAAE,IAAI,GAAG,IAAI,EAClC,GAAG,GAAE,IAAiB,GACrB,IAAI,CAwCN;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,qBAAqB,EAAE,IAAI,GAAG,IAAI,EAClC,GAAG,GAAE,IAAiB,GACrB,IAAI,CAsCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,IAAiB,GAAG,IAAI,CAI9D;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,EACb,GAAG,GAAE,IAAiB,GACrB,MAAM,CAcR"}
|
package/dist/utils/time.js
CHANGED
|
@@ -12,14 +12,30 @@
|
|
|
12
12
|
// ============================================================================
|
|
13
13
|
/**
|
|
14
14
|
* Get the start of the current hour in UTC.
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* Truncates minutes, seconds, and milliseconds to zero.
|
|
17
|
+
*
|
|
18
|
+
* @param now - Reference date (defaults to current time)
|
|
19
|
+
* @returns Date object representing the top of the current hour in UTC
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* getCurrentHourStart(new Date("2025-06-15T14:35:22Z"))
|
|
23
|
+
* // Returns: 2025-06-15T14:00:00.000Z
|
|
24
|
+
* ```
|
|
16
25
|
*/
|
|
17
26
|
export function getCurrentHourStart(now = new Date()) {
|
|
18
27
|
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), 0, 0, 0));
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
21
30
|
* Get the start of the next hour in UTC.
|
|
22
|
-
*
|
|
31
|
+
*
|
|
32
|
+
* @param now - Reference date (defaults to current time)
|
|
33
|
+
* @returns Date object representing the top of the next hour in UTC
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* getNextHourStart(new Date("2025-06-15T14:35:22Z"))
|
|
37
|
+
* // Returns: 2025-06-15T15:00:00.000Z
|
|
38
|
+
* ```
|
|
23
39
|
*/
|
|
24
40
|
export function getNextHourStart(now = new Date()) {
|
|
25
41
|
const next = new Date(getCurrentHourStart(now));
|
|
@@ -28,7 +44,10 @@ export function getNextHourStart(now = new Date()) {
|
|
|
28
44
|
}
|
|
29
45
|
/**
|
|
30
46
|
* Get the next hour reset timestamp.
|
|
31
|
-
*
|
|
47
|
+
*
|
|
48
|
+
* @param now - Reference date (defaults to current time)
|
|
49
|
+
* @returns Date object representing the next hour boundary
|
|
50
|
+
* @deprecated Use {@link getNextHourStart} instead
|
|
32
51
|
*/
|
|
33
52
|
export function getNextHourReset(now = new Date()) {
|
|
34
53
|
return getNextHourStart(now);
|
|
@@ -38,14 +57,28 @@ export function getNextHourReset(now = new Date()) {
|
|
|
38
57
|
// ============================================================================
|
|
39
58
|
/**
|
|
40
59
|
* Get the start of the current day in UTC (midnight).
|
|
41
|
-
*
|
|
60
|
+
*
|
|
61
|
+
* @param now - Reference date (defaults to current time)
|
|
62
|
+
* @returns Date object representing midnight UTC of the current day
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* getCurrentDayStart(new Date("2025-01-15T14:35:22Z"))
|
|
66
|
+
* // Returns: 2025-01-15T00:00:00.000Z
|
|
67
|
+
* ```
|
|
42
68
|
*/
|
|
43
69
|
export function getCurrentDayStart(now = new Date()) {
|
|
44
70
|
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0, 0));
|
|
45
71
|
}
|
|
46
72
|
/**
|
|
47
73
|
* Get the start of the next day in UTC (midnight).
|
|
48
|
-
*
|
|
74
|
+
*
|
|
75
|
+
* @param now - Reference date (defaults to current time)
|
|
76
|
+
* @returns Date object representing midnight UTC of the next day
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* getNextDayStart(new Date("2025-01-15T14:35:22Z"))
|
|
80
|
+
* // Returns: 2025-01-16T00:00:00.000Z
|
|
81
|
+
* ```
|
|
49
82
|
*/
|
|
50
83
|
export function getNextDayStart(now = new Date()) {
|
|
51
84
|
const next = new Date(getCurrentDayStart(now));
|
|
@@ -54,7 +87,10 @@ export function getNextDayStart(now = new Date()) {
|
|
|
54
87
|
}
|
|
55
88
|
/**
|
|
56
89
|
* Get the next day reset timestamp.
|
|
57
|
-
*
|
|
90
|
+
*
|
|
91
|
+
* @param now - Reference date (defaults to current time)
|
|
92
|
+
* @returns Date object representing the next day boundary
|
|
93
|
+
* @deprecated Use {@link getNextDayStart} instead
|
|
58
94
|
*/
|
|
59
95
|
export function getNextDayReset(now = new Date()) {
|
|
60
96
|
return getNextDayStart(now);
|
|
@@ -138,7 +174,12 @@ export function getNextSubscriptionMonthStart(subscriptionStartedAt, now = new D
|
|
|
138
174
|
}
|
|
139
175
|
/**
|
|
140
176
|
* Get the next month reset timestamp (calendar month).
|
|
141
|
-
*
|
|
177
|
+
*
|
|
178
|
+
* Returns the first day of the next calendar month at midnight UTC.
|
|
179
|
+
*
|
|
180
|
+
* @param now - Reference date (defaults to current time)
|
|
181
|
+
* @returns Date object representing the first day of the next calendar month
|
|
182
|
+
* @deprecated Use {@link getNextSubscriptionMonthStart} for subscription-based months
|
|
142
183
|
*/
|
|
143
184
|
export function getNextMonthReset(now = new Date()) {
|
|
144
185
|
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0));
|
|
@@ -148,6 +189,20 @@ export function getNextMonthReset(now = new Date()) {
|
|
|
148
189
|
// ============================================================================
|
|
149
190
|
/**
|
|
150
191
|
* Get time until reset in human-readable format.
|
|
192
|
+
*
|
|
193
|
+
* Formats the duration between now and the reset timestamp into a compact
|
|
194
|
+
* human-readable string. Uses the largest meaningful units.
|
|
195
|
+
*
|
|
196
|
+
* @param resetAt - The reset timestamp
|
|
197
|
+
* @param now - Current time (defaults to `new Date()`)
|
|
198
|
+
* @returns Formatted string like "now", "30s", "45m", "2h 30m", or "3d 2h"
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* const now = new Date("2025-06-15T12:00:00Z");
|
|
203
|
+
* getTimeUntilReset(new Date("2025-06-15T14:30:00Z"), now) // "2h 30m"
|
|
204
|
+
* getTimeUntilReset(new Date("2025-06-15T11:00:00Z"), now) // "now" (past)
|
|
205
|
+
* ```
|
|
151
206
|
*/
|
|
152
207
|
export function getTimeUntilReset(resetAt, now = new Date()) {
|
|
153
208
|
const diffMs = resetAt.getTime() - now.getTime();
|
package/dist/utils/time.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E;AAE/E
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"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"}
|