@newyorkcompute/kalshi-core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/config.d.ts +61 -6
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +56 -5
  4. package/dist/config.js.map +1 -1
  5. package/dist/config.test.d.ts +2 -0
  6. package/dist/config.test.d.ts.map +1 -0
  7. package/dist/config.test.js +94 -0
  8. package/dist/config.test.js.map +1 -0
  9. package/dist/format.d.ts +71 -2
  10. package/dist/format.d.ts.map +1 -1
  11. package/dist/format.js +71 -2
  12. package/dist/format.js.map +1 -1
  13. package/dist/format.test.js +42 -1
  14. package/dist/format.test.js.map +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/mm/index.d.ts +10 -0
  20. package/dist/mm/index.d.ts.map +1 -0
  21. package/dist/mm/index.js +12 -0
  22. package/dist/mm/index.js.map +1 -0
  23. package/dist/mm/inventory.d.ts +70 -0
  24. package/dist/mm/inventory.d.ts.map +1 -0
  25. package/dist/mm/inventory.js +171 -0
  26. package/dist/mm/inventory.js.map +1 -0
  27. package/dist/mm/inventory.test.d.ts +2 -0
  28. package/dist/mm/inventory.test.d.ts.map +1 -0
  29. package/dist/mm/inventory.test.js +358 -0
  30. package/dist/mm/inventory.test.js.map +1 -0
  31. package/dist/mm/order-manager.d.ts +81 -0
  32. package/dist/mm/order-manager.d.ts.map +1 -0
  33. package/dist/mm/order-manager.js +216 -0
  34. package/dist/mm/order-manager.js.map +1 -0
  35. package/dist/mm/order-manager.test.d.ts +2 -0
  36. package/dist/mm/order-manager.test.d.ts.map +1 -0
  37. package/dist/mm/order-manager.test.js +333 -0
  38. package/dist/mm/order-manager.test.js.map +1 -0
  39. package/dist/mm/risk.d.ts +77 -0
  40. package/dist/mm/risk.d.ts.map +1 -0
  41. package/dist/mm/risk.js +179 -0
  42. package/dist/mm/risk.js.map +1 -0
  43. package/dist/mm/risk.test.d.ts +2 -0
  44. package/dist/mm/risk.test.d.ts.map +1 -0
  45. package/dist/mm/risk.test.js +297 -0
  46. package/dist/mm/risk.test.js.map +1 -0
  47. package/dist/mm/types.d.ts +128 -0
  48. package/dist/mm/types.d.ts.map +1 -0
  49. package/dist/mm/types.js +7 -0
  50. package/dist/mm/types.js.map +1 -0
  51. package/dist/websocket/auth.d.ts +35 -0
  52. package/dist/websocket/auth.d.ts.map +1 -0
  53. package/dist/websocket/auth.js +60 -0
  54. package/dist/websocket/auth.js.map +1 -0
  55. package/dist/websocket/auth.test.d.ts +2 -0
  56. package/dist/websocket/auth.test.d.ts.map +1 -0
  57. package/dist/websocket/auth.test.js +65 -0
  58. package/dist/websocket/auth.test.js.map +1 -0
  59. package/dist/websocket/client.d.ts +95 -0
  60. package/dist/websocket/client.d.ts.map +1 -0
  61. package/dist/websocket/client.js +358 -0
  62. package/dist/websocket/client.js.map +1 -0
  63. package/dist/websocket/index.d.ts +9 -0
  64. package/dist/websocket/index.d.ts.map +1 -0
  65. package/dist/websocket/index.js +9 -0
  66. package/dist/websocket/index.js.map +1 -0
  67. package/dist/websocket/types.d.ts +172 -0
  68. package/dist/websocket/types.d.ts.map +1 -0
  69. package/dist/websocket/types.js +12 -0
  70. package/dist/websocket/types.js.map +1 -0
  71. package/dist/websocket/types.test.d.ts +2 -0
  72. package/dist/websocket/types.test.d.ts.map +1 -0
  73. package/dist/websocket/types.test.js +17 -0
  74. package/dist/websocket/types.test.js.map +1 -0
  75. package/package.json +8 -4
package/dist/config.d.ts CHANGED
@@ -5,7 +5,11 @@
5
5
  */
6
6
  import { Configuration, MarketApi, PortfolioApi, OrdersApi, EventsApi } from "kalshi-typescript";
7
7
  /**
8
- * Kalshi API configuration
8
+ * Kalshi API configuration credentials
9
+ *
10
+ * @property apiKey - Kalshi API key ID
11
+ * @property privateKey - RSA private key in PEM format
12
+ * @property basePath - API base URL (production or demo)
9
13
  */
10
14
  export interface KalshiConfig {
11
15
  apiKey: string;
@@ -23,27 +27,78 @@ export declare const DEMO_BASE_PATH = "https://demo-api.kalshi.co/trade-api/v2";
23
27
  /**
24
28
  * Get Kalshi configuration from environment variables
25
29
  *
26
- * @throws Error if required environment variables are missing
30
+ * Reads from:
31
+ * - `KALSHI_API_KEY` - Required API key ID
32
+ * - `KALSHI_PRIVATE_KEY` - Required RSA private key (PEM format)
33
+ * - `KALSHI_BASE_PATH` - Optional base URL (defaults to production)
34
+ *
35
+ * @returns Kalshi configuration object
36
+ * @throws Error if KALSHI_API_KEY or KALSHI_PRIVATE_KEY is missing
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const config = getKalshiConfig();
41
+ * const marketApi = createMarketApi(config);
42
+ * ```
27
43
  */
28
44
  export declare function getKalshiConfig(): KalshiConfig;
29
45
  /**
30
46
  * Create a configured Kalshi SDK Configuration instance
47
+ *
48
+ * @param config - Kalshi API credentials
49
+ * @returns SDK Configuration instance for API clients
31
50
  */
32
51
  export declare function createSdkConfig(config: KalshiConfig): Configuration;
33
52
  /**
34
- * Create a MarketApi instance with the given configuration
53
+ * Create a MarketApi instance for market data operations
54
+ *
55
+ * @param config - Kalshi API credentials
56
+ * @returns Configured MarketApi client
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const api = createMarketApi(config);
61
+ * const markets = await api.getMarkets();
62
+ * ```
35
63
  */
36
64
  export declare function createMarketApi(config: KalshiConfig): MarketApi;
37
65
  /**
38
- * Create a PortfolioApi instance with the given configuration
66
+ * Create a PortfolioApi instance for portfolio operations
67
+ *
68
+ * @param config - Kalshi API credentials
69
+ * @returns Configured PortfolioApi client
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const api = createPortfolioApi(config);
74
+ * const balance = await api.getBalance();
75
+ * ```
39
76
  */
40
77
  export declare function createPortfolioApi(config: KalshiConfig): PortfolioApi;
41
78
  /**
42
- * Create an OrdersApi instance with the given configuration
79
+ * Create an OrdersApi instance for order management
80
+ *
81
+ * @param config - Kalshi API credentials
82
+ * @returns Configured OrdersApi client
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const api = createOrdersApi(config);
87
+ * const orders = await api.getOrders();
88
+ * ```
43
89
  */
44
90
  export declare function createOrdersApi(config: KalshiConfig): OrdersApi;
45
91
  /**
46
- * Create an EventsApi instance with the given configuration
92
+ * Create an EventsApi instance for event data operations
93
+ *
94
+ * @param config - Kalshi API credentials
95
+ * @returns Configured EventsApi client
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const api = createEventsApi(config);
100
+ * const events = await api.getEvents();
101
+ * ```
47
102
  */
48
103
  export declare function createEventsApi(config: KalshiConfig): EventsApi;
49
104
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,kDAAkD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,cAAc,4CAA4C,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAc9C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAMnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAGrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,mBAAmB,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,kDAAkD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,cAAc,4CAA4C,CAAC;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAc9C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAMnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAGrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAG/D"}
package/dist/config.js CHANGED
@@ -15,7 +15,19 @@ export const DEMO_BASE_PATH = "https://demo-api.kalshi.co/trade-api/v2";
15
15
  /**
16
16
  * Get Kalshi configuration from environment variables
17
17
  *
18
- * @throws Error if required environment variables are missing
18
+ * Reads from:
19
+ * - `KALSHI_API_KEY` - Required API key ID
20
+ * - `KALSHI_PRIVATE_KEY` - Required RSA private key (PEM format)
21
+ * - `KALSHI_BASE_PATH` - Optional base URL (defaults to production)
22
+ *
23
+ * @returns Kalshi configuration object
24
+ * @throws Error if KALSHI_API_KEY or KALSHI_PRIVATE_KEY is missing
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const config = getKalshiConfig();
29
+ * const marketApi = createMarketApi(config);
30
+ * ```
19
31
  */
20
32
  export function getKalshiConfig() {
21
33
  const apiKey = process.env.KALSHI_API_KEY;
@@ -31,6 +43,9 @@ export function getKalshiConfig() {
31
43
  }
32
44
  /**
33
45
  * Create a configured Kalshi SDK Configuration instance
46
+ *
47
+ * @param config - Kalshi API credentials
48
+ * @returns SDK Configuration instance for API clients
34
49
  */
35
50
  export function createSdkConfig(config) {
36
51
  return new Configuration({
@@ -40,28 +55,64 @@ export function createSdkConfig(config) {
40
55
  });
41
56
  }
42
57
  /**
43
- * Create a MarketApi instance with the given configuration
58
+ * Create a MarketApi instance for market data operations
59
+ *
60
+ * @param config - Kalshi API credentials
61
+ * @returns Configured MarketApi client
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const api = createMarketApi(config);
66
+ * const markets = await api.getMarkets();
67
+ * ```
44
68
  */
45
69
  export function createMarketApi(config) {
46
70
  const sdkConfig = createSdkConfig(config);
47
71
  return new MarketApi(sdkConfig);
48
72
  }
49
73
  /**
50
- * Create a PortfolioApi instance with the given configuration
74
+ * Create a PortfolioApi instance for portfolio operations
75
+ *
76
+ * @param config - Kalshi API credentials
77
+ * @returns Configured PortfolioApi client
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const api = createPortfolioApi(config);
82
+ * const balance = await api.getBalance();
83
+ * ```
51
84
  */
52
85
  export function createPortfolioApi(config) {
53
86
  const sdkConfig = createSdkConfig(config);
54
87
  return new PortfolioApi(sdkConfig);
55
88
  }
56
89
  /**
57
- * Create an OrdersApi instance with the given configuration
90
+ * Create an OrdersApi instance for order management
91
+ *
92
+ * @param config - Kalshi API credentials
93
+ * @returns Configured OrdersApi client
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const api = createOrdersApi(config);
98
+ * const orders = await api.getOrders();
99
+ * ```
58
100
  */
59
101
  export function createOrdersApi(config) {
60
102
  const sdkConfig = createSdkConfig(config);
61
103
  return new OrdersApi(sdkConfig);
62
104
  }
63
105
  /**
64
- * Create an EventsApi instance with the given configuration
106
+ * Create an EventsApi instance for event data operations
107
+ *
108
+ * @param config - Kalshi API credentials
109
+ * @returns Configured EventsApi client
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * const api = createEventsApi(config);
114
+ * const events = await api.getEvents();
115
+ * ```
65
116
  */
66
117
  export function createEventsApi(config) {
67
118
  const sdkConfig = createSdkConfig(config);
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,GACV,MAAM,mBAAmB,CAAC;AAW3B;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,+CAA+C,CAAC;AAEjF;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,yCAAyC,CAAC;AAExE;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,iBAAiB,CAAC;IAEnE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,OAAO,IAAI,aAAa,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,MAAM,CAAC,UAAU;QAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,GACV,MAAM,mBAAmB,CAAC;AAe3B;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,+CAA+C,CAAC;AAEjF;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,yCAAyC,CAAC;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,iBAAiB,CAAC;IAEnE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,OAAO,IAAI,aAAa,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,MAAM,CAAC,UAAU;QAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { getKalshiConfig, createSdkConfig, createMarketApi, createPortfolioApi, createOrdersApi, createEventsApi, DEFAULT_BASE_PATH, DEMO_BASE_PATH, } from "./config.js";
3
+ // Mock kalshi-typescript
4
+ vi.mock("kalshi-typescript", () => ({
5
+ Configuration: vi.fn().mockImplementation((config) => ({
6
+ apiKey: config.apiKey,
7
+ privateKeyPem: config.privateKeyPem,
8
+ basePath: config.basePath,
9
+ })),
10
+ MarketApi: vi.fn().mockImplementation(() => ({ name: "MarketApi" })),
11
+ PortfolioApi: vi.fn().mockImplementation(() => ({ name: "PortfolioApi" })),
12
+ OrdersApi: vi.fn().mockImplementation(() => ({ name: "OrdersApi" })),
13
+ EventsApi: vi.fn().mockImplementation(() => ({ name: "EventsApi" })),
14
+ }));
15
+ describe("constants", () => {
16
+ it("exports DEFAULT_BASE_PATH", () => {
17
+ expect(DEFAULT_BASE_PATH).toBe("https://api.elections.kalshi.com/trade-api/v2");
18
+ });
19
+ it("exports DEMO_BASE_PATH", () => {
20
+ expect(DEMO_BASE_PATH).toBe("https://demo-api.kalshi.co/trade-api/v2");
21
+ });
22
+ });
23
+ describe("getKalshiConfig", () => {
24
+ const originalEnv = process.env;
25
+ beforeEach(() => {
26
+ vi.resetModules();
27
+ process.env = { ...originalEnv };
28
+ });
29
+ afterEach(() => {
30
+ process.env = originalEnv;
31
+ });
32
+ it("returns config from environment variables", () => {
33
+ process.env.KALSHI_API_KEY = "test-api-key";
34
+ process.env.KALSHI_PRIVATE_KEY = "test-private-key";
35
+ const config = getKalshiConfig();
36
+ expect(config.apiKey).toBe("test-api-key");
37
+ expect(config.privateKey).toBe("test-private-key");
38
+ expect(config.basePath).toBe(DEFAULT_BASE_PATH);
39
+ });
40
+ it("uses custom base path from environment", () => {
41
+ process.env.KALSHI_API_KEY = "test-api-key";
42
+ process.env.KALSHI_PRIVATE_KEY = "test-private-key";
43
+ process.env.KALSHI_BASE_PATH = DEMO_BASE_PATH;
44
+ const config = getKalshiConfig();
45
+ expect(config.basePath).toBe(DEMO_BASE_PATH);
46
+ });
47
+ it("throws error if KALSHI_API_KEY is missing", () => {
48
+ delete process.env.KALSHI_API_KEY;
49
+ process.env.KALSHI_PRIVATE_KEY = "test-private-key";
50
+ expect(() => getKalshiConfig()).toThrow("KALSHI_API_KEY environment variable is required");
51
+ });
52
+ it("throws error if KALSHI_PRIVATE_KEY is missing", () => {
53
+ process.env.KALSHI_API_KEY = "test-api-key";
54
+ delete process.env.KALSHI_PRIVATE_KEY;
55
+ expect(() => getKalshiConfig()).toThrow("KALSHI_PRIVATE_KEY environment variable is required");
56
+ });
57
+ });
58
+ describe("createSdkConfig", () => {
59
+ it("creates Configuration with correct parameters", () => {
60
+ const config = {
61
+ apiKey: "test-api-key",
62
+ privateKey: "test-private-key",
63
+ basePath: DEFAULT_BASE_PATH,
64
+ };
65
+ const sdkConfig = createSdkConfig(config);
66
+ expect(sdkConfig.apiKey).toBe("test-api-key");
67
+ expect(sdkConfig.privateKeyPem).toBe("test-private-key");
68
+ expect(sdkConfig.basePath).toBe(DEFAULT_BASE_PATH);
69
+ });
70
+ });
71
+ describe("API factory functions", () => {
72
+ const testConfig = {
73
+ apiKey: "test-api-key",
74
+ privateKey: "test-private-key",
75
+ basePath: DEFAULT_BASE_PATH,
76
+ };
77
+ it("createMarketApi returns MarketApi instance", () => {
78
+ const api = createMarketApi(testConfig);
79
+ expect(api).toEqual({ name: "MarketApi" });
80
+ });
81
+ it("createPortfolioApi returns PortfolioApi instance", () => {
82
+ const api = createPortfolioApi(testConfig);
83
+ expect(api).toEqual({ name: "PortfolioApi" });
84
+ });
85
+ it("createOrdersApi returns OrdersApi instance", () => {
86
+ const api = createOrdersApi(testConfig);
87
+ expect(api).toEqual({ name: "OrdersApi" });
88
+ });
89
+ it("createEventsApi returns EventsApi instance", () => {
90
+ const api = createEventsApi(testConfig);
91
+ expect(api).toEqual({ name: "EventsApi" });
92
+ });
93
+ });
94
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,yBAAyB;AACzB,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACrD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;IACH,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACpE,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;IAC1E,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACpE,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;CACrE,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAEhC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,WAAW,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,GAAG,GAAG,WAAW,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAEpD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QAEjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,cAAc,CAAC;QAE9C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QAEjC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAEpD,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CACrC,iDAAiD,CAClD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;QAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAEtC,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CACrC,qDAAqD,CACtD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAG;YACb,MAAM,EAAE,cAAc;YACtB,UAAU,EAAE,kBAAkB;YAC9B,QAAQ,EAAE,iBAAiB;SAC5B,CAAC;QAEF,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACzD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,MAAM,UAAU,GAAG;QACjB,MAAM,EAAE,cAAc;QACtB,UAAU,EAAE,kBAAkB;QAC9B,QAAQ,EAAE,iBAAiB;KAC5B,CAAC;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,GAAG,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/format.d.ts CHANGED
@@ -5,22 +5,69 @@
5
5
  */
6
6
  /**
7
7
  * Format a price in cents to a display string (e.g., 45 -> "45¢")
8
+ *
9
+ * @param cents - Price in cents (0-100 for Kalshi markets)
10
+ * @returns Formatted price string with cent symbol, or "—" if null/undefined
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * formatPrice(45) // "45¢"
15
+ * formatPrice(null) // "—"
16
+ * ```
8
17
  */
9
18
  export declare function formatPrice(cents: number | undefined | null): string;
10
19
  /**
11
20
  * Format a price in cents to dollars (e.g., 4500 -> "$45.00")
21
+ *
22
+ * @param cents - Amount in cents
23
+ * @returns Formatted dollar string with currency symbol, or "—" if null/undefined
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * formatCurrency(4500) // "$45.00"
28
+ * formatCurrency(50) // "$0.50"
29
+ * ```
12
30
  */
13
31
  export declare function formatCurrency(cents: number | undefined | null): string;
14
32
  /**
15
33
  * Format a number as a percentage (e.g., 0.45 -> "45%")
34
+ *
35
+ * @param value - Decimal value between 0 and 1
36
+ * @returns Formatted percentage string, or "—" if null/undefined
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * formatPercent(0.45) // "45%"
41
+ * formatPercent(1.0) // "100%"
42
+ * ```
16
43
  */
17
44
  export declare function formatPercent(value: number | undefined | null): string;
18
45
  /**
19
- * Format a price change with indicator (e.g., 2 -> "▲ +2", -3 -> "▼ -3", 0 -> "━ 0")
46
+ * Format a price change with visual indicator
47
+ *
48
+ * @param change - Price change in cents (positive, negative, or zero)
49
+ * @returns Formatted string with arrow indicator
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * formatPriceChange(2) // "▲ +2"
54
+ * formatPriceChange(-3) // "▼ -3"
55
+ * formatPriceChange(0) // "━ 0"
56
+ * ```
20
57
  */
21
58
  export declare function formatPriceChange(change: number): string;
22
59
  /**
23
- * Format a large number with abbreviations (e.g., 1500000 -> "1.5M")
60
+ * Format a large number with K/M abbreviations
61
+ *
62
+ * @param value - Number to format
63
+ * @returns Compact string with K (thousands) or M (millions) suffix
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * formatCompactNumber(1500000) // "1.5M"
68
+ * formatCompactNumber(2500) // "2.5K"
69
+ * formatCompactNumber(500) // "500"
70
+ * ```
24
71
  */
25
72
  export declare function formatCompactNumber(value: number | undefined | null): string;
26
73
  /**
@@ -68,10 +115,32 @@ export declare function formatExpiry(closeTime?: string): string;
68
115
  export declare function calculateSpread(bestBid: number | null | undefined, bestAsk: number | null | undefined): number | null;
69
116
  /**
70
117
  * Truncate a string to a maximum length with ellipsis
118
+ *
119
+ * @param str - String to truncate
120
+ * @param maxLength - Maximum length including ellipsis
121
+ * @returns Truncated string with "…" if needed
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * truncate("Hello World", 8) // "Hello W…"
126
+ * truncate("Hi", 8) // "Hi"
127
+ * ```
71
128
  */
72
129
  export declare function truncate(str: string, maxLength: number): string;
73
130
  /**
74
131
  * Pad a string to a fixed width (left or right aligned)
132
+ *
133
+ * @param str - String to pad
134
+ * @param width - Target width
135
+ * @param align - Alignment direction ("left" adds padding right, "right" adds padding left)
136
+ * @returns Padded string, truncated if longer than width
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * padString("Hi", 5, "left") // "Hi "
141
+ * padString("Hi", 5, "right") // " Hi"
142
+ * padString("Hello World", 5) // "Hello"
143
+ * ```
75
144
  */
76
145
  export declare function padString(str: string, width: number, align?: "left" | "right"): string;
77
146
  //# sourceMappingURL=format.d.ts.map
@@ -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;;;;;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"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAMvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAKtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED;;;;;;;;;;;;GAYG;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;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;;;;;;;;;;;;GAcG;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
@@ -5,6 +5,15 @@
5
5
  */
6
6
  /**
7
7
  * Format a price in cents to a display string (e.g., 45 -> "45¢")
8
+ *
9
+ * @param cents - Price in cents (0-100 for Kalshi markets)
10
+ * @returns Formatted price string with cent symbol, or "—" if null/undefined
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * formatPrice(45) // "45¢"
15
+ * formatPrice(null) // "—"
16
+ * ```
8
17
  */
9
18
  export function formatPrice(cents) {
10
19
  if (cents === undefined || cents === null) {
@@ -14,6 +23,15 @@ export function formatPrice(cents) {
14
23
  }
15
24
  /**
16
25
  * Format a price in cents to dollars (e.g., 4500 -> "$45.00")
26
+ *
27
+ * @param cents - Amount in cents
28
+ * @returns Formatted dollar string with currency symbol, or "—" if null/undefined
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * formatCurrency(4500) // "$45.00"
33
+ * formatCurrency(50) // "$0.50"
34
+ * ```
17
35
  */
18
36
  export function formatCurrency(cents) {
19
37
  if (cents === undefined || cents === null) {
@@ -24,6 +42,15 @@ export function formatCurrency(cents) {
24
42
  }
25
43
  /**
26
44
  * Format a number as a percentage (e.g., 0.45 -> "45%")
45
+ *
46
+ * @param value - Decimal value between 0 and 1
47
+ * @returns Formatted percentage string, or "—" if null/undefined
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * formatPercent(0.45) // "45%"
52
+ * formatPercent(1.0) // "100%"
53
+ * ```
27
54
  */
28
55
  export function formatPercent(value) {
29
56
  if (value === undefined || value === null) {
@@ -32,7 +59,17 @@ export function formatPercent(value) {
32
59
  return `${Math.round(value * 100)}%`;
33
60
  }
34
61
  /**
35
- * Format a price change with indicator (e.g., 2 -> "▲ +2", -3 -> "▼ -3", 0 -> "━ 0")
62
+ * Format a price change with visual indicator
63
+ *
64
+ * @param change - Price change in cents (positive, negative, or zero)
65
+ * @returns Formatted string with arrow indicator
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * formatPriceChange(2) // "▲ +2"
70
+ * formatPriceChange(-3) // "▼ -3"
71
+ * formatPriceChange(0) // "━ 0"
72
+ * ```
36
73
  */
37
74
  export function formatPriceChange(change) {
38
75
  if (change > 0) {
@@ -44,7 +81,17 @@ export function formatPriceChange(change) {
44
81
  return "━ 0";
45
82
  }
46
83
  /**
47
- * Format a large number with abbreviations (e.g., 1500000 -> "1.5M")
84
+ * Format a large number with K/M abbreviations
85
+ *
86
+ * @param value - Number to format
87
+ * @returns Compact string with K (thousands) or M (millions) suffix
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * formatCompactNumber(1500000) // "1.5M"
92
+ * formatCompactNumber(2500) // "2.5K"
93
+ * formatCompactNumber(500) // "500"
94
+ * ```
48
95
  */
49
96
  export function formatCompactNumber(value) {
50
97
  if (value === undefined || value === null) {
@@ -165,6 +212,16 @@ export function calculateSpread(bestBid, bestAsk) {
165
212
  }
166
213
  /**
167
214
  * Truncate a string to a maximum length with ellipsis
215
+ *
216
+ * @param str - String to truncate
217
+ * @param maxLength - Maximum length including ellipsis
218
+ * @returns Truncated string with "…" if needed
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * truncate("Hello World", 8) // "Hello W…"
223
+ * truncate("Hi", 8) // "Hi"
224
+ * ```
168
225
  */
169
226
  export function truncate(str, maxLength) {
170
227
  if (str.length <= maxLength) {
@@ -174,6 +231,18 @@ export function truncate(str, maxLength) {
174
231
  }
175
232
  /**
176
233
  * Pad a string to a fixed width (left or right aligned)
234
+ *
235
+ * @param str - String to pad
236
+ * @param width - Target width
237
+ * @param align - Alignment direction ("left" adds padding right, "right" adds padding left)
238
+ * @returns Padded string, truncated if longer than width
239
+ *
240
+ * @example
241
+ * ```ts
242
+ * padString("Hi", 5, "left") // "Hi "
243
+ * padString("Hi", 5, "right") // " Hi"
244
+ * padString("Hello World", 5) // "Hello"
245
+ * ```
177
246
  */
178
247
  export function padString(str, width, align = "left") {
179
248
  if (str.length >= width) {
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatExpiry, calculateSpread, truncate, padString, } from "./format.js";
2
+ import { formatPrice, formatCurrency, formatPercent, formatPriceChange, formatCompactNumber, formatRelativeTime, 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,6 +87,47 @@ describe("padString", () => {
87
87
  expect(padString("Hello World", 5)).toBe("Hello");
88
88
  });
89
89
  });
90
+ describe("formatRelativeTime", () => {
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 'now' for current time", () => {
99
+ expect(formatRelativeTime('2025-06-15T12:00:00Z')).toBe('now');
100
+ expect(formatRelativeTime(new Date('2025-06-15T12:00:30Z'))).toBe('now');
101
+ });
102
+ it("formats past minutes", () => {
103
+ expect(formatRelativeTime('2025-06-15T11:30:00Z')).toBe('30m ago');
104
+ expect(formatRelativeTime('2025-06-15T11:45:00Z')).toBe('15m ago');
105
+ });
106
+ it("formats past hours", () => {
107
+ expect(formatRelativeTime('2025-06-15T09:00:00Z')).toBe('3h ago');
108
+ expect(formatRelativeTime('2025-06-15T06:00:00Z')).toBe('6h ago');
109
+ });
110
+ it("formats past days", () => {
111
+ expect(formatRelativeTime('2025-06-13T12:00:00Z')).toBe('2d ago');
112
+ expect(formatRelativeTime('2025-06-10T12:00:00Z')).toBe('5d ago');
113
+ });
114
+ it("formats future minutes", () => {
115
+ expect(formatRelativeTime('2025-06-15T12:30:00Z')).toBe('in 30m');
116
+ expect(formatRelativeTime('2025-06-15T12:15:00Z')).toBe('in 15m');
117
+ });
118
+ it("formats future hours", () => {
119
+ expect(formatRelativeTime('2025-06-15T15:00:00Z')).toBe('in 3h');
120
+ expect(formatRelativeTime('2025-06-15T18:00:00Z')).toBe('in 6h');
121
+ });
122
+ it("formats future days", () => {
123
+ expect(formatRelativeTime('2025-06-17T12:00:00Z')).toBe('in 2d');
124
+ expect(formatRelativeTime('2025-06-20T12:00:00Z')).toBe('in 5d');
125
+ });
126
+ it("accepts Date objects", () => {
127
+ expect(formatRelativeTime(new Date('2025-06-15T11:00:00Z'))).toBe('1h ago');
128
+ expect(formatRelativeTime(new Date('2025-06-16T12:00:00Z'))).toBe('in 1d');
129
+ });
130
+ });
90
131
  describe("formatExpiry", () => {
91
132
  beforeEach(() => {
92
133
  vi.useFakeTimers();