@pungoyal/kite-cli 0.1.1 → 0.2.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/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 = [
@@ -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: "string";
55
- readonly description: "Kite Connect API key";
108
+ readonly type: 'string';
109
+ readonly description: 'Kite Connect API key';
56
110
  };
57
111
  readonly env: {
58
- readonly type: "string";
59
- readonly description: "production or sandbox";
112
+ readonly type: 'string';
113
+ readonly description: 'production or sandbox';
60
114
  };
61
115
  readonly 'trading.enabled': {
62
- readonly type: "boolean";
63
- readonly description: "Master kill switch for all order commands";
116
+ readonly type: 'boolean';
117
+ readonly description: 'Master kill switch for all order commands';
64
118
  };
65
119
  readonly 'trading.confirm': {
66
- readonly type: "boolean";
67
- readonly description: "Require confirmation before money-moving actions";
120
+ readonly type: 'boolean';
121
+ readonly description: 'Require confirmation before money-moving actions';
68
122
  };
69
123
  readonly 'trading.maxOrderValue': {
70
- readonly type: "number";
71
- readonly description: "Refuse any single order above this rupee value";
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: "number";
75
- readonly description: "Above this rupee value, require typing the symbol to confirm";
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: "string";
79
- readonly description: "auto, always, or never";
132
+ readonly type: 'string';
133
+ readonly description: 'auto, always, or never';
80
134
  };
81
135
  readonly 'output.compact': {
82
- readonly type: "boolean";
83
- readonly description: "Render tables without borders";
136
+ readonly type: 'boolean';
137
+ readonly description: 'Render tables without borders';
84
138
  };
85
139
  readonly redirectPort: {
86
- readonly type: "number";
87
- readonly description: "Loopback port for the login callback";
140
+ readonly type: 'number';
141
+ readonly description: 'Loopback port for the login callback';
88
142
  };
89
143
  readonly redirectPath: {
90
- readonly type: "string";
91
- readonly description: "Path component of the login callback URL";
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: "sandboxdemo";
111
- readonly apiSecret: "sandboxdemo-secret";
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;
@@ -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: z
19
- .object({
20
- /**
21
- * Local kill switch. When false, every order-placing, order-modifying and
22
- * GTT-mutating command refuses before touching the network.
23
- */
24
- enabled: z.boolean().default(true),
25
- /** Require an interactive confirmation before any money-moving action. */
26
- confirm: z.boolean().default(true),
27
- /**
28
- * Refuse any single order whose notional value exceeds this (rupees).
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
- env: string;
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 an environment. Used by `kite logout --all`. */
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;
@@ -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
- /** Namespaced account key, so sandbox and production sessions coexist. */
109
- function accountKey(name, env) {
110
- return env === 'production' ? name : `${env}:${name}`;
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 = accountKey(name, opts.env);
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 = accountKey(name, opts.env);
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 = accountKey(name, opts.env);
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 an environment. Used by `kite logout --all`. */
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);
@@ -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 {
@@ -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, 'Run `kite login` to start a session.');
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. */
@@ -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
- /** Non-secret session metadata (expiry, user id). The token itself is not here. */
5
- export declare function sessionFile(): string;
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. */
@@ -27,9 +27,18 @@ export function cacheDir() {
27
27
  export function configFile() {
28
28
  return join(configDir(), 'config.json');
29
29
  }
30
- /** Non-secret session metadata (expiry, user id). The token itself is not here. */
31
- export function sessionFile() {
32
- return join(configDir(), 'session.json');
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;