@pungoyal/kite-cli 0.1.0 → 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/README.md +81 -0
- package/dist/commands/alerts.d.ts +12 -0
- package/dist/commands/alerts.js +529 -0
- package/dist/commands/auth.js +104 -28
- package/dist/commands/config.js +56 -13
- package/dist/commands/profiles.d.ts +10 -0
- package/dist/commands/profiles.js +213 -0
- package/dist/commands/watch.js +1 -1
- package/dist/context.d.ts +6 -0
- package/dist/context.js +36 -18
- package/dist/core/api.d.ts +249 -42
- package/dist/core/api.js +100 -1
- package/dist/core/config.d.ts +77 -23
- package/dist/core/config.js +53 -21
- package/dist/core/credentials.d.ts +3 -2
- package/dist/core/credentials.js +13 -7
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.js +2 -2
- package/dist/core/paths.d.ts +9 -2
- package/dist/core/paths.js +12 -3
- package/dist/core/profiles.d.ts +78 -0
- package/dist/core/profiles.js +140 -0
- package/dist/core/schemas.d.ts +78 -5
- package/dist/core/schemas.js +55 -0
- package/dist/core/session.d.ts +3 -2
- package/dist/core/session.js +7 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/run.js +13 -1
- package/dist/safety.js +12 -1
- package/package.json +4 -3
package/dist/core/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { UsageError } from './errors.js';
|
|
3
|
-
import { AuctionSchema, BasketMarginSchema, CandlesSchema, GttCreateResultSchema, GttSchema, HoldingSchema, LtpMapSchema, MarginsSchema, MfHoldingSchema, MfOrderSchema, MfSipSchema, OhlcMapSchema, OrderMarginSchema, OrderSchema, PlaceOrderResultSchema, PositionsSchema, ProfileSchema, QuoteMapSchema, SessionSchema, TradeSchema, } from './schemas.js';
|
|
3
|
+
import { AlertHistoryEntrySchema, AlertSchema, AuctionSchema, BasketMarginSchema, CandlesSchema, GttCreateResultSchema, GttSchema, HoldingSchema, LtpMapSchema, MarginsSchema, MfHoldingSchema, MfOrderSchema, MfSipSchema, OhlcMapSchema, OrderMarginSchema, OrderSchema, PlaceOrderResultSchema, PositionsSchema, ProfileSchema, QuoteMapSchema, SessionSchema, TradeSchema, } from './schemas.js';
|
|
4
4
|
export const VARIETIES = ['regular', 'amo', 'co', 'iceberg', 'auction'];
|
|
5
5
|
export const ORDER_TYPES = ['MARKET', 'LIMIT', 'SL', 'SL-M'];
|
|
6
6
|
export const PRODUCTS = ['CNC', 'NRML', 'MIS', 'MTF'];
|
|
@@ -184,6 +184,67 @@ export class KiteApi {
|
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
// -------------------------------------------------------------------------
|
|
187
|
+
// Alerts
|
|
188
|
+
// -------------------------------------------------------------------------
|
|
189
|
+
async getAlerts(signal) {
|
|
190
|
+
return this.client.request({
|
|
191
|
+
method: 'GET',
|
|
192
|
+
path: '/alerts',
|
|
193
|
+
schema: z.array(AlertSchema),
|
|
194
|
+
signal,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
async getAlert(uuid, signal) {
|
|
198
|
+
return this.client.request({
|
|
199
|
+
method: 'GET',
|
|
200
|
+
path: `/alerts/${encodeURIComponent(uuid)}`,
|
|
201
|
+
schema: AlertSchema,
|
|
202
|
+
signal,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
async getAlertHistory(uuid, signal) {
|
|
206
|
+
return this.client.request({
|
|
207
|
+
method: 'GET',
|
|
208
|
+
path: `/alerts/${encodeURIComponent(uuid)}/history`,
|
|
209
|
+
schema: z.array(AlertHistoryEntrySchema),
|
|
210
|
+
signal,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async createAlert(params, signal) {
|
|
214
|
+
return this.client.request({
|
|
215
|
+
method: 'POST',
|
|
216
|
+
path: '/alerts',
|
|
217
|
+
schema: AlertSchema,
|
|
218
|
+
form: serialiseAlert(params),
|
|
219
|
+
signal,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
async modifyAlert(uuid, params, signal) {
|
|
223
|
+
return this.client.request({
|
|
224
|
+
method: 'PUT',
|
|
225
|
+
path: `/alerts/${encodeURIComponent(uuid)}`,
|
|
226
|
+
schema: AlertSchema,
|
|
227
|
+
form: serialiseAlert(params),
|
|
228
|
+
signal,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Delete one or more alerts.
|
|
233
|
+
*
|
|
234
|
+
* Kite takes the uuids as *repeated query parameters* (`?uuid=a&uuid=b`) on a
|
|
235
|
+
* DELETE, not a path segment or a form body — an easy thing to carry over
|
|
236
|
+
* wrongly from the GTT delete, which is path-keyed by a numeric id.
|
|
237
|
+
*/
|
|
238
|
+
async deleteAlerts(uuids, signal) {
|
|
239
|
+
return this.client.request({
|
|
240
|
+
method: 'DELETE',
|
|
241
|
+
path: '/alerts',
|
|
242
|
+
query: { uuid: uuids },
|
|
243
|
+
schema: z.unknown(),
|
|
244
|
+
signal,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
// -------------------------------------------------------------------------
|
|
187
248
|
// Portfolio
|
|
188
249
|
// -------------------------------------------------------------------------
|
|
189
250
|
async getHoldings(signal) {
|
|
@@ -393,6 +454,44 @@ function serialiseGtt(params) {
|
|
|
393
454
|
};
|
|
394
455
|
}
|
|
395
456
|
// ---------------------------------------------------------------------------
|
|
457
|
+
// Alert serialisation
|
|
458
|
+
// ---------------------------------------------------------------------------
|
|
459
|
+
export const ALERT_TYPES = ['simple', 'ato'];
|
|
460
|
+
/** Kite's raw comparison operators. The CLI accepts friendlier aliases and
|
|
461
|
+
* normalises to these before they reach the wire. */
|
|
462
|
+
export const ALERT_OPERATORS = ['<=', '>=', '<', '>', '=='];
|
|
463
|
+
export const ALERT_RHS_TYPES = ['constant', 'instrument'];
|
|
464
|
+
/** The only left/right attribute Kite documents for alerts. */
|
|
465
|
+
export const ALERT_DEFAULT_ATTRIBUTE = 'LastTradedPrice';
|
|
466
|
+
/**
|
|
467
|
+
* Alert fields are plain form values — EXCEPT `basket`, which is a JSON-encoded
|
|
468
|
+
* string inside a form field, the same asymmetry as `serialiseGtt`. The right
|
|
469
|
+
* side is sent as either a constant or an instrument reference, never both.
|
|
470
|
+
*/
|
|
471
|
+
function serialiseAlert(params) {
|
|
472
|
+
const form = {
|
|
473
|
+
name: params.name,
|
|
474
|
+
type: params.type,
|
|
475
|
+
lhs_exchange: params.lhs_exchange,
|
|
476
|
+
lhs_tradingsymbol: params.lhs_tradingsymbol,
|
|
477
|
+
lhs_attribute: params.lhs_attribute,
|
|
478
|
+
operator: params.operator,
|
|
479
|
+
rhs_type: params.rhs_type,
|
|
480
|
+
};
|
|
481
|
+
if (params.rhs_type === 'constant') {
|
|
482
|
+
form.rhs_constant = params.rhs_constant;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
form.rhs_exchange = params.rhs_exchange;
|
|
486
|
+
form.rhs_tradingsymbol = params.rhs_tradingsymbol;
|
|
487
|
+
form.rhs_attribute = params.rhs_attribute;
|
|
488
|
+
}
|
|
489
|
+
if (params.basket) {
|
|
490
|
+
form.basket = JSON.stringify(params.basket);
|
|
491
|
+
}
|
|
492
|
+
return form;
|
|
493
|
+
}
|
|
494
|
+
// ---------------------------------------------------------------------------
|
|
396
495
|
// Historical helpers
|
|
397
496
|
// ---------------------------------------------------------------------------
|
|
398
497
|
export const HISTORICAL_INTERVALS = [
|
package/dist/core/config.d.ts
CHANGED
|
@@ -12,6 +12,46 @@ export declare const EnvironmentSchema: z.ZodEnum<{
|
|
|
12
12
|
sandbox: "sandbox";
|
|
13
13
|
}>;
|
|
14
14
|
export type Environment = z.infer<typeof EnvironmentSchema>;
|
|
15
|
+
export declare const TradingSchema: z.ZodObject<{
|
|
16
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
17
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
maxOrderValue: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
strictConfirmAbove: z.ZodDefault<z.ZodNumber>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
export type TradingConfig = z.infer<typeof TradingSchema>;
|
|
22
|
+
/**
|
|
23
|
+
* Per-profile trading overrides. Every field is optional with NO default:
|
|
24
|
+
* an absent field means "inherit the global setting", never "no limit". That
|
|
25
|
+
* inheritance is deliberately fail-closed — a profile that omits a cap must
|
|
26
|
+
* still be bound by the global cap, or the one guard the user configured would
|
|
27
|
+
* silently stop applying to their other accounts.
|
|
28
|
+
*/
|
|
29
|
+
export declare const ProfileTradingSchema: z.ZodObject<{
|
|
30
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
32
|
+
maxOrderValue: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
strictConfirmAbove: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
export type ProfileTradingOverrides = z.infer<typeof ProfileTradingSchema>;
|
|
36
|
+
/**
|
|
37
|
+
* A named account. Each real Zerodha account has its own Kite Connect app, so a
|
|
38
|
+
* profile carries its own (semi-public) api key and env; its api secret and
|
|
39
|
+
* access token live in the keyring / encrypted file, namespaced by profile.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ProfileConfigSchema: z.ZodObject<{
|
|
42
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
43
|
+
env: z.ZodOptional<z.ZodEnum<{
|
|
44
|
+
production: "production";
|
|
45
|
+
sandbox: "sandbox";
|
|
46
|
+
}>>;
|
|
47
|
+
trading: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
50
|
+
maxOrderValue: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
strictConfirmAbove: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type ProfileConfig = z.infer<typeof ProfileConfigSchema>;
|
|
15
55
|
export declare const ConfigSchema: z.ZodObject<{
|
|
16
56
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
17
57
|
env: z.ZodDefault<z.ZodEnum<{
|
|
@@ -24,10 +64,24 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
24
64
|
maxOrderValue: z.ZodOptional<z.ZodNumber>;
|
|
25
65
|
strictConfirmAbove: z.ZodDefault<z.ZodNumber>;
|
|
26
66
|
}, z.core.$strip>>;
|
|
67
|
+
defaultProfile: z.ZodOptional<z.ZodString>;
|
|
68
|
+
profiles: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
69
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
70
|
+
env: z.ZodOptional<z.ZodEnum<{
|
|
71
|
+
production: "production";
|
|
72
|
+
sandbox: "sandbox";
|
|
73
|
+
}>>;
|
|
74
|
+
trading: z.ZodOptional<z.ZodObject<{
|
|
75
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
76
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
77
|
+
maxOrderValue: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
strictConfirmAbove: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
80
|
+
}, z.core.$strip>>>;
|
|
27
81
|
output: z.ZodPrefault<z.ZodObject<{
|
|
28
82
|
color: z.ZodDefault<z.ZodEnum<{
|
|
29
|
-
auto: "auto";
|
|
30
83
|
always: "always";
|
|
84
|
+
auto: "auto";
|
|
31
85
|
never: "never";
|
|
32
86
|
}>>;
|
|
33
87
|
compact: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -51,44 +105,44 @@ export declare function saveConfig(config: Config): Promise<void>;
|
|
|
51
105
|
*/
|
|
52
106
|
export declare const SETTABLE_KEYS: {
|
|
53
107
|
readonly apiKey: {
|
|
54
|
-
readonly type:
|
|
55
|
-
readonly description:
|
|
108
|
+
readonly type: 'string';
|
|
109
|
+
readonly description: 'Kite Connect API key';
|
|
56
110
|
};
|
|
57
111
|
readonly env: {
|
|
58
|
-
readonly type:
|
|
59
|
-
readonly description:
|
|
112
|
+
readonly type: 'string';
|
|
113
|
+
readonly description: 'production or sandbox';
|
|
60
114
|
};
|
|
61
115
|
readonly 'trading.enabled': {
|
|
62
|
-
readonly type:
|
|
63
|
-
readonly description:
|
|
116
|
+
readonly type: 'boolean';
|
|
117
|
+
readonly description: 'Master kill switch for all order commands';
|
|
64
118
|
};
|
|
65
119
|
readonly 'trading.confirm': {
|
|
66
|
-
readonly type:
|
|
67
|
-
readonly description:
|
|
120
|
+
readonly type: 'boolean';
|
|
121
|
+
readonly description: 'Require confirmation before money-moving actions';
|
|
68
122
|
};
|
|
69
123
|
readonly 'trading.maxOrderValue': {
|
|
70
|
-
readonly type:
|
|
71
|
-
readonly description:
|
|
124
|
+
readonly type: 'number';
|
|
125
|
+
readonly description: 'Refuse any single order above this rupee value';
|
|
72
126
|
};
|
|
73
127
|
readonly 'trading.strictConfirmAbove': {
|
|
74
|
-
readonly type:
|
|
75
|
-
readonly description:
|
|
128
|
+
readonly type: 'number';
|
|
129
|
+
readonly description: 'Above this rupee value, require typing the symbol to confirm';
|
|
76
130
|
};
|
|
77
131
|
readonly 'output.color': {
|
|
78
|
-
readonly type:
|
|
79
|
-
readonly description:
|
|
132
|
+
readonly type: 'string';
|
|
133
|
+
readonly description: 'auto, always, or never';
|
|
80
134
|
};
|
|
81
135
|
readonly 'output.compact': {
|
|
82
|
-
readonly type:
|
|
83
|
-
readonly description:
|
|
136
|
+
readonly type: 'boolean';
|
|
137
|
+
readonly description: 'Render tables without borders';
|
|
84
138
|
};
|
|
85
139
|
readonly redirectPort: {
|
|
86
|
-
readonly type:
|
|
87
|
-
readonly description:
|
|
140
|
+
readonly type: 'number';
|
|
141
|
+
readonly description: 'Loopback port for the login callback';
|
|
88
142
|
};
|
|
89
143
|
readonly redirectPath: {
|
|
90
|
-
readonly type:
|
|
91
|
-
readonly description:
|
|
144
|
+
readonly type: 'string';
|
|
145
|
+
readonly description: 'Path component of the login callback URL';
|
|
92
146
|
};
|
|
93
147
|
};
|
|
94
148
|
export type SettableKey = keyof typeof SETTABLE_KEYS;
|
|
@@ -107,8 +161,8 @@ export interface Endpoints {
|
|
|
107
161
|
export declare function endpointsFor(env: Environment): Endpoints;
|
|
108
162
|
/** Public sandbox credentials, documented at https://kite.trade/docs/connect/v3/sandbox/ */
|
|
109
163
|
export declare const SANDBOX_CREDENTIALS: {
|
|
110
|
-
readonly apiKey:
|
|
111
|
-
readonly apiSecret:
|
|
164
|
+
readonly apiKey: 'sandboxdemo';
|
|
165
|
+
readonly apiSecret: 'sandboxdemo-secret';
|
|
112
166
|
};
|
|
113
167
|
/** Resolve the effective environment: --env flag > KITE_ENV > config > production. */
|
|
114
168
|
export declare function resolveEnv(flag: string | undefined, config: Config): Environment;
|
package/dist/core/config.js
CHANGED
|
@@ -11,31 +11,63 @@ import { configDir, configFile, ensurePrivateDir } from './paths.js';
|
|
|
11
11
|
* is exactly how an accidental order gets placed.
|
|
12
12
|
*/
|
|
13
13
|
export const EnvironmentSchema = z.enum(['production', 'sandbox']);
|
|
14
|
+
export const TradingSchema = z.object({
|
|
15
|
+
/**
|
|
16
|
+
* Local kill switch. When false, every order-placing, order-modifying and
|
|
17
|
+
* GTT-mutating command refuses before touching the network.
|
|
18
|
+
*/
|
|
19
|
+
enabled: z.boolean().default(true),
|
|
20
|
+
/** Require an interactive confirmation before any money-moving action. */
|
|
21
|
+
confirm: z.boolean().default(true),
|
|
22
|
+
/**
|
|
23
|
+
* Refuse any single order whose notional value exceeds this (rupees).
|
|
24
|
+
* Undefined means no cap.
|
|
25
|
+
*/
|
|
26
|
+
maxOrderValue: z.number().positive().optional(),
|
|
27
|
+
/**
|
|
28
|
+
* Above this notional value, require typing a literal token to confirm
|
|
29
|
+
* rather than a single keystroke.
|
|
30
|
+
*/
|
|
31
|
+
strictConfirmAbove: z.number().positive().default(100_000),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Per-profile trading overrides. Every field is optional with NO default:
|
|
35
|
+
* an absent field means "inherit the global setting", never "no limit". That
|
|
36
|
+
* inheritance is deliberately fail-closed — a profile that omits a cap must
|
|
37
|
+
* still be bound by the global cap, or the one guard the user configured would
|
|
38
|
+
* silently stop applying to their other accounts.
|
|
39
|
+
*/
|
|
40
|
+
export const ProfileTradingSchema = z.object({
|
|
41
|
+
enabled: z.boolean().optional(),
|
|
42
|
+
confirm: z.boolean().optional(),
|
|
43
|
+
maxOrderValue: z.number().positive().optional(),
|
|
44
|
+
strictConfirmAbove: z.number().positive().optional(),
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* A named account. Each real Zerodha account has its own Kite Connect app, so a
|
|
48
|
+
* profile carries its own (semi-public) api key and env; its api secret and
|
|
49
|
+
* access token live in the keyring / encrypted file, namespaced by profile.
|
|
50
|
+
*/
|
|
51
|
+
export const ProfileConfigSchema = z.object({
|
|
52
|
+
apiKey: z.string().min(1).optional(),
|
|
53
|
+
env: EnvironmentSchema.optional(),
|
|
54
|
+
trading: ProfileTradingSchema.optional(),
|
|
55
|
+
});
|
|
14
56
|
export const ConfigSchema = z.object({
|
|
15
57
|
/** Kite Connect API key. Semi-public (it appears in login URLs), so not a keyring secret. */
|
|
16
58
|
apiKey: z.string().min(1).optional(),
|
|
17
59
|
env: EnvironmentSchema.default('production'),
|
|
18
|
-
trading:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* Undefined means no cap.
|
|
30
|
-
*/
|
|
31
|
-
maxOrderValue: z.number().positive().optional(),
|
|
32
|
-
/**
|
|
33
|
-
* Above this notional value, require typing a literal token to confirm
|
|
34
|
-
* rather than a single keystroke.
|
|
35
|
-
*/
|
|
36
|
-
strictConfirmAbove: z.number().positive().default(100_000),
|
|
37
|
-
})
|
|
38
|
-
.prefault({}),
|
|
60
|
+
trading: TradingSchema.prefault({}),
|
|
61
|
+
/**
|
|
62
|
+
* The profile used when none is named on the command line or in KITE_PROFILE.
|
|
63
|
+
* Absent means the reserved `default` profile (top-level apiKey/env above).
|
|
64
|
+
*/
|
|
65
|
+
defaultProfile: z.string().min(1).optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Named accounts beyond `default`. The `default` and `sandbox` profiles are
|
|
68
|
+
* reserved and synthesised, so they never need an entry here.
|
|
69
|
+
*/
|
|
70
|
+
profiles: z.record(z.string(), ProfileConfigSchema).default({}),
|
|
39
71
|
output: z
|
|
40
72
|
.object({
|
|
41
73
|
color: z.enum(['auto', 'always', 'never']).default('auto'),
|
|
@@ -7,7 +7,8 @@ export interface CredentialLookup {
|
|
|
7
7
|
/** True when an OS keyring is present and usable on this machine. */
|
|
8
8
|
export declare function keyringAvailable(): Promise<boolean>;
|
|
9
9
|
export interface CredentialStoreOptions {
|
|
10
|
-
|
|
10
|
+
/** Profile storage prefix, e.g. '' (default), 'sandbox:', 'profile:<name>:'. */
|
|
11
|
+
scope: string;
|
|
11
12
|
/** Passphrase for the file backend when the keyring is unavailable. */
|
|
12
13
|
passphrase?: string | undefined;
|
|
13
14
|
}
|
|
@@ -21,7 +22,7 @@ export interface CredentialStoreOptions {
|
|
|
21
22
|
export declare function getSecret(name: SecretName, opts: CredentialStoreOptions): Promise<CredentialLookup | null>;
|
|
22
23
|
export declare function setSecret(name: SecretName, value: string, opts: CredentialStoreOptions): Promise<Backend>;
|
|
23
24
|
export declare function deleteSecret(name: SecretName, opts: CredentialStoreOptions): Promise<void>;
|
|
24
|
-
/** Remove every stored secret for
|
|
25
|
+
/** Remove every stored secret for a profile. Used by `kite logout --all`. */
|
|
25
26
|
export declare function deleteAllSecrets(opts: CredentialStoreOptions): Promise<void>;
|
|
26
27
|
/** True when secrets are being supplied entirely by the environment. */
|
|
27
28
|
export declare function usingEnvCredentials(): boolean;
|
package/dist/core/credentials.js
CHANGED
|
@@ -105,9 +105,15 @@ function filePassphrase() {
|
|
|
105
105
|
const value = process.env['KITE_CREDENTIALS_PASSPHRASE'];
|
|
106
106
|
return value && value !== '' ? value : null;
|
|
107
107
|
}
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Name the keyring entry / file key for a secret by prepending the profile's
|
|
110
|
+
* storage prefix. The prefix ('' for default, 'sandbox:', 'profile:<name>:') is
|
|
111
|
+
* computed by `storagePrefixFor` in profiles.ts and passed in, so this module
|
|
112
|
+
* stays unaware of the profile model — and the default profile keeps the exact
|
|
113
|
+
* unprefixed keys the single-account CLI has always written.
|
|
114
|
+
*/
|
|
115
|
+
function scopedKey(name, scope) {
|
|
116
|
+
return `${scope}${name}`;
|
|
111
117
|
}
|
|
112
118
|
/**
|
|
113
119
|
* Read a secret, trying each backend in priority order.
|
|
@@ -122,7 +128,7 @@ export async function getSecret(name, opts) {
|
|
|
122
128
|
registerSecret(fromEnv);
|
|
123
129
|
return { value: fromEnv, backend: 'env' };
|
|
124
130
|
}
|
|
125
|
-
const account =
|
|
131
|
+
const account = scopedKey(name, opts.scope);
|
|
126
132
|
const fromKeyring = await keyringGet(account);
|
|
127
133
|
if (fromKeyring) {
|
|
128
134
|
registerSecret(fromKeyring);
|
|
@@ -141,7 +147,7 @@ export async function getSecret(name, opts) {
|
|
|
141
147
|
}
|
|
142
148
|
export async function setSecret(name, value, opts) {
|
|
143
149
|
registerSecret(value);
|
|
144
|
-
const account =
|
|
150
|
+
const account = scopedKey(name, opts.scope);
|
|
145
151
|
if (await keyringSet(account, value)) {
|
|
146
152
|
return 'keyring';
|
|
147
153
|
}
|
|
@@ -155,7 +161,7 @@ export async function setSecret(name, value, opts) {
|
|
|
155
161
|
return 'file';
|
|
156
162
|
}
|
|
157
163
|
export async function deleteSecret(name, opts) {
|
|
158
|
-
const account =
|
|
164
|
+
const account = scopedKey(name, opts.scope);
|
|
159
165
|
await keyringDelete(account);
|
|
160
166
|
const passphrase = opts.passphrase ?? filePassphrase();
|
|
161
167
|
if (passphrase) {
|
|
@@ -171,7 +177,7 @@ export async function deleteSecret(name, opts) {
|
|
|
171
177
|
}
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
|
-
/** Remove every stored secret for
|
|
180
|
+
/** Remove every stored secret for a profile. Used by `kite logout --all`. */
|
|
175
181
|
export async function deleteAllSecrets(opts) {
|
|
176
182
|
await deleteSecret('access_token', opts);
|
|
177
183
|
await deleteSecret('api_secret', opts);
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare class KiteApiError extends KiteCliError {
|
|
|
62
62
|
}
|
|
63
63
|
/** The local session is missing or expired. */
|
|
64
64
|
export declare class AuthRequiredError extends KiteCliError {
|
|
65
|
-
constructor(message?: string);
|
|
65
|
+
constructor(message?: string, hint?: string);
|
|
66
66
|
}
|
|
67
67
|
/** Bad CLI usage — distinct from Kite rejecting valid-looking input. */
|
|
68
68
|
export declare class UsageError extends KiteCliError {
|
package/dist/core/errors.js
CHANGED
|
@@ -63,8 +63,8 @@ export class KiteApiError extends KiteCliError {
|
|
|
63
63
|
}
|
|
64
64
|
/** The local session is missing or expired. */
|
|
65
65
|
export class AuthRequiredError extends KiteCliError {
|
|
66
|
-
constructor(message = 'Not logged in.') {
|
|
67
|
-
super(message, ExitCode.Auth,
|
|
66
|
+
constructor(message = 'Not logged in.', hint = 'Run `kite login` to start a session.') {
|
|
67
|
+
super(message, ExitCode.Auth, hint);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
/** Bad CLI usage — distinct from Kite rejecting valid-looking input. */
|
package/dist/core/paths.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
export declare function configDir(): string;
|
|
2
2
|
export declare function cacheDir(): string;
|
|
3
3
|
export declare function configFile(): string;
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Non-secret session metadata (expiry, user id) for a profile. The token itself
|
|
6
|
+
* is not here.
|
|
7
|
+
*
|
|
8
|
+
* The `default` profile keeps the historical `session.json` path so existing
|
|
9
|
+
* installs are untouched; every other profile gets its own `session.<name>.json`,
|
|
10
|
+
* which is what lets several accounts hold live sessions at once.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sessionFile(profile?: string): string;
|
|
6
13
|
/** Encrypted credential store, used only when the OS keyring is unavailable. */
|
|
7
14
|
export declare function credentialsFile(): string;
|
|
8
15
|
/** Instrument master cache, refreshed daily. */
|
package/dist/core/paths.js
CHANGED
|
@@ -27,9 +27,18 @@ export function cacheDir() {
|
|
|
27
27
|
export function configFile() {
|
|
28
28
|
return join(configDir(), 'config.json');
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Non-secret session metadata (expiry, user id) for a profile. The token itself
|
|
32
|
+
* is not here.
|
|
33
|
+
*
|
|
34
|
+
* The `default` profile keeps the historical `session.json` path so existing
|
|
35
|
+
* installs are untouched; every other profile gets its own `session.<name>.json`,
|
|
36
|
+
* which is what lets several accounts hold live sessions at once.
|
|
37
|
+
*/
|
|
38
|
+
export function sessionFile(profile = 'default') {
|
|
39
|
+
if (profile === 'default')
|
|
40
|
+
return join(configDir(), 'session.json');
|
|
41
|
+
return join(configDir(), `session.${profile}.json`);
|
|
33
42
|
}
|
|
34
43
|
/** Encrypted credential store, used only when the OS keyring is unavailable. */
|
|
35
44
|
export function credentialsFile() {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type Config, type Environment, type TradingConfig } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Multi-account resolution.
|
|
4
|
+
*
|
|
5
|
+
* A *profile* is a named Zerodha account. Selection is stateless per invocation
|
|
6
|
+
* — there is deliberately no sticky "active account" that persists across
|
|
7
|
+
* commands, because forgetting which account is active while placing real
|
|
8
|
+
* orders is exactly the mistake this feature must not introduce. Instead the
|
|
9
|
+
* target is resolved fresh every run, and the money-moving preview shows the
|
|
10
|
+
* verified user id (see `safety.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Two profile names are reserved:
|
|
13
|
+
* - `default` — today's single-account setup (top-level apiKey/env in config,
|
|
14
|
+
* secrets stored unprefixed). Chosen so existing installs need
|
|
15
|
+
* no migration.
|
|
16
|
+
* - `sandbox` — Zerodha's public sandbox. One fixed identity, so there is no
|
|
17
|
+
* value in per-account sandbox profiles.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_PROFILE = "default";
|
|
20
|
+
export declare const SANDBOX_PROFILE = "sandbox";
|
|
21
|
+
export declare const RESERVED_PROFILES: readonly ["default", "sandbox"];
|
|
22
|
+
export interface ResolvedProfile {
|
|
23
|
+
name: string;
|
|
24
|
+
/** Semi-public Kite Connect API key. Empty until the profile is logged in. */
|
|
25
|
+
apiKey: string;
|
|
26
|
+
env: Environment;
|
|
27
|
+
/** Per-profile trading overrides, or undefined to use the global settings. */
|
|
28
|
+
trading: Config['profiles'][string]['trading'];
|
|
29
|
+
/**
|
|
30
|
+
* True when the caller named this profile explicitly (`--profile` / KITE_PROFILE),
|
|
31
|
+
* as opposed to falling back to the configured default or the `--env` alias.
|
|
32
|
+
* Drives the fail-closed guard against an ambient KITE_ACCESS_TOKEN silently
|
|
33
|
+
* overriding an explicitly chosen account.
|
|
34
|
+
*/
|
|
35
|
+
explicit: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Reject names that could escape a filename or collide with a reserved prefix. */
|
|
38
|
+
export declare function assertValidProfileName(name: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Keyring / encrypted-file namespace for a profile's secrets.
|
|
41
|
+
*
|
|
42
|
+
* The reserved profiles reproduce the historical env-keyed scheme byte-for-byte
|
|
43
|
+
* (`production` unprefixed, `sandbox:` otherwise), so no stored secret has to be
|
|
44
|
+
* migrated. Every other profile gets a `profile:<name>:` namespace that cannot
|
|
45
|
+
* collide with an env name.
|
|
46
|
+
*/
|
|
47
|
+
export declare function storagePrefixFor(profile: Pick<ResolvedProfile, 'name' | 'env'>): string;
|
|
48
|
+
/** Every profile the user has, reserved ones first, without duplicates. */
|
|
49
|
+
export declare function listProfileNames(config: Config): string[];
|
|
50
|
+
export declare function isKnownProfile(config: Config, name: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Look up a profile by name without applying command-line overrides.
|
|
53
|
+
*
|
|
54
|
+
* An unknown name yields an empty, production profile rather than throwing, so
|
|
55
|
+
* `kite --profile new login` (and `profiles add`) can create it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function getProfile(config: Config, name: string): ResolvedProfile;
|
|
58
|
+
export interface ProfileSelectors {
|
|
59
|
+
/** The `--profile` flag value, if any. */
|
|
60
|
+
profileFlag?: string | undefined;
|
|
61
|
+
/** The `--env` flag value, if any. */
|
|
62
|
+
envFlag?: string | undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the effective profile for this invocation.
|
|
66
|
+
*
|
|
67
|
+
* Precedence: `--profile` > KITE_PROFILE > (`--env sandbox` alias) >
|
|
68
|
+
* `config.defaultProfile` > `default`. An explicit `--env`/KITE_ENV then
|
|
69
|
+
* overrides the resolved profile's environment, so `--env production` still
|
|
70
|
+
* forces production the way it always has.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveProfile(selectors: ProfileSelectors, config: Config): ResolvedProfile;
|
|
73
|
+
/**
|
|
74
|
+
* The trading config actually in force: global settings overlaid with the
|
|
75
|
+
* profile's overrides. Fail-closed by construction — a field the profile leaves
|
|
76
|
+
* unset falls back to the global value, so an omitted cap never becomes "no cap".
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveTradingConfig(config: Config, profile: ResolvedProfile): TradingConfig;
|