@jsnw/kalshi-client 0.0.1

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/index.mjs ADDED
@@ -0,0 +1,652 @@
1
+ import { constants, createSign } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { v4 } from "uuid";
4
+ import { WebSocket } from "ws";
5
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
6
+ //#region src/request-signer.ts
7
+ var RequestSigner = class {
8
+ privkey;
9
+ /**
10
+ * @param {RequestSignerOptions} options
11
+ */
12
+ constructor(options) {
13
+ this.privkey = options.privateKey;
14
+ }
15
+ /**
16
+ * @param {SignatureParameters} params
17
+ * @return {string}
18
+ */
19
+ getSignature({ timestamp, httpMethod, path }) {
20
+ const text = `${(timestamp instanceof Date ? timestamp.getTime() : timestamp).toString()}${httpMethod.toUpperCase()}${path.split("?")[0].replace(/\/+$/, "")}`;
21
+ const sign = createSign("RSA-SHA256");
22
+ sign.update(text);
23
+ sign.end();
24
+ return sign.sign({
25
+ key: this.privkey,
26
+ padding: constants.RSA_PKCS1_PSS_PADDING,
27
+ saltLength: constants.RSA_PSS_SALTLEN_DIGEST
28
+ }).toString("base64");
29
+ }
30
+ };
31
+ //#endregion
32
+ //#region src/credentials-provider.ts
33
+ var InMemoryCredentialsProvider = class {
34
+ accessKey;
35
+ privateKey;
36
+ signer;
37
+ /**
38
+ * @param {InMemoryCredentialsProviderOptions} options
39
+ */
40
+ constructor(options) {
41
+ this.accessKey = options.accessKey;
42
+ this.privateKey = options.privateKey;
43
+ this.signer = new RequestSigner({ privateKey: this.privateKey });
44
+ }
45
+ /**
46
+ * @param {string} accessKey
47
+ */
48
+ setAccessKey(accessKey) {
49
+ if (this.accessKey === accessKey) return;
50
+ this.accessKey = accessKey;
51
+ }
52
+ /**
53
+ * @param {string} privateKey
54
+ */
55
+ setPrivateKey(privateKey) {
56
+ if (this.privateKey === privateKey) return;
57
+ this.privateKey = privateKey;
58
+ this.signer = new RequestSigner({ privateKey });
59
+ }
60
+ /**
61
+ * @return {string}
62
+ */
63
+ getAccessKey() {
64
+ return this.accessKey;
65
+ }
66
+ /**
67
+ * @param {SignatureParameters} options
68
+ * @return {string}
69
+ */
70
+ getSignature(options) {
71
+ return this.signer.getSignature(options);
72
+ }
73
+ };
74
+ //#endregion
75
+ //#region src/schemas/primitives.ts
76
+ const primitives$fixedPointSchema = z.string().regex(/^\d{1,14}\.\d{2,8}$/);
77
+ const primitives$orderSideSchema = z.enum(["yes", "no"]);
78
+ const primitives$bookSideSchema = z.enum(["bid", "ask"]);
79
+ const primitives$orderActionSchema = z.enum(["buy", "sell"]);
80
+ //#endregion
81
+ //#region src/schemas/orders.ts
82
+ const orders$orderStatusSchema = z.enum([
83
+ "resting",
84
+ "canceled",
85
+ "executed"
86
+ ]);
87
+ const orders$orderTypeSchema = z.enum(["limit", "market"]);
88
+ const orders$selfTradePreventionTypeSchema = z.enum(["taker_at_cross", "maker"]);
89
+ const orders$orderDetailedSchema = z.object({
90
+ order_id: z.uuid(),
91
+ user_id: z.uuid(),
92
+ subaccount_number: z.number().min(0).max(32).default(0),
93
+ order_group_id: z.uuid().nullable().optional(),
94
+ exchange_index: z.number().min(0).default(0),
95
+ client_order_id: z.string(),
96
+ ticker: z.string(),
97
+ outcome_side: primitives$orderSideSchema,
98
+ book_side: primitives$bookSideSchema,
99
+ type: orders$orderTypeSchema,
100
+ status: orders$orderStatusSchema,
101
+ yes_price_dollars: primitives$fixedPointSchema,
102
+ no_price_dollars: primitives$fixedPointSchema,
103
+ fill_count_fp: primitives$fixedPointSchema,
104
+ remaining_count_fp: primitives$fixedPointSchema,
105
+ initial_count_fp: primitives$fixedPointSchema,
106
+ taker_fill_cost_dollars: primitives$fixedPointSchema,
107
+ maker_fill_cost_dollars: primitives$fixedPointSchema,
108
+ taker_fees_dollars: primitives$fixedPointSchema,
109
+ maker_fees_dollars: primitives$fixedPointSchema,
110
+ self_trade_prevention_type: orders$selfTradePreventionTypeSchema.nullable().optional(),
111
+ cancel_order_on_pause: z.boolean(),
112
+ created_time: z.iso.datetime(),
113
+ expiration_time: z.iso.datetime().nullable().optional(),
114
+ last_update_time: z.iso.datetime().nullable().optional()
115
+ });
116
+ const orders$orderWsSchema = orders$orderDetailedSchema.omit({
117
+ exchange_index: true,
118
+ type: true,
119
+ no_price_dollars: true,
120
+ cancel_order_on_pause: true
121
+ }).extend({
122
+ side: primitives$orderSideSchema,
123
+ created_ts_ms: z.number().positive(),
124
+ last_updated_ts_ms: z.number().positive().optional(),
125
+ expiration_ts_ms: z.number().positive().optional()
126
+ });
127
+ //#endregion
128
+ //#region src/consts.ts
129
+ const KALSHI_WS_URL = {
130
+ "development": "wss://external-api-ws.demo.kalshi.co",
131
+ "production": "wss://external-api-ws.kalshi.com"
132
+ };
133
+ //#endregion
134
+ //#region src/typed-emitter.ts
135
+ var TypedEmitter = class {
136
+ listeners = /* @__PURE__ */ new Map();
137
+ wrappers = /* @__PURE__ */ new WeakMap();
138
+ on(event, listener) {
139
+ if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
140
+ this.listeners.get(event).add(listener);
141
+ }
142
+ once(event, listener) {
143
+ const wrapper = (...args) => {
144
+ listener(...args);
145
+ this.off(event, listener);
146
+ };
147
+ this.wrappers.set(listener, wrapper);
148
+ this.on(event, wrapper);
149
+ }
150
+ off(event, listener) {
151
+ const originalFn = this.wrappers.get(listener) || listener;
152
+ this.listeners.get(event)?.delete(originalFn);
153
+ this.wrappers.delete(listener);
154
+ }
155
+ emit(event, ...args) {
156
+ this.listeners.get(event)?.forEach((fn) => fn(...args));
157
+ }
158
+ removeListeners(event) {
159
+ this.listeners.delete(event);
160
+ }
161
+ removeAllListeners() {
162
+ this.listeners.clear();
163
+ }
164
+ listenersCount(event) {
165
+ if (event !== void 0) return this.listeners.get(event)?.size || 0;
166
+ let acc = 0;
167
+ for (const set of this.listeners.values()) acc += set.size;
168
+ return acc;
169
+ }
170
+ };
171
+ //#endregion
172
+ //#region src/defer.ts
173
+ /**
174
+ * @template T
175
+ * @return {DeferredPromise<T>}
176
+ */
177
+ function defer() {
178
+ let resolve, reject;
179
+ return {
180
+ promise: new Promise((res, rej) => {
181
+ resolve = res;
182
+ reject = rej;
183
+ }),
184
+ resolve,
185
+ reject
186
+ };
187
+ }
188
+ //#endregion
189
+ //#region src/ws-wrapper/errors.ts
190
+ var WsWrapperError = class extends Error {};
191
+ var NotConnectedError = class extends WsWrapperError {};
192
+ var InvalidStateError = class extends WsWrapperError {};
193
+ //#endregion
194
+ //#region src/random-int.ts
195
+ /**
196
+ * Generates a random integer between min (inclusive) and max (inclusive)
197
+ * @param {number} min - The minimum value (inclusive)
198
+ * @param {number} max - The maximum value (inclusive)
199
+ * @returns {number} A random integer between min and max
200
+ */
201
+ function randomInt(min, max) {
202
+ return Math.floor(Math.random() * (max - min + 1)) + min;
203
+ }
204
+ //#endregion
205
+ //#region src/ws-wrapper/ws-wrapper.ts
206
+ var WsWrapper = class extends TypedEmitter {
207
+ wsAddress;
208
+ agent;
209
+ connectHeaders;
210
+ reconnectStrategy;
211
+ state = "idle";
212
+ openDefer = null;
213
+ closeDefer = null;
214
+ reconnectAbort = null;
215
+ ws = null;
216
+ closeRequested = false;
217
+ reconnectAttempt = 0;
218
+ lastError = null;
219
+ /**
220
+ * @param {WsWrapperOptions} options
221
+ */
222
+ constructor(options) {
223
+ super();
224
+ this.wsAddress = options.address;
225
+ this.agent = options.agent;
226
+ this.connectHeaders = options.headers;
227
+ this.reconnectStrategy = options.reconnect;
228
+ }
229
+ /**
230
+ * @return {Promise<void>}
231
+ */
232
+ open() {
233
+ switch (this.state) {
234
+ case "idle":
235
+ this.state = "connecting";
236
+ this.openDefer = defer();
237
+ this.createWs();
238
+ return this.openDefer.promise;
239
+ case "connecting":
240
+ case "reconnecting": return this.openDefer.promise;
241
+ case "connected": return Promise.resolve();
242
+ case "closing": return Promise.reject(/* @__PURE__ */ new Error("Cannot reopen WS connection while it's still closing"));
243
+ default:
244
+ const _exhaustive = this.state;
245
+ throw new Error(`Unreachable: ${_exhaustive}`);
246
+ }
247
+ }
248
+ /**
249
+ * @param {BufferLike} data
250
+ * @return {Promise<void>}
251
+ */
252
+ send(data) {
253
+ return new Promise((resolve, reject) => {
254
+ if (this.state !== "connected") return reject(new NotConnectedError());
255
+ if (!this.ws) return reject(new InvalidStateError());
256
+ this.ws.send(data, (err) => {
257
+ if (err) return reject(err);
258
+ return resolve();
259
+ });
260
+ });
261
+ }
262
+ /**
263
+ * @return {Promise<void>}
264
+ */
265
+ close() {
266
+ switch (this.state) {
267
+ case "idle": return Promise.resolve();
268
+ case "connected":
269
+ case "connecting":
270
+ case "reconnecting":
271
+ this.state = "closing";
272
+ this.closeRequested = true;
273
+ this.closeDefer = defer();
274
+ this.ws?.close();
275
+ this.reconnectAbort?.abort();
276
+ return this.closeDefer.promise;
277
+ case "closing": return this.closeDefer.promise;
278
+ default:
279
+ const _exhaustive = this.state;
280
+ throw new Error(`Unreachable: ${_exhaustive}`);
281
+ }
282
+ }
283
+ createWs() {
284
+ this.ws = new WebSocket(this.wsAddress, {
285
+ autoPong: true,
286
+ headers: this.getConnectHeaders(),
287
+ agent: this.agent
288
+ });
289
+ this.ws.on("open", this.handleOpen);
290
+ this.ws.on("message", this.handleMessage);
291
+ this.ws.on("error", this.handleError);
292
+ this.ws.on("close", this.handleClose);
293
+ }
294
+ /**
295
+ * @return {Record<string, string>}
296
+ * @private
297
+ */
298
+ getConnectHeaders() {
299
+ if (!this.connectHeaders) return {};
300
+ if (typeof this.connectHeaders === "function") return this.connectHeaders();
301
+ return this.connectHeaders;
302
+ }
303
+ /**
304
+ * @return {number | false}
305
+ * @private
306
+ */
307
+ getReconnectDelay() {
308
+ const attempt = this.reconnectAttempt;
309
+ if (this.closeRequested || !this.reconnectStrategy) return false;
310
+ if (typeof this.reconnectStrategy === "function") return this.reconnectStrategy(attempt);
311
+ if (typeof this.reconnectStrategy === "object") {
312
+ if (attempt > this.reconnectStrategy.maxAttempts) return false;
313
+ if (typeof this.reconnectStrategy.interval === "function") return this.reconnectStrategy.interval(attempt);
314
+ if (typeof this.reconnectStrategy.interval === "number") return this.reconnectStrategy.interval;
315
+ if (typeof this.reconnectStrategy.interval === "object" && !Array.isArray(this.reconnectStrategy.interval)) return randomInt(this.reconnectStrategy.interval.min, this.reconnectStrategy.interval.max);
316
+ if (Array.isArray(this.reconnectStrategy.interval)) {
317
+ if (this.reconnectStrategy.interval.length === 0) return 0;
318
+ else if (this.reconnectStrategy.interval.length === 1) return this.reconnectStrategy.interval[0];
319
+ else if (this.reconnectStrategy.interval.length > 1) return this.reconnectStrategy.interval[(attempt - 1) % this.reconnectStrategy.interval.length];
320
+ }
321
+ }
322
+ return false;
323
+ }
324
+ /**
325
+ * @private
326
+ */
327
+ reset() {
328
+ this.state = "idle";
329
+ this.ws?.removeAllListeners();
330
+ this.openDefer?.reject(this.lastError ?? /* @__PURE__ */ new Error("WS connection closed"));
331
+ this.closeDefer?.resolve();
332
+ this.closeRequested = false;
333
+ this.openDefer = null;
334
+ this.closeDefer = null;
335
+ this.ws = null;
336
+ this.lastError = null;
337
+ this.reconnectAttempt = 0;
338
+ }
339
+ /**
340
+ */
341
+ handleOpen = () => {
342
+ this.state = "connected";
343
+ this.openDefer?.resolve();
344
+ this.openDefer = null;
345
+ const attempt = this.reconnectAttempt;
346
+ this.reconnectAttempt = 0;
347
+ this.emit("ready", attempt > 0);
348
+ };
349
+ /**
350
+ * @param {WebSocket.RawData} data
351
+ * @param {boolean} isBinary
352
+ */
353
+ handleMessage = (data, isBinary) => {
354
+ this.emit("message", data, isBinary);
355
+ };
356
+ /**
357
+ * @param {Error} err
358
+ */
359
+ handleError = (err) => {
360
+ this.lastError = err;
361
+ this.emit("error", err);
362
+ };
363
+ /**
364
+ * @param {number} code
365
+ * @param {Buffer} reason
366
+ */
367
+ handleClose = async (code, reason) => {
368
+ this.reconnectAttempt += 1;
369
+ const reconnectDelay = this.getReconnectDelay();
370
+ if (reconnectDelay !== false) {
371
+ this.state = "reconnecting";
372
+ this.reconnectAbort = new AbortController();
373
+ try {
374
+ await setTimeout$1(Math.max(1, reconnectDelay), void 0, { signal: this.reconnectAbort.signal });
375
+ } catch (e) {
376
+ this.reset();
377
+ this.emit("close");
378
+ return;
379
+ }
380
+ if (this.state !== "reconnecting") return;
381
+ this.ws?.removeAllListeners();
382
+ this.ws = null;
383
+ this.emit("reconnecting", this.reconnectAttempt);
384
+ this.createWs();
385
+ } else {
386
+ this.reset();
387
+ this.emit("close");
388
+ }
389
+ };
390
+ };
391
+ //#endregion
392
+ //#region src/wait-registry/errors.ts
393
+ var TimeoutError = class extends Error {
394
+ constructor(key) {
395
+ super(`Timed out waiting for key: ${key.toString()}`);
396
+ this.name = "TimeoutError";
397
+ }
398
+ };
399
+ var RegistryClearedError = class extends Error {
400
+ constructor() {
401
+ super("Registry cleared");
402
+ this.name = "RegistryClearedError";
403
+ }
404
+ };
405
+ //#endregion
406
+ //#region src/wait-registry/wait-registry.ts
407
+ var WaitRegistry = class {
408
+ storage = /* @__PURE__ */ new Map();
409
+ add(key, expiresInMs) {
410
+ if (this.storage.has(key)) throw new TypeError(`Key already exists: ${key.toString()}`);
411
+ const deferred = defer();
412
+ const timer = setTimeout(this.rejectOnTimeout.bind(this, key), expiresInMs);
413
+ timer.unref();
414
+ this.storage.set(key, {
415
+ deferred,
416
+ _timer: timer
417
+ });
418
+ return deferred.promise;
419
+ }
420
+ resolve(key, value) {
421
+ const awaiter = this.storage.get(key);
422
+ if (!awaiter) return;
423
+ clearTimeout(awaiter._timer);
424
+ this.storage.delete(key);
425
+ awaiter.deferred.resolve(value);
426
+ }
427
+ reject(key, error) {
428
+ const awaiter = this.storage.get(key);
429
+ if (!awaiter) return;
430
+ clearTimeout(awaiter._timer);
431
+ this.storage.delete(key);
432
+ awaiter.deferred.reject(error);
433
+ }
434
+ clear(passError) {
435
+ const error = passError ?? new RegistryClearedError();
436
+ for (const awaiter of this.storage.values()) {
437
+ clearTimeout(awaiter._timer);
438
+ awaiter.deferred.reject(error);
439
+ }
440
+ this.storage.clear();
441
+ }
442
+ rejectOnTimeout(key) {
443
+ const awaiter = this.storage.get(key);
444
+ if (!awaiter) return;
445
+ this.storage.delete(key);
446
+ clearTimeout(awaiter._timer);
447
+ awaiter.deferred.reject(new TimeoutError(key));
448
+ }
449
+ };
450
+ //#endregion
451
+ //#region src/logging.ts
452
+ const noopLogger = (level, message, context) => {};
453
+ //#endregion
454
+ //#region src/ws/messages.ts
455
+ const wsOkMessageSchema = z.object({
456
+ id: z.number(),
457
+ sid: z.number(),
458
+ type: z.literal("ok"),
459
+ msg: z.any().optional()
460
+ });
461
+ const wsErrorMessageSchema = z.object({
462
+ id: z.number(),
463
+ type: z.literal("error"),
464
+ msg: z.object({
465
+ code: z.number(),
466
+ msg: z.string()
467
+ })
468
+ });
469
+ const wsSubscribedMessageSchema = z.object({
470
+ id: z.number(),
471
+ type: z.literal("subscribed"),
472
+ msg: z.object({
473
+ channel: z.string(),
474
+ sid: z.number()
475
+ })
476
+ });
477
+ const wsUserOrderMessageSchema = z.object({
478
+ sid: z.number().positive(),
479
+ type: z.literal("user_order"),
480
+ msg: orders$orderWsSchema
481
+ });
482
+ const wsAnyMessageSchema = z.discriminatedUnion("type", [
483
+ wsOkMessageSchema,
484
+ wsErrorMessageSchema,
485
+ wsSubscribedMessageSchema,
486
+ wsUserOrderMessageSchema
487
+ ]);
488
+ //#endregion
489
+ //#region src/ws/errors.ts
490
+ var WsKalshiError = class extends Error {
491
+ id;
492
+ code;
493
+ /**
494
+ * @param {number} id
495
+ * @param {number} code
496
+ * @param {string} message
497
+ */
498
+ constructor(id, code, message) {
499
+ super(message);
500
+ this.id = id;
501
+ this.code = code;
502
+ }
503
+ };
504
+ //#endregion
505
+ //#region src/ws/ws-client.ts
506
+ var WsClient = class extends TypedEmitter {
507
+ id;
508
+ baseURL;
509
+ credentialsProvider;
510
+ log;
511
+ ws;
512
+ lastMessageId = 0;
513
+ subscribeAwaiters = new WaitRegistry();
514
+ /**
515
+ * @param {WsClientOptions} options
516
+ */
517
+ constructor(options) {
518
+ super();
519
+ this.id = options.id ?? v4();
520
+ this.baseURL = KALSHI_WS_URL[options.environment ?? "development"];
521
+ this.credentialsProvider = options.credentialsProvider;
522
+ this.log = options.log ?? noopLogger;
523
+ const path = "/trade-api/ws/v2", address = `${this.baseURL}${path}`;
524
+ this.ws = new WsWrapper({
525
+ ...options.wsOptions,
526
+ address,
527
+ headers: () => {
528
+ const timestamp = Date.now();
529
+ const signature = this.credentialsProvider.getSignature({
530
+ timestamp,
531
+ httpMethod: "GET",
532
+ path
533
+ });
534
+ return {
535
+ "Content-Type": "application/json",
536
+ "KALSHI-ACCESS-KEY": this.credentialsProvider.getAccessKey(),
537
+ "KALSHI-ACCESS-SIGNATURE": signature,
538
+ "KALSHI-ACCESS-TIMESTAMP": timestamp.toString()
539
+ };
540
+ }
541
+ });
542
+ this.ws.on("ready", this.onReady);
543
+ this.ws.on("message", this.onMessage);
544
+ this.ws.on("error", this.onError);
545
+ this.ws.on("reconnecting", this.onReconnecting);
546
+ this.ws.on("close", this.onClose);
547
+ }
548
+ onReady = async (afterReconnect) => {
549
+ this.log("debug", "WebSocket connection ready", { afterReconnect });
550
+ this.emit("ready");
551
+ };
552
+ /**
553
+ * @param {WebSocket.RawData} data
554
+ * @param {boolean} isBinary
555
+ * @return {Promise<void>}
556
+ */
557
+ onMessage = async (data, isBinary) => {
558
+ if (isBinary) {
559
+ this.log("warn", "invalid incoming message format (=binary)");
560
+ return;
561
+ }
562
+ let jsonData = null;
563
+ try {
564
+ jsonData = JSON.parse(data.toString());
565
+ } catch (e) {
566
+ this.log("warn", "failed to decode incoming message as JSON string");
567
+ return;
568
+ }
569
+ this.log("debug", "incoming message", { message: jsonData });
570
+ const { data: msg, error } = wsAnyMessageSchema.safeParse(jsonData);
571
+ if (error) {
572
+ this.log("warn", "failed to validate message", {
573
+ message: jsonData,
574
+ error
575
+ });
576
+ return;
577
+ }
578
+ this.processMessage(msg);
579
+ };
580
+ /**
581
+ * @param {number} attempt
582
+ */
583
+ onReconnecting = (attempt) => {
584
+ this.log("debug", "reconnecting", { attempt });
585
+ this.emit("reconnect", attempt);
586
+ };
587
+ /**
588
+ * @param {Error} err
589
+ */
590
+ onError = (err) => {
591
+ this.log("error", "WebSocket error", { err });
592
+ };
593
+ /**
594
+ */
595
+ onClose = () => {
596
+ this.log("debug", "WebSocket connection closed");
597
+ this.emit("close");
598
+ this.subscribeAwaiters.clear();
599
+ };
600
+ /**
601
+ * @param {WsAnyMessage} msg
602
+ * @private
603
+ */
604
+ processMessage(msg) {
605
+ switch (msg.type) {
606
+ case "ok":
607
+ this.subscribeAwaiters.resolve(msg.id, true);
608
+ break;
609
+ case "error":
610
+ this.subscribeAwaiters.reject(msg.id, new WsKalshiError(msg.id, msg.msg.code, msg.msg.msg));
611
+ break;
612
+ case "subscribed":
613
+ this.subscribeAwaiters.resolve(msg.id, true);
614
+ break;
615
+ }
616
+ this.emit("message", msg);
617
+ }
618
+ };
619
+ //#endregion
620
+ //#region src/ws/common.ts
621
+ const WS_KALSHI_ERRORS = {
622
+ UNABLE_TO_PROCESS: 1,
623
+ PARAMS_REQUIRED: 2,
624
+ CHANNELS_REQUIRED: 3,
625
+ SUBSCRIPTION_IDS_REQUIRED: 4,
626
+ UNKNOWN_COMMAND: 5,
627
+ ALREADY_SUBSCRIBED: 6,
628
+ UNKNOWN_SUBSCRIPTION_ID: 7,
629
+ UNKNOWN_CHANNEL_NAME: 8,
630
+ AUTHENTICATION_REQUIRED: 9,
631
+ CHANNEL_ERROR: 10,
632
+ INVALID_PARAMETER: 11,
633
+ EXACTLY_ONE_SUBSCRIPTION_ID_IS_REQUIRED: 12,
634
+ UNSUPPORTED_ACTION: 13,
635
+ MARKET_TICKER_REQUIRED: 14,
636
+ ACTION_REQUIRED: 15,
637
+ MARKET_NOT_FOUND: 16,
638
+ INTERNAL_ERROR: 17,
639
+ COMMAND_TIMEOUT: 18,
640
+ SHARD_FACTOR_MUST_BE_GT0: 19,
641
+ SHARD_FACTOR_IS_REQUIRED: 20,
642
+ INVALID_SHARD_KEY: 21,
643
+ SHARD_FACTOR_MUST_BE_LT100: 22,
644
+ SUBSCRIPTION_BUFFER_OVERFLOW: 25
645
+ };
646
+ const WS_KALSHI_SERVER_ERRORS = [
647
+ WS_KALSHI_ERRORS.CHANNEL_ERROR,
648
+ WS_KALSHI_ERRORS.INTERNAL_ERROR,
649
+ WS_KALSHI_ERRORS.COMMAND_TIMEOUT
650
+ ];
651
+ //#endregion
652
+ export { InMemoryCredentialsProvider, RequestSigner, WS_KALSHI_ERRORS, WS_KALSHI_SERVER_ERRORS, WsClient, WsKalshiError, orders$orderDetailedSchema, orders$orderStatusSchema, orders$orderTypeSchema, orders$orderWsSchema, orders$selfTradePreventionTypeSchema, primitives$bookSideSchema, primitives$fixedPointSchema, primitives$orderActionSchema, primitives$orderSideSchema, wsAnyMessageSchema, wsErrorMessageSchema, wsOkMessageSchema, wsSubscribedMessageSchema, wsUserOrderMessageSchema };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@jsnw/kalshi-client",
3
+ "private": false,
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "version": "0.0.1",
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
11
+ "exports": {
12
+ "node": {
13
+ "import": {
14
+ "default": "./dist/index.mjs",
15
+ "types": "./dist/index.d.mts"
16
+ },
17
+ "require": {
18
+ "default": "./dist/index.cjs",
19
+ "types": "./dist/index.d.cts"
20
+ }
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "dependencies": {
27
+ "uuid": "^14.0.0",
28
+ "ws": "^8.21.0",
29
+ "zod": "^4.4.3"
30
+ },
31
+ "optionalDependencies": {
32
+ "bufferutil": "^4.1.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^24.12.4",
36
+ "@types/ws": "^8.18.1",
37
+ "nodemon": "^3.1.14",
38
+ "rimraf": "^6.1.3",
39
+ "ts-node": "^10.9.2",
40
+ "tsdown": "^0.22.1",
41
+ "typescript": "^5.9.3"
42
+ },
43
+ "scripts": {
44
+ "clean": "rimraf ./dist",
45
+ "build": "tsdown"
46
+ }
47
+ }