@gaberoo/kalshitools 1.0.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/README.md +666 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/config/init.d.ts +13 -0
- package/dist/commands/config/init.js +89 -0
- package/dist/commands/config/show.d.ts +10 -0
- package/dist/commands/config/show.js +77 -0
- package/dist/commands/markets/list.d.ts +11 -0
- package/dist/commands/markets/list.js +64 -0
- package/dist/commands/markets/show.d.ts +13 -0
- package/dist/commands/markets/show.js +79 -0
- package/dist/commands/orders/cancel.d.ts +14 -0
- package/dist/commands/orders/cancel.js +129 -0
- package/dist/commands/orders/create.d.ts +19 -0
- package/dist/commands/orders/create.js +211 -0
- package/dist/commands/orders/list.d.ts +13 -0
- package/dist/commands/orders/list.js +92 -0
- package/dist/commands/portfolio/balance.d.ts +9 -0
- package/dist/commands/portfolio/balance.js +36 -0
- package/dist/commands/portfolio/fills.d.ts +11 -0
- package/dist/commands/portfolio/fills.js +80 -0
- package/dist/commands/portfolio/positions.d.ts +9 -0
- package/dist/commands/portfolio/positions.js +58 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/base-command.d.ts +13 -0
- package/dist/lib/base-command.js +38 -0
- package/dist/lib/config/manager.d.ts +71 -0
- package/dist/lib/config/manager.js +137 -0
- package/dist/lib/config/schema.d.ts +175 -0
- package/dist/lib/config/schema.js +59 -0
- package/dist/lib/errors/base.d.ts +84 -0
- package/dist/lib/errors/base.js +106 -0
- package/dist/lib/kalshi/auth.d.ts +17 -0
- package/dist/lib/kalshi/auth.js +71 -0
- package/dist/lib/kalshi/client.d.ts +86 -0
- package/dist/lib/kalshi/client.js +228 -0
- package/dist/lib/kalshi/index.d.ts +8 -0
- package/dist/lib/kalshi/index.js +19 -0
- package/dist/lib/kalshi/types.d.ts +155 -0
- package/dist/lib/kalshi/types.js +4 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +41 -0
- package/dist/lib/output/formatter.d.ts +69 -0
- package/dist/lib/output/formatter.js +111 -0
- package/dist/lib/retry.d.ts +18 -0
- package/dist/lib/retry.js +81 -0
- package/dist/lib/sanitize.d.ts +28 -0
- package/dist/lib/sanitize.js +124 -0
- package/dist/lib/shutdown.d.ts +43 -0
- package/dist/lib/shutdown.js +106 -0
- package/dist/lib/validation.d.ts +37 -0
- package/dist/lib/validation.js +120 -0
- package/oclif.manifest.json +520 -0
- package/package.json +98 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { defaultConfig } from './schema.js';
|
|
6
|
+
import { ConfigError } from '../errors/base.js';
|
|
7
|
+
import { logger } from '../logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* Configuration manager for kalshitools
|
|
10
|
+
*/
|
|
11
|
+
export class ConfigManager {
|
|
12
|
+
store;
|
|
13
|
+
static instance = null;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.store = new Conf({
|
|
16
|
+
projectName: 'kalshitools',
|
|
17
|
+
defaults: defaultConfig,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get singleton instance
|
|
22
|
+
*/
|
|
23
|
+
static getInstance() {
|
|
24
|
+
if (!ConfigManager.instance) {
|
|
25
|
+
ConfigManager.instance = new ConfigManager();
|
|
26
|
+
}
|
|
27
|
+
return ConfigManager.instance;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the full configuration
|
|
31
|
+
*/
|
|
32
|
+
getConfig() {
|
|
33
|
+
const config = this.store.store;
|
|
34
|
+
return config;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the current environment (demo or production)
|
|
38
|
+
*/
|
|
39
|
+
getEnvironment() {
|
|
40
|
+
return process.env.KALSHI_ENV === 'production' ? 'production' : this.store.get('environment', 'demo');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the environment
|
|
44
|
+
*/
|
|
45
|
+
setEnvironment(env) {
|
|
46
|
+
this.store.set('environment', env);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get API configuration for the current environment
|
|
50
|
+
*/
|
|
51
|
+
getApiConfig() {
|
|
52
|
+
const env = this.getEnvironment();
|
|
53
|
+
const config = this.store.get(`api.${env}`);
|
|
54
|
+
// Override with environment variables if present
|
|
55
|
+
const keyId = process.env.KALSHI_API_KEY_ID || config.keyId;
|
|
56
|
+
const privateKeyPath = process.env.KALSHI_PRIVATE_KEY_PATH || config.privateKeyPath;
|
|
57
|
+
if (!keyId || !privateKeyPath) {
|
|
58
|
+
throw new ConfigError(`API credentials not configured for ${env} environment. Run 'kalshitools config init' to set up.`, { environment: env });
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
baseUrl: config.baseUrl,
|
|
62
|
+
keyId,
|
|
63
|
+
privateKeyPath,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read private key from file
|
|
68
|
+
*/
|
|
69
|
+
readPrivateKey() {
|
|
70
|
+
const apiConfig = this.getApiConfig();
|
|
71
|
+
const keyPath = apiConfig.privateKeyPath;
|
|
72
|
+
// Expand ~ to home directory
|
|
73
|
+
const expandedPath = keyPath.startsWith('~') ? join(homedir(), keyPath.slice(1)) : keyPath;
|
|
74
|
+
try {
|
|
75
|
+
const privateKey = readFileSync(expandedPath, 'utf-8');
|
|
76
|
+
logger.debug({ path: expandedPath }, 'Read private key from file');
|
|
77
|
+
return privateKey;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new ConfigError(`Failed to read private key from ${expandedPath}`, {
|
|
81
|
+
path: expandedPath,
|
|
82
|
+
error: error instanceof Error ? error.message : String(error),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Set API configuration for an environment
|
|
88
|
+
*/
|
|
89
|
+
setApiConfig(env, config) {
|
|
90
|
+
const current = this.store.get(`api.${env}`);
|
|
91
|
+
this.store.set(`api.${env}`, { ...current, ...config });
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get output configuration
|
|
95
|
+
*/
|
|
96
|
+
getOutputConfig() {
|
|
97
|
+
return this.store.get('output');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get trading configuration
|
|
101
|
+
*/
|
|
102
|
+
getTradingConfig() {
|
|
103
|
+
return this.store.get('trading');
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Set a configuration value
|
|
107
|
+
*/
|
|
108
|
+
set(key, value) {
|
|
109
|
+
this.store.set(key, value);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get the configuration file path
|
|
113
|
+
*/
|
|
114
|
+
getConfigPath() {
|
|
115
|
+
return this.store.path;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reset configuration to defaults
|
|
119
|
+
*/
|
|
120
|
+
reset() {
|
|
121
|
+
this.store.clear();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check if configuration is initialized
|
|
125
|
+
*/
|
|
126
|
+
isConfigured() {
|
|
127
|
+
const env = this.getEnvironment();
|
|
128
|
+
const config = this.store.get(`api.${env}`);
|
|
129
|
+
return Boolean(config.keyId && config.privateKeyPath);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the global configuration manager instance
|
|
134
|
+
*/
|
|
135
|
+
export function getConfig() {
|
|
136
|
+
return ConfigManager.getInstance();
|
|
137
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* API environment configuration schema
|
|
4
|
+
*/
|
|
5
|
+
declare const apiEnvSchema: z.ZodObject<{
|
|
6
|
+
baseUrl: z.ZodString;
|
|
7
|
+
keyId: z.ZodOptional<z.ZodString>;
|
|
8
|
+
privateKeyPath: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
keyId?: string | undefined;
|
|
12
|
+
privateKeyPath?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
keyId?: string | undefined;
|
|
16
|
+
privateKeyPath?: string | undefined;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Output configuration schema
|
|
20
|
+
*/
|
|
21
|
+
declare const outputSchema: z.ZodObject<{
|
|
22
|
+
defaultFormat: z.ZodDefault<z.ZodEnum<["table", "json"]>>;
|
|
23
|
+
colors: z.ZodDefault<z.ZodBoolean>;
|
|
24
|
+
}, "strip", z.ZodTypeAny, {
|
|
25
|
+
defaultFormat: "json" | "table";
|
|
26
|
+
colors: boolean;
|
|
27
|
+
}, {
|
|
28
|
+
defaultFormat?: "json" | "table" | undefined;
|
|
29
|
+
colors?: boolean | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Trading safety configuration schema
|
|
33
|
+
*/
|
|
34
|
+
declare const tradingSchema: z.ZodObject<{
|
|
35
|
+
confirmations: z.ZodDefault<z.ZodBoolean>;
|
|
36
|
+
maxOrderSize: z.ZodDefault<z.ZodNumber>;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
confirmations: boolean;
|
|
39
|
+
maxOrderSize: number;
|
|
40
|
+
}, {
|
|
41
|
+
confirmations?: boolean | undefined;
|
|
42
|
+
maxOrderSize?: number | undefined;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Main configuration schema
|
|
46
|
+
*/
|
|
47
|
+
export declare const configSchema: z.ZodObject<{
|
|
48
|
+
version: z.ZodLiteral<"1">;
|
|
49
|
+
environment: z.ZodDefault<z.ZodEnum<["demo", "production"]>>;
|
|
50
|
+
api: z.ZodObject<{
|
|
51
|
+
demo: z.ZodObject<{
|
|
52
|
+
baseUrl: z.ZodString;
|
|
53
|
+
keyId: z.ZodOptional<z.ZodString>;
|
|
54
|
+
privateKeyPath: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
baseUrl: string;
|
|
57
|
+
keyId?: string | undefined;
|
|
58
|
+
privateKeyPath?: string | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
baseUrl: string;
|
|
61
|
+
keyId?: string | undefined;
|
|
62
|
+
privateKeyPath?: string | undefined;
|
|
63
|
+
}>;
|
|
64
|
+
production: z.ZodObject<{
|
|
65
|
+
baseUrl: z.ZodString;
|
|
66
|
+
keyId: z.ZodOptional<z.ZodString>;
|
|
67
|
+
privateKeyPath: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, "strip", z.ZodTypeAny, {
|
|
69
|
+
baseUrl: string;
|
|
70
|
+
keyId?: string | undefined;
|
|
71
|
+
privateKeyPath?: string | undefined;
|
|
72
|
+
}, {
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
keyId?: string | undefined;
|
|
75
|
+
privateKeyPath?: string | undefined;
|
|
76
|
+
}>;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
demo: {
|
|
79
|
+
baseUrl: string;
|
|
80
|
+
keyId?: string | undefined;
|
|
81
|
+
privateKeyPath?: string | undefined;
|
|
82
|
+
};
|
|
83
|
+
production: {
|
|
84
|
+
baseUrl: string;
|
|
85
|
+
keyId?: string | undefined;
|
|
86
|
+
privateKeyPath?: string | undefined;
|
|
87
|
+
};
|
|
88
|
+
}, {
|
|
89
|
+
demo: {
|
|
90
|
+
baseUrl: string;
|
|
91
|
+
keyId?: string | undefined;
|
|
92
|
+
privateKeyPath?: string | undefined;
|
|
93
|
+
};
|
|
94
|
+
production: {
|
|
95
|
+
baseUrl: string;
|
|
96
|
+
keyId?: string | undefined;
|
|
97
|
+
privateKeyPath?: string | undefined;
|
|
98
|
+
};
|
|
99
|
+
}>;
|
|
100
|
+
output: z.ZodDefault<z.ZodObject<{
|
|
101
|
+
defaultFormat: z.ZodDefault<z.ZodEnum<["table", "json"]>>;
|
|
102
|
+
colors: z.ZodDefault<z.ZodBoolean>;
|
|
103
|
+
}, "strip", z.ZodTypeAny, {
|
|
104
|
+
defaultFormat: "json" | "table";
|
|
105
|
+
colors: boolean;
|
|
106
|
+
}, {
|
|
107
|
+
defaultFormat?: "json" | "table" | undefined;
|
|
108
|
+
colors?: boolean | undefined;
|
|
109
|
+
}>>;
|
|
110
|
+
trading: z.ZodDefault<z.ZodObject<{
|
|
111
|
+
confirmations: z.ZodDefault<z.ZodBoolean>;
|
|
112
|
+
maxOrderSize: z.ZodDefault<z.ZodNumber>;
|
|
113
|
+
}, "strip", z.ZodTypeAny, {
|
|
114
|
+
confirmations: boolean;
|
|
115
|
+
maxOrderSize: number;
|
|
116
|
+
}, {
|
|
117
|
+
confirmations?: boolean | undefined;
|
|
118
|
+
maxOrderSize?: number | undefined;
|
|
119
|
+
}>>;
|
|
120
|
+
}, "strip", z.ZodTypeAny, {
|
|
121
|
+
version: "1";
|
|
122
|
+
output: {
|
|
123
|
+
defaultFormat: "json" | "table";
|
|
124
|
+
colors: boolean;
|
|
125
|
+
};
|
|
126
|
+
environment: "demo" | "production";
|
|
127
|
+
api: {
|
|
128
|
+
demo: {
|
|
129
|
+
baseUrl: string;
|
|
130
|
+
keyId?: string | undefined;
|
|
131
|
+
privateKeyPath?: string | undefined;
|
|
132
|
+
};
|
|
133
|
+
production: {
|
|
134
|
+
baseUrl: string;
|
|
135
|
+
keyId?: string | undefined;
|
|
136
|
+
privateKeyPath?: string | undefined;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
trading: {
|
|
140
|
+
confirmations: boolean;
|
|
141
|
+
maxOrderSize: number;
|
|
142
|
+
};
|
|
143
|
+
}, {
|
|
144
|
+
version: "1";
|
|
145
|
+
api: {
|
|
146
|
+
demo: {
|
|
147
|
+
baseUrl: string;
|
|
148
|
+
keyId?: string | undefined;
|
|
149
|
+
privateKeyPath?: string | undefined;
|
|
150
|
+
};
|
|
151
|
+
production: {
|
|
152
|
+
baseUrl: string;
|
|
153
|
+
keyId?: string | undefined;
|
|
154
|
+
privateKeyPath?: string | undefined;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
output?: {
|
|
158
|
+
defaultFormat?: "json" | "table" | undefined;
|
|
159
|
+
colors?: boolean | undefined;
|
|
160
|
+
} | undefined;
|
|
161
|
+
environment?: "demo" | "production" | undefined;
|
|
162
|
+
trading?: {
|
|
163
|
+
confirmations?: boolean | undefined;
|
|
164
|
+
maxOrderSize?: number | undefined;
|
|
165
|
+
} | undefined;
|
|
166
|
+
}>;
|
|
167
|
+
export type Config = z.infer<typeof configSchema>;
|
|
168
|
+
export type ApiEnvConfig = z.infer<typeof apiEnvSchema>;
|
|
169
|
+
export type OutputConfig = z.infer<typeof outputSchema>;
|
|
170
|
+
export type TradingConfig = z.infer<typeof tradingSchema>;
|
|
171
|
+
/**
|
|
172
|
+
* Default configuration
|
|
173
|
+
*/
|
|
174
|
+
export declare const defaultConfig: Config;
|
|
175
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* API environment configuration schema
|
|
4
|
+
*/
|
|
5
|
+
const apiEnvSchema = z.object({
|
|
6
|
+
baseUrl: z.string().url(),
|
|
7
|
+
keyId: z.string().optional(),
|
|
8
|
+
privateKeyPath: z.string().optional(),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Output configuration schema
|
|
12
|
+
*/
|
|
13
|
+
const outputSchema = z.object({
|
|
14
|
+
defaultFormat: z.enum(['table', 'json']).default('table'),
|
|
15
|
+
colors: z.boolean().default(true),
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Trading safety configuration schema
|
|
19
|
+
*/
|
|
20
|
+
const tradingSchema = z.object({
|
|
21
|
+
confirmations: z.boolean().default(true),
|
|
22
|
+
maxOrderSize: z.number().positive().default(1000),
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Main configuration schema
|
|
26
|
+
*/
|
|
27
|
+
export const configSchema = z.object({
|
|
28
|
+
version: z.literal('1'),
|
|
29
|
+
environment: z.enum(['demo', 'production']).default('demo'),
|
|
30
|
+
api: z.object({
|
|
31
|
+
demo: apiEnvSchema,
|
|
32
|
+
production: apiEnvSchema,
|
|
33
|
+
}),
|
|
34
|
+
output: outputSchema.default({}),
|
|
35
|
+
trading: tradingSchema.default({}),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Default configuration
|
|
39
|
+
*/
|
|
40
|
+
export const defaultConfig = {
|
|
41
|
+
version: '1',
|
|
42
|
+
environment: 'demo',
|
|
43
|
+
api: {
|
|
44
|
+
demo: {
|
|
45
|
+
baseUrl: 'https://demo-api.kalshi.co/trade-api/v2',
|
|
46
|
+
},
|
|
47
|
+
production: {
|
|
48
|
+
baseUrl: 'https://trading-api.kalshi.com/trade-api/v2',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
output: {
|
|
52
|
+
defaultFormat: 'table',
|
|
53
|
+
colors: true,
|
|
54
|
+
},
|
|
55
|
+
trading: {
|
|
56
|
+
confirmations: true,
|
|
57
|
+
maxOrderSize: 1000,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes for the CLI
|
|
3
|
+
*/
|
|
4
|
+
export declare enum ExitCode {
|
|
5
|
+
Success = 0,
|
|
6
|
+
GeneralError = 1,
|
|
7
|
+
ConfigError = 2,
|
|
8
|
+
AuthError = 3,
|
|
9
|
+
APIError = 4,
|
|
10
|
+
ValidationError = 5,
|
|
11
|
+
RateLimitError = 6
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Error code type for structured error responses
|
|
15
|
+
*/
|
|
16
|
+
export type ErrorCode = 'GENERAL_ERROR' | 'CONFIG_ERROR' | 'AUTH_ERROR' | 'API_ERROR' | 'VALIDATION_ERROR' | 'RATE_LIMIT_ERROR' | 'NETWORK_ERROR' | 'NOT_FOUND' | 'TIMEOUT';
|
|
17
|
+
/**
|
|
18
|
+
* Base error class for all kalshitools errors
|
|
19
|
+
*/
|
|
20
|
+
export declare class KalshiToolsError extends Error {
|
|
21
|
+
readonly code: ErrorCode;
|
|
22
|
+
readonly exitCode: ExitCode;
|
|
23
|
+
readonly details?: Record<string, unknown>;
|
|
24
|
+
constructor(message: string, code?: ErrorCode, exitCode?: ExitCode, details?: Record<string, unknown>);
|
|
25
|
+
/**
|
|
26
|
+
* Convert error to JSON format for structured output
|
|
27
|
+
*/
|
|
28
|
+
toJSON(): {
|
|
29
|
+
success: false;
|
|
30
|
+
error: {
|
|
31
|
+
code: ErrorCode;
|
|
32
|
+
message: string;
|
|
33
|
+
details?: Record<string, unknown>;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Configuration-related errors
|
|
39
|
+
*/
|
|
40
|
+
export declare class ConfigError extends KalshiToolsError {
|
|
41
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Authentication-related errors
|
|
45
|
+
*/
|
|
46
|
+
export declare class AuthError extends KalshiToolsError {
|
|
47
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* API-related errors
|
|
51
|
+
*/
|
|
52
|
+
export declare class APIError extends KalshiToolsError {
|
|
53
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validation errors
|
|
57
|
+
*/
|
|
58
|
+
export declare class ValidationError extends KalshiToolsError {
|
|
59
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Rate limit errors
|
|
63
|
+
*/
|
|
64
|
+
export declare class RateLimitError extends KalshiToolsError {
|
|
65
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Network-related errors
|
|
69
|
+
*/
|
|
70
|
+
export declare class NetworkError extends KalshiToolsError {
|
|
71
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Resource not found errors
|
|
75
|
+
*/
|
|
76
|
+
export declare class NotFoundError extends KalshiToolsError {
|
|
77
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Timeout errors
|
|
81
|
+
*/
|
|
82
|
+
export declare class TimeoutError extends KalshiToolsError {
|
|
83
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
84
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes for the CLI
|
|
3
|
+
*/
|
|
4
|
+
export var ExitCode;
|
|
5
|
+
(function (ExitCode) {
|
|
6
|
+
ExitCode[ExitCode["Success"] = 0] = "Success";
|
|
7
|
+
ExitCode[ExitCode["GeneralError"] = 1] = "GeneralError";
|
|
8
|
+
ExitCode[ExitCode["ConfigError"] = 2] = "ConfigError";
|
|
9
|
+
ExitCode[ExitCode["AuthError"] = 3] = "AuthError";
|
|
10
|
+
ExitCode[ExitCode["APIError"] = 4] = "APIError";
|
|
11
|
+
ExitCode[ExitCode["ValidationError"] = 5] = "ValidationError";
|
|
12
|
+
ExitCode[ExitCode["RateLimitError"] = 6] = "RateLimitError";
|
|
13
|
+
})(ExitCode || (ExitCode = {}));
|
|
14
|
+
/**
|
|
15
|
+
* Base error class for all kalshitools errors
|
|
16
|
+
*/
|
|
17
|
+
export class KalshiToolsError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
exitCode;
|
|
20
|
+
details;
|
|
21
|
+
constructor(message, code = 'GENERAL_ERROR', exitCode = ExitCode.GeneralError, details) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = this.constructor.name;
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.exitCode = exitCode;
|
|
26
|
+
this.details = details;
|
|
27
|
+
Error.captureStackTrace(this, this.constructor);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Convert error to JSON format for structured output
|
|
31
|
+
*/
|
|
32
|
+
toJSON() {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
error: {
|
|
36
|
+
code: this.code,
|
|
37
|
+
message: this.message,
|
|
38
|
+
...(this.details && { details: this.details }),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Configuration-related errors
|
|
45
|
+
*/
|
|
46
|
+
export class ConfigError extends KalshiToolsError {
|
|
47
|
+
constructor(message, details) {
|
|
48
|
+
super(message, 'CONFIG_ERROR', ExitCode.ConfigError, details);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Authentication-related errors
|
|
53
|
+
*/
|
|
54
|
+
export class AuthError extends KalshiToolsError {
|
|
55
|
+
constructor(message, details) {
|
|
56
|
+
super(message, 'AUTH_ERROR', ExitCode.AuthError, details);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* API-related errors
|
|
61
|
+
*/
|
|
62
|
+
export class APIError extends KalshiToolsError {
|
|
63
|
+
constructor(message, details) {
|
|
64
|
+
super(message, 'API_ERROR', ExitCode.APIError, details);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validation errors
|
|
69
|
+
*/
|
|
70
|
+
export class ValidationError extends KalshiToolsError {
|
|
71
|
+
constructor(message, details) {
|
|
72
|
+
super(message, 'VALIDATION_ERROR', ExitCode.ValidationError, details);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Rate limit errors
|
|
77
|
+
*/
|
|
78
|
+
export class RateLimitError extends KalshiToolsError {
|
|
79
|
+
constructor(message, details) {
|
|
80
|
+
super(message, 'RATE_LIMIT_ERROR', ExitCode.RateLimitError, details);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Network-related errors
|
|
85
|
+
*/
|
|
86
|
+
export class NetworkError extends KalshiToolsError {
|
|
87
|
+
constructor(message, details) {
|
|
88
|
+
super(message, 'NETWORK_ERROR', ExitCode.GeneralError, details);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resource not found errors
|
|
93
|
+
*/
|
|
94
|
+
export class NotFoundError extends KalshiToolsError {
|
|
95
|
+
constructor(message, details) {
|
|
96
|
+
super(message, 'NOT_FOUND', ExitCode.GeneralError, details);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Timeout errors
|
|
101
|
+
*/
|
|
102
|
+
export class TimeoutError extends KalshiToolsError {
|
|
103
|
+
constructor(message, details) {
|
|
104
|
+
super(message, 'TIMEOUT', ExitCode.GeneralError, details);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate HTTP signature for Kalshi API authentication
|
|
3
|
+
* Uses RSA-PSS signing as required by Kalshi API
|
|
4
|
+
*/
|
|
5
|
+
export declare class KalshiAuth {
|
|
6
|
+
private keyId;
|
|
7
|
+
private privateKey;
|
|
8
|
+
constructor(keyId: string, privateKey: string);
|
|
9
|
+
/**
|
|
10
|
+
* Generate authentication headers for a request
|
|
11
|
+
*/
|
|
12
|
+
generateAuthHeaders(method: string, path: string, timestamp?: number): Record<string, string>;
|
|
13
|
+
/**
|
|
14
|
+
* Validate private key format
|
|
15
|
+
*/
|
|
16
|
+
static validatePrivateKey(privateKey: string): boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import crypto, { createSign } from 'node:crypto';
|
|
2
|
+
import { AuthError } from '../errors/base.js';
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Generate HTTP signature for Kalshi API authentication
|
|
6
|
+
* Uses RSA-PSS signing as required by Kalshi API
|
|
7
|
+
*/
|
|
8
|
+
export class KalshiAuth {
|
|
9
|
+
keyId;
|
|
10
|
+
privateKey;
|
|
11
|
+
constructor(keyId, privateKey) {
|
|
12
|
+
this.keyId = keyId;
|
|
13
|
+
this.privateKey = privateKey;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate authentication headers for a request
|
|
17
|
+
*/
|
|
18
|
+
generateAuthHeaders(method, path, timestamp) {
|
|
19
|
+
const ts = timestamp || Date.now();
|
|
20
|
+
const timestampStr = Math.floor(ts / 1000).toString();
|
|
21
|
+
// Create signature string: METHOD + timestamp + path
|
|
22
|
+
const signaturePayload = `${timestampStr}${method}${path}`;
|
|
23
|
+
logger.debug({ method, path, timestamp: timestampStr }, 'Generating signature');
|
|
24
|
+
try {
|
|
25
|
+
// Sign using RSA-PSS
|
|
26
|
+
const sign = createSign('RSA-SHA256');
|
|
27
|
+
sign.update(signaturePayload);
|
|
28
|
+
sign.end();
|
|
29
|
+
const signature = sign.sign({
|
|
30
|
+
key: this.privateKey,
|
|
31
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
32
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
|
|
33
|
+
}, 'base64');
|
|
34
|
+
return {
|
|
35
|
+
'KALSHI-ACCESS-KEY': this.keyId,
|
|
36
|
+
'KALSHI-ACCESS-SIGNATURE': signature,
|
|
37
|
+
'KALSHI-ACCESS-TIMESTAMP': timestampStr,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error({ error }, 'Failed to generate signature');
|
|
42
|
+
throw new AuthError('Failed to generate authentication signature', {
|
|
43
|
+
error: error instanceof Error ? error.message : String(error),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validate private key format
|
|
49
|
+
*/
|
|
50
|
+
static validatePrivateKey(privateKey) {
|
|
51
|
+
try {
|
|
52
|
+
// Check if it's PEM format
|
|
53
|
+
if (!privateKey.includes('-----BEGIN') || !privateKey.includes('-----END')) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
// Try to create a sign instance to validate the key
|
|
57
|
+
const sign = createSign('RSA-SHA256');
|
|
58
|
+
sign.update('test');
|
|
59
|
+
sign.end();
|
|
60
|
+
sign.sign({
|
|
61
|
+
key: privateKey,
|
|
62
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
63
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
|
|
64
|
+
}, 'base64');
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|