@newyorkcompute/kalshi-core 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ /**
2
+ * TTL Cache
3
+ *
4
+ * Lightweight in-memory cache with time-to-live expiration.
5
+ * Useful for caching API responses to reduce rate limiting.
6
+ */
7
+ /**
8
+ * Get cached data if not expired
9
+ *
10
+ * @param key - Cache key
11
+ * @param ttl - Time-to-live in milliseconds (default: 60s)
12
+ * @returns Cached data or null if expired/missing
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const data = getCached<Market[]>('markets', 30000);
17
+ * if (!data) {
18
+ * // Fetch fresh data
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function getCached<T>(key: string, ttl?: number): T | null;
23
+ /**
24
+ * Set cached data with current timestamp
25
+ *
26
+ * @param key - Cache key
27
+ * @param data - Data to cache
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * setCache('markets', marketData);
32
+ * ```
33
+ */
34
+ export declare function setCache<T>(key: string, data: T): void;
35
+ /**
36
+ * Clear specific cache entry
37
+ *
38
+ * @param key - Cache key to clear
39
+ */
40
+ export declare function clearCache(key: string): void;
41
+ /**
42
+ * Clear all cache entries
43
+ */
44
+ export declare function clearAllCache(): void;
45
+ /**
46
+ * Get cache statistics (for debugging)
47
+ *
48
+ * @returns Object with cache size and keys
49
+ */
50
+ export declare function getCacheStats(): {
51
+ size: number;
52
+ keys: string[];
53
+ };
54
+ /**
55
+ * Common TTL constants for Kalshi data
56
+ */
57
+ export declare const CACHE_TTL: {
58
+ /** 5 minutes - Trade history doesn't change rapidly */
59
+ readonly PRICE_HISTORY: number;
60
+ /** 10 minutes - Market titles/close times rarely change */
61
+ readonly MARKET_METADATA: number;
62
+ /** 1 minute - Events list */
63
+ readonly EVENTS: number;
64
+ /** No cache - Orderbook needs real-time data */
65
+ readonly ORDERBOOK: 0;
66
+ /** No cache - Balance needs real-time data */
67
+ readonly BALANCE: 0;
68
+ /** No cache - Positions need real-time data */
69
+ readonly POSITIONS: 0;
70
+ };
71
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAoB,GAAG,CAAC,GAAG,IAAI,CAY7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAKtD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKhE;AAED;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB,uDAAuD;;IAEvD,2DAA2D;;IAE3D,6BAA6B;;IAE7B,gDAAgD;;IAEhD,8CAA8C;;IAE9C,+CAA+C;;CAEvC,CAAC"}
package/dist/cache.js ADDED
@@ -0,0 +1,96 @@
1
+ /**
2
+ * TTL Cache
3
+ *
4
+ * Lightweight in-memory cache with time-to-live expiration.
5
+ * Useful for caching API responses to reduce rate limiting.
6
+ */
7
+ // Cache storage
8
+ const cache = new Map();
9
+ // Default TTL: 1 minute
10
+ const DEFAULT_TTL = 60 * 1000;
11
+ /**
12
+ * Get cached data if not expired
13
+ *
14
+ * @param key - Cache key
15
+ * @param ttl - Time-to-live in milliseconds (default: 60s)
16
+ * @returns Cached data or null if expired/missing
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const data = getCached<Market[]>('markets', 30000);
21
+ * if (!data) {
22
+ * // Fetch fresh data
23
+ * }
24
+ * ```
25
+ */
26
+ export function getCached(key, ttl = DEFAULT_TTL) {
27
+ const entry = cache.get(key);
28
+ if (!entry)
29
+ return null;
30
+ const isExpired = Date.now() - entry.timestamp > ttl;
31
+ if (isExpired) {
32
+ cache.delete(key);
33
+ return null;
34
+ }
35
+ return entry.data;
36
+ }
37
+ /**
38
+ * Set cached data with current timestamp
39
+ *
40
+ * @param key - Cache key
41
+ * @param data - Data to cache
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * setCache('markets', marketData);
46
+ * ```
47
+ */
48
+ export function setCache(key, data) {
49
+ cache.set(key, {
50
+ data,
51
+ timestamp: Date.now(),
52
+ });
53
+ }
54
+ /**
55
+ * Clear specific cache entry
56
+ *
57
+ * @param key - Cache key to clear
58
+ */
59
+ export function clearCache(key) {
60
+ cache.delete(key);
61
+ }
62
+ /**
63
+ * Clear all cache entries
64
+ */
65
+ export function clearAllCache() {
66
+ cache.clear();
67
+ }
68
+ /**
69
+ * Get cache statistics (for debugging)
70
+ *
71
+ * @returns Object with cache size and keys
72
+ */
73
+ export function getCacheStats() {
74
+ return {
75
+ size: cache.size,
76
+ keys: Array.from(cache.keys()),
77
+ };
78
+ }
79
+ /**
80
+ * Common TTL constants for Kalshi data
81
+ */
82
+ export const CACHE_TTL = {
83
+ /** 5 minutes - Trade history doesn't change rapidly */
84
+ PRICE_HISTORY: 5 * 60 * 1000,
85
+ /** 10 minutes - Market titles/close times rarely change */
86
+ MARKET_METADATA: 10 * 60 * 1000,
87
+ /** 1 minute - Events list */
88
+ EVENTS: 60 * 1000,
89
+ /** No cache - Orderbook needs real-time data */
90
+ ORDERBOOK: 0,
91
+ /** No cache - Balance needs real-time data */
92
+ BALANCE: 0,
93
+ /** No cache - Positions need real-time data */
94
+ POSITIONS: 0,
95
+ };
96
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,gBAAgB;AAChB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;AAErD,wBAAwB;AACxB,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI,CAAC;AAE9B;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAI,GAAW,EAAE,MAAc,WAAW;IACjE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE7B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;IACrD,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,IAAS,CAAC;AACzB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,QAAQ,CAAI,GAAW,EAAE,IAAO;IAC9C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;QACb,IAAI;QACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,uDAAuD;IACvD,aAAa,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAC5B,2DAA2D;IAC3D,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAC/B,6BAA6B;IAC7B,MAAM,EAAE,EAAE,GAAG,IAAI;IACjB,gDAAgD;IAChD,SAAS,EAAE,CAAC;IACZ,8CAA8C;IAC9C,OAAO,EAAE,CAAC;IACV,+CAA+C;IAC/C,SAAS,EAAE,CAAC;CACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Cache Tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../src/cache.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Cache Tests
3
+ */
4
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
5
+ import { getCached, setCache, clearCache, clearAllCache, getCacheStats, CACHE_TTL, } from './cache.js';
6
+ describe('cache', () => {
7
+ beforeEach(() => {
8
+ clearAllCache();
9
+ vi.useFakeTimers();
10
+ });
11
+ afterEach(() => {
12
+ vi.useRealTimers();
13
+ });
14
+ describe('setCache and getCached', () => {
15
+ it('should store and retrieve data', () => {
16
+ const data = { ticker: 'KXBTC', price: 50 };
17
+ setCache('market-1', data);
18
+ const result = getCached('market-1');
19
+ expect(result).toEqual(data);
20
+ });
21
+ it('should return null for non-existent key', () => {
22
+ const result = getCached('non-existent');
23
+ expect(result).toBeNull();
24
+ });
25
+ it('should return null after TTL expires', () => {
26
+ const data = { value: 42 };
27
+ setCache('test-key', data);
28
+ // Advance time past default TTL (60s)
29
+ vi.advanceTimersByTime(61 * 1000);
30
+ const result = getCached('test-key');
31
+ expect(result).toBeNull();
32
+ });
33
+ it('should return data before TTL expires', () => {
34
+ const data = { value: 42 };
35
+ setCache('test-key', data);
36
+ // Advance time but stay within TTL
37
+ vi.advanceTimersByTime(30 * 1000);
38
+ const result = getCached('test-key');
39
+ expect(result).toEqual(data);
40
+ });
41
+ it('should respect custom TTL', () => {
42
+ const data = { value: 'test' };
43
+ const customTTL = 5000; // 5 seconds
44
+ setCache('custom-ttl', data);
45
+ // Still valid at 4 seconds
46
+ vi.advanceTimersByTime(4000);
47
+ expect(getCached('custom-ttl', customTTL)).toEqual(data);
48
+ // Expired at 6 seconds
49
+ vi.advanceTimersByTime(2000);
50
+ expect(getCached('custom-ttl', customTTL)).toBeNull();
51
+ });
52
+ it('should overwrite existing cache entry', () => {
53
+ setCache('key', { v: 1 });
54
+ setCache('key', { v: 2 });
55
+ const result = getCached('key');
56
+ expect(result).toEqual({ v: 2 });
57
+ });
58
+ });
59
+ describe('clearCache', () => {
60
+ it('should clear specific cache entry', () => {
61
+ setCache('key1', 'value1');
62
+ setCache('key2', 'value2');
63
+ clearCache('key1');
64
+ expect(getCached('key1')).toBeNull();
65
+ expect(getCached('key2')).toBe('value2');
66
+ });
67
+ it('should handle clearing non-existent key', () => {
68
+ expect(() => clearCache('non-existent')).not.toThrow();
69
+ });
70
+ });
71
+ describe('clearAllCache', () => {
72
+ it('should clear all cache entries', () => {
73
+ setCache('key1', 'value1');
74
+ setCache('key2', 'value2');
75
+ setCache('key3', 'value3');
76
+ clearAllCache();
77
+ expect(getCached('key1')).toBeNull();
78
+ expect(getCached('key2')).toBeNull();
79
+ expect(getCached('key3')).toBeNull();
80
+ });
81
+ });
82
+ describe('getCacheStats', () => {
83
+ it('should return cache statistics', () => {
84
+ setCache('key1', 'value1');
85
+ setCache('key2', 'value2');
86
+ const stats = getCacheStats();
87
+ expect(stats.size).toBe(2);
88
+ expect(stats.keys).toContain('key1');
89
+ expect(stats.keys).toContain('key2');
90
+ });
91
+ it('should return empty stats for empty cache', () => {
92
+ const stats = getCacheStats();
93
+ expect(stats.size).toBe(0);
94
+ expect(stats.keys).toEqual([]);
95
+ });
96
+ });
97
+ describe('CACHE_TTL constants', () => {
98
+ it('should have expected TTL values', () => {
99
+ expect(CACHE_TTL.PRICE_HISTORY).toBe(5 * 60 * 1000);
100
+ expect(CACHE_TTL.MARKET_METADATA).toBe(10 * 60 * 1000);
101
+ expect(CACHE_TTL.EVENTS).toBe(60 * 1000);
102
+ expect(CACHE_TTL.ORDERBOOK).toBe(0);
103
+ expect(CACHE_TTL.BALANCE).toBe(0);
104
+ expect(CACHE_TTL.POSITIONS).toBe(0);
105
+ });
106
+ });
107
+ });
108
+ //# sourceMappingURL=cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../src/cache.test.ts"],"names":[],"mappings":"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"}
package/dist/format.d.ts CHANGED
@@ -25,8 +25,47 @@ export declare function formatPriceChange(change: number): string;
25
25
  export declare function formatCompactNumber(value: number | undefined | null): string;
26
26
  /**
27
27
  * Format a timestamp to a relative time string
28
+ *
29
+ * @param timestamp - Date string or Date object
30
+ * @returns Relative time string (e.g., "2d ago", "in 3h")
28
31
  */
29
32
  export declare function formatRelativeTime(timestamp: string | Date): string;
33
+ /**
34
+ * Format market close time as expiry string
35
+ *
36
+ * Handles various time ranges:
37
+ * - Minutes: "45m"
38
+ * - Hours: "3h 45m"
39
+ * - Days: "2d 14h" or "45d" (for >30 days)
40
+ * - Years: "2y 3mo" or "2y"
41
+ * - Very distant (>10y): "distant"
42
+ * - Past: "CLOSED"
43
+ *
44
+ * @param closeTime - ISO date string for market close time
45
+ * @returns Formatted expiry string
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * formatExpiry('2025-12-31T23:59:59Z') // "1y 2mo"
50
+ * formatExpiry('2099-01-01T00:00:00Z') // "distant"
51
+ * formatExpiry('2024-01-01T00:00:00Z') // "CLOSED" (if past)
52
+ * ```
53
+ */
54
+ export declare function formatExpiry(closeTime?: string): string;
55
+ /**
56
+ * Calculate spread between best bid and best ask
57
+ *
58
+ * @param bestBid - Best (highest) bid price
59
+ * @param bestAsk - Best (lowest) ask price
60
+ * @returns Spread in cents, or null if either price is missing
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * calculateSpread(48, 52) // 4
65
+ * calculateSpread(null, 52) // null
66
+ * ```
67
+ */
68
+ export declare function calculateSpread(bestBid: number | null | undefined, bestAsk: number | null | undefined): number | null;
30
69
  /**
31
70
  * Truncate a string to a maximum length with ellipsis
32
71
  */
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAMvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKtE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAY5E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAuBnE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAM,GAAG,OAAgB,GAC/B,MAAM,CAMR"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAMvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKtE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAY5E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAuBnE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CA4CvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC,MAAM,GAAG,IAAI,CAGf;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAM,GAAG,OAAgB,GAC/B,MAAM,CAMR"}
package/dist/format.js CHANGED
@@ -60,6 +60,9 @@ export function formatCompactNumber(value) {
60
60
  }
61
61
  /**
62
62
  * Format a timestamp to a relative time string
63
+ *
64
+ * @param timestamp - Date string or Date object
65
+ * @returns Relative time string (e.g., "2d ago", "in 3h")
63
66
  */
64
67
  export function formatRelativeTime(timestamp) {
65
68
  const date = typeof timestamp === "string" ? new Date(timestamp) : timestamp;
@@ -83,6 +86,83 @@ export function formatRelativeTime(timestamp) {
83
86
  }
84
87
  return "now";
85
88
  }
89
+ /**
90
+ * Format market close time as expiry string
91
+ *
92
+ * Handles various time ranges:
93
+ * - Minutes: "45m"
94
+ * - Hours: "3h 45m"
95
+ * - Days: "2d 14h" or "45d" (for >30 days)
96
+ * - Years: "2y 3mo" or "2y"
97
+ * - Very distant (>10y): "distant"
98
+ * - Past: "CLOSED"
99
+ *
100
+ * @param closeTime - ISO date string for market close time
101
+ * @returns Formatted expiry string
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * formatExpiry('2025-12-31T23:59:59Z') // "1y 2mo"
106
+ * formatExpiry('2099-01-01T00:00:00Z') // "distant"
107
+ * formatExpiry('2024-01-01T00:00:00Z') // "CLOSED" (if past)
108
+ * ```
109
+ */
110
+ export function formatExpiry(closeTime) {
111
+ if (!closeTime)
112
+ return '';
113
+ const now = new Date();
114
+ const close = new Date(closeTime);
115
+ const diffMs = close.getTime() - now.getTime();
116
+ if (diffMs <= 0)
117
+ return 'CLOSED';
118
+ const diffMins = Math.floor(diffMs / (1000 * 60));
119
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
120
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
121
+ const diffYears = Math.floor(diffDays / 365);
122
+ // For very distant dates, show "distant"
123
+ if (diffYears > 10) {
124
+ return 'distant';
125
+ }
126
+ // For dates > 1 year, show years and months
127
+ if (diffYears >= 1) {
128
+ const remainingMonths = Math.floor((diffDays % 365) / 30);
129
+ return remainingMonths > 0 ? `${diffYears}y ${remainingMonths}mo` : `${diffYears}y`;
130
+ }
131
+ // For dates > 30 days, show just days
132
+ if (diffDays > 30) {
133
+ return `${diffDays}d`;
134
+ }
135
+ // For dates with days remaining, show days and hours
136
+ if (diffDays > 0) {
137
+ const remainingHours = diffHours % 24;
138
+ return `${diffDays}d ${remainingHours}h`;
139
+ }
140
+ // For dates with hours remaining, show hours and minutes
141
+ if (diffHours > 0) {
142
+ const remainingMins = diffMins % 60;
143
+ return `${diffHours}h ${remainingMins}m`;
144
+ }
145
+ // Just minutes
146
+ return `${diffMins}m`;
147
+ }
148
+ /**
149
+ * Calculate spread between best bid and best ask
150
+ *
151
+ * @param bestBid - Best (highest) bid price
152
+ * @param bestAsk - Best (lowest) ask price
153
+ * @returns Spread in cents, or null if either price is missing
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * calculateSpread(48, 52) // 4
158
+ * calculateSpread(null, 52) // null
159
+ * ```
160
+ */
161
+ export function calculateSpread(bestBid, bestAsk) {
162
+ if (bestBid == null || bestAsk == null)
163
+ return null;
164
+ return bestAsk - bestBid;
165
+ }
86
166
  /**
87
167
  * Truncate a string to a maximum length with ellipsis
88
168
  */
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAgC;IAC1D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,KAAK,GAAG,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgC;IAC7D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,GAAG,GAAG,CAAC;IAC5B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgC;IAC5D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,OAAO,MAAM,MAAM,EAAE,CAAC;IACxB,CAAC;SAAM,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,MAAM,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAgC;IAClE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9C,CAAC;IACD,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;QACnB,OAAO,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAwB;IACzD,MAAM,IAAI,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAEnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,OAAO,GAAG,MAAM,GAAG,QAAQ,IAAI,MAAM,EAAE,CAAC;IAC1C,CAAC;IACD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO,GAAG,MAAM,GAAG,SAAS,IAAI,MAAM,EAAE,CAAC;IAC3C,CAAC;IACD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,OAAO,GAAG,MAAM,GAAG,QAAQ,IAAI,MAAM,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,SAAiB;IACrD,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,GAAW,EACX,KAAa,EACb,QAA0B,MAAM;IAEhC,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { describe, it, expect } from "vitest";
2
- import { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, truncate, padString, } from "./format.js";
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatExpiry, calculateSpread, truncate, padString, } from "./format.js";
3
3
  describe("formatPrice", () => {
4
4
  it("formats cents with cent symbol", () => {
5
5
  expect(formatPrice(45)).toBe("45¢");
@@ -87,4 +87,68 @@ describe("padString", () => {
87
87
  expect(padString("Hello World", 5)).toBe("Hello");
88
88
  });
89
89
  });
90
+ describe("formatExpiry", () => {
91
+ beforeEach(() => {
92
+ vi.useFakeTimers();
93
+ vi.setSystemTime(new Date('2025-06-15T12:00:00Z'));
94
+ });
95
+ afterEach(() => {
96
+ vi.useRealTimers();
97
+ });
98
+ it("returns empty string for undefined", () => {
99
+ expect(formatExpiry(undefined)).toBe('');
100
+ });
101
+ it("returns CLOSED for past dates", () => {
102
+ expect(formatExpiry('2025-06-14T12:00:00Z')).toBe('CLOSED');
103
+ expect(formatExpiry('2020-01-01T00:00:00Z')).toBe('CLOSED');
104
+ });
105
+ it("formats minutes", () => {
106
+ expect(formatExpiry('2025-06-15T12:30:00Z')).toBe('30m');
107
+ expect(formatExpiry('2025-06-15T12:45:00Z')).toBe('45m');
108
+ });
109
+ it("formats hours and minutes", () => {
110
+ expect(formatExpiry('2025-06-15T15:30:00Z')).toBe('3h 30m');
111
+ expect(formatExpiry('2025-06-15T20:00:00Z')).toBe('8h 0m');
112
+ });
113
+ it("formats days and hours", () => {
114
+ expect(formatExpiry('2025-06-17T12:00:00Z')).toBe('2d 0h');
115
+ expect(formatExpiry('2025-06-20T18:00:00Z')).toBe('5d 6h');
116
+ });
117
+ it("formats just days for >30 days", () => {
118
+ expect(formatExpiry('2025-08-15T12:00:00Z')).toBe('61d');
119
+ expect(formatExpiry('2025-10-15T12:00:00Z')).toBe('122d');
120
+ });
121
+ it("formats years and months", () => {
122
+ expect(formatExpiry('2026-06-15T12:00:00Z')).toBe('1y');
123
+ expect(formatExpiry('2027-09-15T12:00:00Z')).toBe('2y 3mo');
124
+ });
125
+ it("returns distant for >10 years", () => {
126
+ expect(formatExpiry('2036-06-15T12:00:00Z')).toBe('distant');
127
+ expect(formatExpiry('2099-01-01T00:00:00Z')).toBe('distant');
128
+ });
129
+ });
130
+ describe("calculateSpread", () => {
131
+ it("calculates spread correctly", () => {
132
+ expect(calculateSpread(48, 52)).toBe(4);
133
+ expect(calculateSpread(45, 55)).toBe(10);
134
+ expect(calculateSpread(50, 51)).toBe(1);
135
+ });
136
+ it("returns null for null bid", () => {
137
+ expect(calculateSpread(null, 52)).toBeNull();
138
+ });
139
+ it("returns null for null ask", () => {
140
+ expect(calculateSpread(48, null)).toBeNull();
141
+ });
142
+ it("returns null for undefined values", () => {
143
+ expect(calculateSpread(undefined, 52)).toBeNull();
144
+ expect(calculateSpread(48, undefined)).toBeNull();
145
+ expect(calculateSpread(undefined, undefined)).toBeNull();
146
+ });
147
+ it("handles zero spread", () => {
148
+ expect(calculateSpread(50, 50)).toBe(0);
149
+ });
150
+ it("handles negative spread (crossed market)", () => {
151
+ expect(calculateSpread(52, 48)).toBe(-4);
152
+ });
153
+ });
90
154
  //# sourceMappingURL=format.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.test.js","sourceRoot":"","sources":["../src/format.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.test.js","sourceRoot":"","sources":["../src/format.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,9 @@
4
4
  * Shared utilities for Kalshi prediction market tools.
5
5
  */
6
6
  export { type KalshiConfig, DEFAULT_BASE_PATH, DEMO_BASE_PATH, getKalshiConfig, createSdkConfig, createMarketApi, createPortfolioApi, createOrdersApi, createEventsApi, } from "./config.js";
7
- export { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatRelativeTime, truncate, padString, } from "./format.js";
7
+ export { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatRelativeTime, formatExpiry, calculateSpread, truncate, padString, } from "./format.js";
8
+ export { getCached, setCache, clearCache, clearAllCache, getCacheStats, CACHE_TTL, } from "./cache.js";
9
+ export { createRateLimiter, isRateLimitError, type RateLimiter, type RateLimiterConfig, type RateLimiterState, } from "./rate-limiter.js";
8
10
  export * from "./types.js";
9
11
  export { withTimeout, TimeoutError } from "./with-timeout.js";
10
12
  export { validateOrder, type OrderValidationInput, type OrderValidationResult, } from "./validate-order.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,KAAK,YAAY,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACV,MAAM,aAAa,CAAC;AAGrB,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,KAAK,YAAY,EACjB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,SAAS,GACV,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,aAAa,EACb,aAAa,EACb,SAAS,GACV,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,mBAAmB,CAAC;AAG3B,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -6,7 +6,11 @@
6
6
  // Configuration
7
7
  export { DEFAULT_BASE_PATH, DEMO_BASE_PATH, getKalshiConfig, createSdkConfig, createMarketApi, createPortfolioApi, createOrdersApi, createEventsApi, } from "./config.js";
8
8
  // Formatting utilities
9
- export { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatRelativeTime, truncate, padString, } from "./format.js";
9
+ export { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatRelativeTime, formatExpiry, calculateSpread, truncate, padString, } from "./format.js";
10
+ // Cache utilities
11
+ export { getCached, setCache, clearCache, clearAllCache, getCacheStats, CACHE_TTL, } from "./cache.js";
12
+ // Rate limiting
13
+ export { createRateLimiter, isRateLimitError, } from "./rate-limiter.js";
10
14
  // Types
11
15
  export * from "./types.js";
12
16
  // Utilities
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gBAAgB;AAChB,OAAO,EAEL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,uBAAuB;AACvB,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,YAAY;AACZ,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9D,aAAa;AACb,OAAO,EACL,aAAa,GAGd,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gBAAgB;AAChB,OAAO,EAEL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,uBAAuB;AACvB,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,kBAAkB;AAClB,OAAO,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,aAAa,EACb,aAAa,EACb,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,gBAAgB;AAChB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,mBAAmB,CAAC;AAE3B,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,YAAY;AACZ,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9D,aAAa;AACb,OAAO,EACL,aAAa,GAGd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Rate Limiter
3
+ *
4
+ * Implements exponential backoff and circuit breaker patterns
5
+ * for handling API rate limits gracefully.
6
+ */
7
+ export interface RateLimiterConfig {
8
+ /** Minimum interval between requests in ms (default: 1000) */
9
+ minInterval: number;
10
+ /** Maximum interval between requests in ms (default: 60000) */
11
+ maxInterval: number;
12
+ /** Multiplier for exponential backoff (default: 2) */
13
+ backoffMultiplier: number;
14
+ /** Number of consecutive failures before circuit opens (default: 5) */
15
+ circuitBreakerThreshold: number;
16
+ /** Time to wait before attempting to close circuit in ms (default: 30000) */
17
+ circuitResetTimeout: number;
18
+ }
19
+ export interface RateLimiterState {
20
+ /** Current interval between requests */
21
+ currentInterval: number;
22
+ /** Number of consecutive failures */
23
+ consecutiveFailures: number;
24
+ /** Whether the circuit breaker is open (blocking requests) */
25
+ isCircuitOpen: boolean;
26
+ /** Whether rate limiting is active */
27
+ isRateLimited: boolean;
28
+ /** Timestamp of last successful request */
29
+ lastSuccessTime: number;
30
+ /** Timestamp of last failure */
31
+ lastFailureTime: number;
32
+ }
33
+ /**
34
+ * Create a rate limiter instance
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const limiter = createRateLimiter();
39
+ *
40
+ * async function fetchData() {
41
+ * if (limiter.shouldBlock()) {
42
+ * return; // Skip request
43
+ * }
44
+ *
45
+ * try {
46
+ * const data = await api.getData();
47
+ * limiter.recordSuccess();
48
+ * return data;
49
+ * } catch (err) {
50
+ * if (isRateLimitError(err)) {
51
+ * limiter.recordRateLimitError();
52
+ * } else {
53
+ * limiter.recordFailure();
54
+ * }
55
+ * throw err;
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ export declare function createRateLimiter(config?: Partial<RateLimiterConfig>): {
61
+ shouldBlock: () => boolean;
62
+ getCurrentInterval: () => number;
63
+ getState: () => Readonly<RateLimiterState>;
64
+ recordSuccess: () => void;
65
+ recordRateLimitError: () => void;
66
+ recordFailure: () => void;
67
+ reset: () => void;
68
+ };
69
+ /**
70
+ * Type for the rate limiter instance
71
+ */
72
+ export type RateLimiter = ReturnType<typeof createRateLimiter>;
73
+ /**
74
+ * Check if an error is a rate limit error (HTTP 429)
75
+ *
76
+ * @param error - Error to check
77
+ * @returns true if the error is a rate limit error
78
+ */
79
+ export declare function isRateLimitError(error: unknown): boolean;
80
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,uBAAuB,EAAE,MAAM,CAAC;IAChC,6EAA6E;IAC7E,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,eAAe,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,aAAa,EAAE,OAAO,CAAC;IACvB,sCAAsC;IACtC,aAAa,EAAE,OAAO,CAAC;IACvB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC;CACzB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,iBAAiB,CAAM;uBAiB/C,OAAO;8BAOA,MAAM;oBAOhB,QAAQ,CAAC,gBAAgB,CAAC;yBAOrB,IAAI;gCAmBG,IAAI;yBAoBX,IAAI;iBA8BZ,IAAI;EAyBvB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAmBxD"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Rate Limiter
3
+ *
4
+ * Implements exponential backoff and circuit breaker patterns
5
+ * for handling API rate limits gracefully.
6
+ */
7
+ const DEFAULT_CONFIG = {
8
+ minInterval: 1000,
9
+ maxInterval: 60000,
10
+ backoffMultiplier: 2,
11
+ circuitBreakerThreshold: 5,
12
+ circuitResetTimeout: 30000,
13
+ };
14
+ /**
15
+ * Create a rate limiter instance
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const limiter = createRateLimiter();
20
+ *
21
+ * async function fetchData() {
22
+ * if (limiter.shouldBlock()) {
23
+ * return; // Skip request
24
+ * }
25
+ *
26
+ * try {
27
+ * const data = await api.getData();
28
+ * limiter.recordSuccess();
29
+ * return data;
30
+ * } catch (err) {
31
+ * if (isRateLimitError(err)) {
32
+ * limiter.recordRateLimitError();
33
+ * } else {
34
+ * limiter.recordFailure();
35
+ * }
36
+ * throw err;
37
+ * }
38
+ * }
39
+ * ```
40
+ */
41
+ export function createRateLimiter(config = {}) {
42
+ const cfg = { ...DEFAULT_CONFIG, ...config };
43
+ let state = {
44
+ currentInterval: cfg.minInterval,
45
+ consecutiveFailures: 0,
46
+ isCircuitOpen: false,
47
+ isRateLimited: false,
48
+ lastSuccessTime: 0,
49
+ lastFailureTime: 0,
50
+ };
51
+ let circuitResetTimer = null;
52
+ /**
53
+ * Check if requests should be blocked
54
+ */
55
+ function shouldBlock() {
56
+ return state.isCircuitOpen;
57
+ }
58
+ /**
59
+ * Get the current recommended interval between requests
60
+ */
61
+ function getCurrentInterval() {
62
+ return state.currentInterval;
63
+ }
64
+ /**
65
+ * Get the current state (for debugging/display)
66
+ */
67
+ function getState() {
68
+ return { ...state };
69
+ }
70
+ /**
71
+ * Record a successful request - resets backoff
72
+ */
73
+ function recordSuccess() {
74
+ state.consecutiveFailures = 0;
75
+ state.currentInterval = cfg.minInterval;
76
+ state.isRateLimited = false;
77
+ state.lastSuccessTime = Date.now();
78
+ // Close circuit if it was open
79
+ if (state.isCircuitOpen) {
80
+ state.isCircuitOpen = false;
81
+ if (circuitResetTimer) {
82
+ clearTimeout(circuitResetTimer);
83
+ circuitResetTimer = null;
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * Record a rate limit error (429) - applies exponential backoff
89
+ */
90
+ function recordRateLimitError() {
91
+ state.consecutiveFailures++;
92
+ state.isRateLimited = true;
93
+ state.lastFailureTime = Date.now();
94
+ // Apply exponential backoff
95
+ state.currentInterval = Math.min(state.currentInterval * cfg.backoffMultiplier, cfg.maxInterval);
96
+ // Open circuit if threshold reached
97
+ if (state.consecutiveFailures >= cfg.circuitBreakerThreshold) {
98
+ openCircuit();
99
+ }
100
+ }
101
+ /**
102
+ * Record a general failure (not rate limit)
103
+ */
104
+ function recordFailure() {
105
+ state.consecutiveFailures++;
106
+ state.lastFailureTime = Date.now();
107
+ // Open circuit if threshold reached
108
+ if (state.consecutiveFailures >= cfg.circuitBreakerThreshold) {
109
+ openCircuit();
110
+ }
111
+ }
112
+ /**
113
+ * Open the circuit breaker (block all requests temporarily)
114
+ */
115
+ function openCircuit() {
116
+ if (state.isCircuitOpen)
117
+ return;
118
+ state.isCircuitOpen = true;
119
+ // Schedule circuit reset
120
+ circuitResetTimer = setTimeout(() => {
121
+ state.isCircuitOpen = false;
122
+ state.consecutiveFailures = 0;
123
+ state.currentInterval = cfg.minInterval;
124
+ circuitResetTimer = null;
125
+ }, cfg.circuitResetTimeout);
126
+ }
127
+ /**
128
+ * Reset the rate limiter to initial state
129
+ */
130
+ function reset() {
131
+ if (circuitResetTimer) {
132
+ clearTimeout(circuitResetTimer);
133
+ circuitResetTimer = null;
134
+ }
135
+ state = {
136
+ currentInterval: cfg.minInterval,
137
+ consecutiveFailures: 0,
138
+ isCircuitOpen: false,
139
+ isRateLimited: false,
140
+ lastSuccessTime: 0,
141
+ lastFailureTime: 0,
142
+ };
143
+ }
144
+ return {
145
+ shouldBlock,
146
+ getCurrentInterval,
147
+ getState,
148
+ recordSuccess,
149
+ recordRateLimitError,
150
+ recordFailure,
151
+ reset,
152
+ };
153
+ }
154
+ /**
155
+ * Check if an error is a rate limit error (HTTP 429)
156
+ *
157
+ * @param error - Error to check
158
+ * @returns true if the error is a rate limit error
159
+ */
160
+ export function isRateLimitError(error) {
161
+ if (!error || typeof error !== 'object')
162
+ return false;
163
+ // Check for status code 429
164
+ if ('status' in error && error.status === 429)
165
+ return true;
166
+ if ('response' in error) {
167
+ const response = error.response;
168
+ if (response?.status === 429)
169
+ return true;
170
+ }
171
+ // Check error message
172
+ if ('message' in error && typeof error.message === 'string') {
173
+ const msg = error.message.toLowerCase();
174
+ if (msg.includes('429') || msg.includes('rate limit') || msg.includes('too many requests')) {
175
+ return true;
176
+ }
177
+ }
178
+ return false;
179
+ }
180
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Rate Limiter Tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=rate-limiter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.test.d.ts","sourceRoot":"","sources":["../src/rate-limiter.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Rate Limiter Tests
3
+ */
4
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
5
+ import { createRateLimiter, isRateLimitError, } from './rate-limiter.js';
6
+ describe('createRateLimiter', () => {
7
+ beforeEach(() => {
8
+ vi.useFakeTimers();
9
+ });
10
+ afterEach(() => {
11
+ vi.useRealTimers();
12
+ });
13
+ describe('initial state', () => {
14
+ it('should not block requests initially', () => {
15
+ const limiter = createRateLimiter();
16
+ expect(limiter.shouldBlock()).toBe(false);
17
+ });
18
+ it('should have minimum interval initially', () => {
19
+ const limiter = createRateLimiter({ minInterval: 1000 });
20
+ expect(limiter.getCurrentInterval()).toBe(1000);
21
+ });
22
+ it('should have correct initial state', () => {
23
+ const limiter = createRateLimiter();
24
+ const state = limiter.getState();
25
+ expect(state.consecutiveFailures).toBe(0);
26
+ expect(state.isCircuitOpen).toBe(false);
27
+ expect(state.isRateLimited).toBe(false);
28
+ });
29
+ });
30
+ describe('recordSuccess', () => {
31
+ it('should reset consecutive failures', () => {
32
+ const limiter = createRateLimiter();
33
+ limiter.recordFailure();
34
+ limiter.recordFailure();
35
+ expect(limiter.getState().consecutiveFailures).toBe(2);
36
+ limiter.recordSuccess();
37
+ expect(limiter.getState().consecutiveFailures).toBe(0);
38
+ });
39
+ it('should reset interval to minimum', () => {
40
+ const limiter = createRateLimiter({ minInterval: 1000 });
41
+ limiter.recordRateLimitError();
42
+ expect(limiter.getCurrentInterval()).toBeGreaterThan(1000);
43
+ limiter.recordSuccess();
44
+ expect(limiter.getCurrentInterval()).toBe(1000);
45
+ });
46
+ it('should clear rate limited flag', () => {
47
+ const limiter = createRateLimiter();
48
+ limiter.recordRateLimitError();
49
+ expect(limiter.getState().isRateLimited).toBe(true);
50
+ limiter.recordSuccess();
51
+ expect(limiter.getState().isRateLimited).toBe(false);
52
+ });
53
+ });
54
+ describe('recordRateLimitError', () => {
55
+ it('should increase interval with exponential backoff', () => {
56
+ const limiter = createRateLimiter({
57
+ minInterval: 1000,
58
+ backoffMultiplier: 2,
59
+ });
60
+ limiter.recordRateLimitError();
61
+ expect(limiter.getCurrentInterval()).toBe(2000);
62
+ limiter.recordRateLimitError();
63
+ expect(limiter.getCurrentInterval()).toBe(4000);
64
+ limiter.recordRateLimitError();
65
+ expect(limiter.getCurrentInterval()).toBe(8000);
66
+ });
67
+ it('should not exceed max interval', () => {
68
+ const limiter = createRateLimiter({
69
+ minInterval: 1000,
70
+ maxInterval: 5000,
71
+ backoffMultiplier: 2,
72
+ });
73
+ // 1000 -> 2000 -> 4000 -> 5000 (capped)
74
+ limiter.recordRateLimitError();
75
+ limiter.recordRateLimitError();
76
+ limiter.recordRateLimitError();
77
+ limiter.recordRateLimitError();
78
+ expect(limiter.getCurrentInterval()).toBe(5000);
79
+ });
80
+ it('should set rate limited flag', () => {
81
+ const limiter = createRateLimiter();
82
+ limiter.recordRateLimitError();
83
+ expect(limiter.getState().isRateLimited).toBe(true);
84
+ });
85
+ it('should increment consecutive failures', () => {
86
+ const limiter = createRateLimiter();
87
+ limiter.recordRateLimitError();
88
+ expect(limiter.getState().consecutiveFailures).toBe(1);
89
+ limiter.recordRateLimitError();
90
+ expect(limiter.getState().consecutiveFailures).toBe(2);
91
+ });
92
+ });
93
+ describe('circuit breaker', () => {
94
+ it('should open circuit after threshold failures', () => {
95
+ const limiter = createRateLimiter({
96
+ circuitBreakerThreshold: 3,
97
+ });
98
+ limiter.recordFailure();
99
+ limiter.recordFailure();
100
+ expect(limiter.shouldBlock()).toBe(false);
101
+ limiter.recordFailure();
102
+ expect(limiter.shouldBlock()).toBe(true);
103
+ });
104
+ it('should reset circuit after timeout', () => {
105
+ const limiter = createRateLimiter({
106
+ circuitBreakerThreshold: 2,
107
+ circuitResetTimeout: 5000,
108
+ });
109
+ limiter.recordFailure();
110
+ limiter.recordFailure();
111
+ expect(limiter.shouldBlock()).toBe(true);
112
+ // Advance time past reset timeout
113
+ vi.advanceTimersByTime(5001);
114
+ expect(limiter.shouldBlock()).toBe(false);
115
+ expect(limiter.getState().consecutiveFailures).toBe(0);
116
+ });
117
+ it('should close circuit on success', () => {
118
+ const limiter = createRateLimiter({
119
+ circuitBreakerThreshold: 2,
120
+ });
121
+ limiter.recordFailure();
122
+ limiter.recordFailure();
123
+ expect(limiter.shouldBlock()).toBe(true);
124
+ limiter.recordSuccess();
125
+ expect(limiter.shouldBlock()).toBe(false);
126
+ });
127
+ });
128
+ describe('reset', () => {
129
+ it('should reset all state', () => {
130
+ const limiter = createRateLimiter({
131
+ minInterval: 1000,
132
+ circuitBreakerThreshold: 2,
133
+ });
134
+ limiter.recordRateLimitError();
135
+ limiter.recordRateLimitError();
136
+ expect(limiter.shouldBlock()).toBe(true);
137
+ expect(limiter.getCurrentInterval()).toBeGreaterThan(1000);
138
+ limiter.reset();
139
+ expect(limiter.shouldBlock()).toBe(false);
140
+ expect(limiter.getCurrentInterval()).toBe(1000);
141
+ expect(limiter.getState().consecutiveFailures).toBe(0);
142
+ expect(limiter.getState().isRateLimited).toBe(false);
143
+ });
144
+ });
145
+ });
146
+ describe('isRateLimitError', () => {
147
+ it('should return true for error with status 429', () => {
148
+ expect(isRateLimitError({ status: 429 })).toBe(true);
149
+ });
150
+ it('should return true for error with response.status 429', () => {
151
+ expect(isRateLimitError({ response: { status: 429 } })).toBe(true);
152
+ });
153
+ it('should return true for error message containing 429', () => {
154
+ expect(isRateLimitError({ message: 'Error 429: Too Many Requests' })).toBe(true);
155
+ });
156
+ it('should return true for error message containing rate limit', () => {
157
+ expect(isRateLimitError({ message: 'Rate limit exceeded' })).toBe(true);
158
+ });
159
+ it('should return true for error message containing too many requests', () => {
160
+ expect(isRateLimitError({ message: 'too many requests' })).toBe(true);
161
+ });
162
+ it('should return false for other errors', () => {
163
+ expect(isRateLimitError({ status: 500 })).toBe(false);
164
+ expect(isRateLimitError({ message: 'Internal server error' })).toBe(false);
165
+ });
166
+ it('should return false for null/undefined', () => {
167
+ expect(isRateLimitError(null)).toBe(false);
168
+ expect(isRateLimitError(undefined)).toBe(false);
169
+ });
170
+ it('should return false for non-objects', () => {
171
+ expect(isRateLimitError('error')).toBe(false);
172
+ expect(isRateLimitError(123)).toBe(false);
173
+ });
174
+ });
175
+ //# sourceMappingURL=rate-limiter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.test.js","sourceRoot":"","sources":["../src/rate-limiter.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newyorkcompute/kalshi-core",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Shared utilities for Kalshi prediction market tools — SDK configuration, formatting, and types",
5
5
  "author": "NewYorkCompute",
6
6
  "license": "MIT",