@jsnw/kalshi-client 0.0.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.
package/dist/index.cjs CHANGED
@@ -4,6 +4,7 @@ let zod = require("zod");
4
4
  let uuid = require("uuid");
5
5
  let ws = require("ws");
6
6
  let node_timers_promises = require("node:timers/promises");
7
+ let _jsnw_api_client = require("@jsnw/api-client");
7
8
  //#region src/request-signer.ts
8
9
  var RequestSigner = class {
9
10
  privkey;
@@ -78,8 +79,39 @@ const primitives$fixedPointSchema = zod.z.string().regex(/^\d{1,14}\.\d{2,8}$/);
78
79
  const primitives$orderSideSchema = zod.z.enum(["yes", "no"]);
79
80
  const primitives$bookSideSchema = zod.z.enum(["bid", "ask"]);
80
81
  const primitives$orderActionSchema = zod.z.enum(["buy", "sell"]);
82
+ const primitives$rateLimitBucketMetaSchema = zod.z.object({
83
+ refill_rate: zod.z.number(),
84
+ bucket_capacity: zod.z.number()
85
+ });
86
+ //#endregion
87
+ //#region src/schemas/http.ts
88
+ const http$errorMessageSchema = zod.z.object({
89
+ code: zod.z.number(),
90
+ message: zod.z.string().optional(),
91
+ details: zod.z.any().optional(),
92
+ service: zod.z.any().optional()
93
+ });
94
+ //#endregion
95
+ //#region src/schemas/account.ts
96
+ const account$accountTierSchema = zod.z.enum([
97
+ "basic",
98
+ "advanced",
99
+ "expert",
100
+ "premier",
101
+ "paragon",
102
+ "prime",
103
+ "prestige"
104
+ ]);
105
+ const account$subaccountSchema = zod.z.number().min(0).max(63).default(0);
106
+ const account$accountGrantSchema = zod.z.object({
107
+ exchange_instance: zod.z.enum(["event_contract", "margined"]),
108
+ level: account$accountTierSchema,
109
+ source: zod.z.enum(["volume", "manual"]),
110
+ expires_ts: zod.z.number().nullable().default(null)
111
+ });
81
112
  //#endregion
82
113
  //#region src/schemas/orders.ts
114
+ const orders$clientOrderIdSchema = zod.z.string().nullable().optional();
83
115
  const orders$orderStatusSchema = zod.z.enum([
84
116
  "resting",
85
117
  "canceled",
@@ -87,17 +119,22 @@ const orders$orderStatusSchema = zod.z.enum([
87
119
  ]);
88
120
  const orders$orderTypeSchema = zod.z.enum(["limit", "market"]);
89
121
  const orders$selfTradePreventionTypeSchema = zod.z.enum(["taker_at_cross", "maker"]);
122
+ const orders$timeInForceSchema = zod.z.enum([
123
+ "fill_or_kill",
124
+ "good_till_canceled",
125
+ "immediate_or_cancel"
126
+ ]);
90
127
  const orders$orderDetailedSchema = zod.z.object({
91
128
  order_id: zod.z.uuid(),
92
129
  user_id: zod.z.uuid(),
93
- subaccount_number: zod.z.number().min(0).max(32).default(0),
94
- order_group_id: zod.z.uuid().nullable().optional(),
130
+ client_order_id: orders$clientOrderIdSchema,
131
+ order_group_id: zod.z.string().nullable().optional(),
132
+ subaccount_number: account$subaccountSchema,
95
133
  exchange_index: zod.z.number().min(0).default(0),
96
- client_order_id: zod.z.string(),
97
134
  ticker: zod.z.string(),
135
+ type: orders$orderTypeSchema,
98
136
  outcome_side: primitives$orderSideSchema,
99
137
  book_side: primitives$bookSideSchema,
100
- type: orders$orderTypeSchema,
101
138
  status: orders$orderStatusSchema,
102
139
  yes_price_dollars: primitives$fixedPointSchema,
103
140
  no_price_dollars: primitives$fixedPointSchema,
@@ -108,11 +145,11 @@ const orders$orderDetailedSchema = zod.z.object({
108
145
  maker_fill_cost_dollars: primitives$fixedPointSchema,
109
146
  taker_fees_dollars: primitives$fixedPointSchema,
110
147
  maker_fees_dollars: primitives$fixedPointSchema,
111
- self_trade_prevention_type: orders$selfTradePreventionTypeSchema.nullable().optional(),
148
+ self_trade_prevention_type: orders$selfTradePreventionTypeSchema,
112
149
  cancel_order_on_pause: zod.z.boolean(),
113
150
  created_time: zod.z.iso.datetime(),
114
- expiration_time: zod.z.iso.datetime().nullable().optional(),
115
- last_update_time: zod.z.iso.datetime().nullable().optional()
151
+ last_update_time: zod.z.iso.datetime().nullable().optional(),
152
+ expiration_time: zod.z.iso.datetime().nullable().optional()
116
153
  });
117
154
  const orders$orderWsSchema = orders$orderDetailedSchema.omit({
118
155
  exchange_index: true,
@@ -125,12 +162,32 @@ const orders$orderWsSchema = orders$orderDetailedSchema.omit({
125
162
  last_updated_ts_ms: zod.z.number().positive().optional(),
126
163
  expiration_ts_ms: zod.z.number().positive().optional()
127
164
  });
165
+ const orders$createOrderDtoSchema = zod.z.object({
166
+ client_order_id: zod.z.string().optional(),
167
+ order_group_id: zod.z.string().optional(),
168
+ exchange_index: zod.z.number().min(0).default(0),
169
+ ticker: zod.z.string(),
170
+ side: primitives$bookSideSchema,
171
+ count: primitives$fixedPointSchema,
172
+ subaccount: account$subaccountSchema,
173
+ price: primitives$fixedPointSchema,
174
+ post_only: zod.z.boolean().default(false),
175
+ reduce_only: zod.z.boolean().default(false),
176
+ cancel_order_on_pause: zod.z.boolean(),
177
+ self_trade_prevention_type: orders$selfTradePreventionTypeSchema,
178
+ time_in_force: orders$timeInForceSchema,
179
+ expiration_time: zod.z.number().optional()
180
+ });
128
181
  //#endregion
129
182
  //#region src/consts.ts
130
183
  const KALSHI_WS_URL = {
131
184
  "development": "wss://external-api-ws.demo.kalshi.co",
132
185
  "production": "wss://external-api-ws.kalshi.com"
133
186
  };
187
+ const KALSHI_API_URL = {
188
+ "development": "https://external-api.demo.kalshi.co",
189
+ "production": "https://external-api.kalshi.com"
190
+ };
134
191
  //#endregion
135
192
  //#region src/typed-emitter.ts
136
193
  var TypedEmitter = class {
@@ -502,6 +559,8 @@ var WsKalshiError = class extends Error {
502
559
  this.code = code;
503
560
  }
504
561
  };
562
+ var WsClosedError = class extends Error {};
563
+ var WsClosedByUserError = class extends Error {};
505
564
  //#endregion
506
565
  //#region src/ws/ws-client.ts
507
566
  var WsClient = class extends TypedEmitter {
@@ -546,9 +605,39 @@ var WsClient = class extends TypedEmitter {
546
605
  this.ws.on("reconnecting", this.onReconnecting);
547
606
  this.ws.on("close", this.onClose);
548
607
  }
608
+ /**
609
+ * @return {Promise<void>}
610
+ */
611
+ connect() {
612
+ return this.ws.open();
613
+ }
614
+ /**
615
+ * @return {Promise<void>}
616
+ */
617
+ async subscribe(options) {
618
+ const { channel, timeoutMs, ...rest } = options;
619
+ const messageId = ++this.lastMessageId;
620
+ const payload = {
621
+ id: messageId,
622
+ cmd: "subscribe",
623
+ params: {
624
+ channels: [channel],
625
+ ...rest
626
+ }
627
+ };
628
+ const promise = this.subscribeAwaiters.add(messageId, timeoutMs ?? 2e3);
629
+ await this.ws.send(JSON.stringify(payload));
630
+ return promise;
631
+ }
632
+ /**
633
+ * @return {Promise<void>}
634
+ */
635
+ close() {
636
+ this.subscribeAwaiters.clear(new WsClosedByUserError());
637
+ return this.ws.close();
638
+ }
549
639
  onReady = async (afterReconnect) => {
550
- this.log("debug", "WebSocket connection ready", { afterReconnect });
551
- this.emit("ready");
640
+ this.emit("ready", afterReconnect);
552
641
  };
553
642
  /**
554
643
  * @param {WebSocket.RawData} data
@@ -582,21 +671,19 @@ var WsClient = class extends TypedEmitter {
582
671
  * @param {number} attempt
583
672
  */
584
673
  onReconnecting = (attempt) => {
585
- this.log("debug", "reconnecting", { attempt });
586
674
  this.emit("reconnect", attempt);
587
675
  };
588
676
  /**
589
677
  * @param {Error} err
590
678
  */
591
679
  onError = (err) => {
592
- this.log("error", "WebSocket error", { err });
680
+ this.emit("ws_error", err);
593
681
  };
594
682
  /**
595
683
  */
596
684
  onClose = () => {
597
- this.log("debug", "WebSocket connection closed");
598
685
  this.emit("close");
599
- this.subscribeAwaiters.clear();
686
+ this.subscribeAwaiters.clear(new WsClosedError());
600
687
  };
601
688
  /**
602
689
  * @param {WsAnyMessage} msg
@@ -650,21 +737,192 @@ const WS_KALSHI_SERVER_ERRORS = [
650
737
  WS_KALSHI_ERRORS.COMMAND_TIMEOUT
651
738
  ];
652
739
  //#endregion
740
+ //#region src/api/metadata.ts
741
+ const METADATA = { NO_AUTH: Symbol("no-auth") };
742
+ //#endregion
743
+ //#region src/api/router/exchange.ts
744
+ const exchangeRouter = (0, _jsnw_api_client.createRouter)({
745
+ getStatus: {
746
+ method: "get",
747
+ path: "/status",
748
+ responses: { 200: zod.z.object({
749
+ exchange_active: zod.z.boolean(),
750
+ trading_active: zod.z.boolean(),
751
+ exchange_estimated_resume_time: zod.z.iso.datetime().nullable().optional()
752
+ }) }
753
+ },
754
+ getUserDataTimestamp: {
755
+ method: "get",
756
+ path: "/user_data_timestamp",
757
+ responses: { 200: zod.z.object({ as_of_time: zod.z.iso.datetime() }) }
758
+ }
759
+ }, {
760
+ path: "exchange",
761
+ metadata: { [METADATA.NO_AUTH]: true }
762
+ });
763
+ //#endregion
764
+ //#region src/api/router/account.ts
765
+ const accountRouter = (0, _jsnw_api_client.createRouter)({
766
+ getLimits: {
767
+ method: "get",
768
+ path: "/limits",
769
+ responses: { 200: zod.z.object({
770
+ usage_tier: account$accountTierSchema,
771
+ read: primitives$rateLimitBucketMetaSchema,
772
+ write: primitives$rateLimitBucketMetaSchema,
773
+ grants: zod.z.array(account$accountGrantSchema)
774
+ }) }
775
+ },
776
+ listNonDefaultEndpointCosts: {
777
+ method: "get",
778
+ path: "/endpoint_costs",
779
+ responses: { 200: zod.z.object({
780
+ default_cost: zod.z.number().min(0),
781
+ endpoint_costs: zod.z.array(zod.z.object({
782
+ method: zod.z.string(),
783
+ path: zod.z.string(),
784
+ cost: zod.z.number().min(0)
785
+ }))
786
+ }) },
787
+ metadata: { [METADATA.NO_AUTH]: true }
788
+ }
789
+ }, { path: "/account" });
790
+ //#endregion
791
+ //#region src/api/router/orders.ts
792
+ const ordersRouter = (0, _jsnw_api_client.createRouter)({
793
+ getOrder: {
794
+ method: "get",
795
+ path: "/orders/:order_id",
796
+ params: zod.z.object({ order_id: zod.z.uuid() }),
797
+ responses: { 200: zod.z.object({ order: orders$orderDetailedSchema }) }
798
+ },
799
+ createOrder: {
800
+ method: "post",
801
+ path: "/events/orders",
802
+ body: orders$createOrderDtoSchema,
803
+ responses: { 201: zod.z.object({
804
+ order_id: zod.z.uuid(),
805
+ client_order_id: orders$clientOrderIdSchema,
806
+ fill_count: primitives$fixedPointSchema,
807
+ remaining_count: primitives$fixedPointSchema,
808
+ average_fill_price: primitives$fixedPointSchema.nullable().optional(),
809
+ average_fee_paid: primitives$fixedPointSchema.nullable().optional(),
810
+ ts_ms: zod.z.number().min(0)
811
+ }) }
812
+ },
813
+ cancelOrderV1: {
814
+ method: "delete",
815
+ path: "/orders/:order_id",
816
+ params: zod.z.object({ order_id: zod.z.uuid() }),
817
+ query: zod.z.object({
818
+ subaccount: zod.z.number().min(0).max(63).default(0),
819
+ exchange_index: zod.z.number().min(0).default(0)
820
+ }).prefault({}),
821
+ responses: { 200: zod.z.object({
822
+ order: orders$orderDetailedSchema,
823
+ reduced_by_fp: primitives$fixedPointSchema
824
+ }) }
825
+ },
826
+ cancelOrderV2: {
827
+ method: "delete",
828
+ path: "/events/orders/:order_id",
829
+ params: zod.z.object({ order_id: zod.z.uuid() }),
830
+ query: zod.z.object({
831
+ subaccount: zod.z.number().min(0).max(63).default(0),
832
+ exchange_index: zod.z.number().min(0).default(0)
833
+ }).prefault({}),
834
+ responses: { 200: zod.z.object({
835
+ order_id: zod.z.uuid(),
836
+ client_order_id: orders$clientOrderIdSchema,
837
+ reduced_by: primitives$fixedPointSchema,
838
+ ts_ms: zod.z.number().min(0)
839
+ }) }
840
+ },
841
+ getOrderQueuePosition: {
842
+ method: "get",
843
+ path: "/orders/:order_id/queue_position",
844
+ params: zod.z.object({ order_id: zod.z.uuid() }),
845
+ responses: { 200: zod.z.object({ queue_position_fp: primitives$fixedPointSchema }) }
846
+ }
847
+ }, { path: "/portfolio" });
848
+ //#endregion
849
+ //#region src/api/router/index.ts
850
+ const apiRouter = (0, _jsnw_api_client.createRouter)({
851
+ exchange: exchangeRouter,
852
+ account: accountRouter,
853
+ orders: ordersRouter
854
+ }, { path: "/trade-api/v2" });
855
+ //#endregion
856
+ //#region src/api/client.ts
857
+ var ApiClient = class extends _jsnw_api_client.ApiClient {
858
+ /**
859
+ * @param {ApiClientConfig} config
860
+ */
861
+ constructor(config) {
862
+ super(apiRouter, {
863
+ ...config,
864
+ baseURL: KALSHI_API_URL[config.environment ?? "development"],
865
+ qsArrayFormat: "brackets",
866
+ contentType: "application/json"
867
+ });
868
+ }
869
+ /**
870
+ * @template {Route} TRoute
871
+ * @param {TRoute} route
872
+ * @param {ApiRequestParams<TRoute>} params
873
+ * @param {ApiCallOptions} options
874
+ * @return {Promise<ApiResponse<TRoute>>}
875
+ */
876
+ /**
877
+ * @param {"force"} force
878
+ * @return {Promise<void>}
879
+ * @private
880
+ */
881
+ /**
882
+ * @param {ApiRawRequest} req
883
+ * @return {ApiRawRequest}
884
+ * @protected
885
+ */
886
+ onBeforeRequest(req) {
887
+ if (req.route.metadata?.[METADATA.NO_AUTH] && req.route.metadata[METADATA.NO_AUTH] === true) return req;
888
+ const ts = Date.now();
889
+ req.headers["kalshi-access-key"] = this.config.credentialsProvider.getAccessKey();
890
+ req.headers["kalshi-access-timestamp"] = ts.toString();
891
+ req.headers["kalshi-access-signature"] = this.config.credentialsProvider.getSignature({
892
+ httpMethod: req.route.method,
893
+ path: req.path,
894
+ timestamp: ts
895
+ });
896
+ return req;
897
+ }
898
+ };
899
+ //#endregion
900
+ exports.ApiClient = ApiClient;
653
901
  exports.InMemoryCredentialsProvider = InMemoryCredentialsProvider;
654
902
  exports.RequestSigner = RequestSigner;
655
903
  exports.WS_KALSHI_ERRORS = WS_KALSHI_ERRORS;
656
904
  exports.WS_KALSHI_SERVER_ERRORS = WS_KALSHI_SERVER_ERRORS;
657
905
  exports.WsClient = WsClient;
906
+ exports.WsClosedByUserError = WsClosedByUserError;
907
+ exports.WsClosedError = WsClosedError;
658
908
  exports.WsKalshiError = WsKalshiError;
909
+ exports.account$accountGrantSchema = account$accountGrantSchema;
910
+ exports.account$accountTierSchema = account$accountTierSchema;
911
+ exports.account$subaccountSchema = account$subaccountSchema;
912
+ exports.http$errorMessageSchema = http$errorMessageSchema;
913
+ exports.orders$clientOrderIdSchema = orders$clientOrderIdSchema;
914
+ exports.orders$createOrderDtoSchema = orders$createOrderDtoSchema;
659
915
  exports.orders$orderDetailedSchema = orders$orderDetailedSchema;
660
916
  exports.orders$orderStatusSchema = orders$orderStatusSchema;
661
917
  exports.orders$orderTypeSchema = orders$orderTypeSchema;
662
918
  exports.orders$orderWsSchema = orders$orderWsSchema;
663
919
  exports.orders$selfTradePreventionTypeSchema = orders$selfTradePreventionTypeSchema;
920
+ exports.orders$timeInForceSchema = orders$timeInForceSchema;
664
921
  exports.primitives$bookSideSchema = primitives$bookSideSchema;
665
922
  exports.primitives$fixedPointSchema = primitives$fixedPointSchema;
666
923
  exports.primitives$orderActionSchema = primitives$orderActionSchema;
667
924
  exports.primitives$orderSideSchema = primitives$orderSideSchema;
925
+ exports.primitives$rateLimitBucketMetaSchema = primitives$rateLimitBucketMetaSchema;
668
926
  exports.wsAnyMessageSchema = wsAnyMessageSchema;
669
927
  exports.wsErrorMessageSchema = wsErrorMessageSchema;
670
928
  exports.wsOkMessageSchema = wsOkMessageSchema;