@pungoyal/kite-cli 0.1.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +292 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +7 -0
  5. package/dist/commands/auth.d.ts +2 -0
  6. package/dist/commands/auth.js +265 -0
  7. package/dist/commands/config.d.ts +2 -0
  8. package/dist/commands/config.js +182 -0
  9. package/dist/commands/gtt.d.ts +12 -0
  10. package/dist/commands/gtt.js +276 -0
  11. package/dist/commands/market.d.ts +2 -0
  12. package/dist/commands/market.js +389 -0
  13. package/dist/commands/orders.d.ts +2 -0
  14. package/dist/commands/orders.js +679 -0
  15. package/dist/commands/portfolio.d.ts +2 -0
  16. package/dist/commands/portfolio.js +286 -0
  17. package/dist/commands/types.d.ts +16 -0
  18. package/dist/commands/types.js +1 -0
  19. package/dist/commands/watch.d.ts +18 -0
  20. package/dist/commands/watch.js +285 -0
  21. package/dist/context.d.ts +40 -0
  22. package/dist/context.js +126 -0
  23. package/dist/core/api.d.ts +843 -0
  24. package/dist/core/api.js +472 -0
  25. package/dist/core/auth.d.ts +68 -0
  26. package/dist/core/auth.js +220 -0
  27. package/dist/core/client.d.ts +76 -0
  28. package/dist/core/client.js +285 -0
  29. package/dist/core/config.d.ts +114 -0
  30. package/dist/core/config.js +163 -0
  31. package/dist/core/credentials.d.ts +27 -0
  32. package/dist/core/credentials.js +182 -0
  33. package/dist/core/errors.d.ts +83 -0
  34. package/dist/core/errors.js +152 -0
  35. package/dist/core/instruments.d.ts +87 -0
  36. package/dist/core/instruments.js +288 -0
  37. package/dist/core/paths.d.ts +11 -0
  38. package/dist/core/paths.js +56 -0
  39. package/dist/core/ratelimit.d.ts +57 -0
  40. package/dist/core/ratelimit.js +196 -0
  41. package/dist/core/redact.d.ts +48 -0
  42. package/dist/core/redact.js +181 -0
  43. package/dist/core/schemas.d.ts +662 -0
  44. package/dist/core/schemas.js +433 -0
  45. package/dist/core/secretstore.d.ts +11 -0
  46. package/dist/core/secretstore.js +138 -0
  47. package/dist/core/session.d.ts +37 -0
  48. package/dist/core/session.js +102 -0
  49. package/dist/core/ticker.d.ts +131 -0
  50. package/dist/core/ticker.js +367 -0
  51. package/dist/index.d.ts +17 -0
  52. package/dist/index.js +17 -0
  53. package/dist/output/format.d.ts +31 -0
  54. package/dist/output/format.js +162 -0
  55. package/dist/output/io.d.ts +70 -0
  56. package/dist/output/io.js +143 -0
  57. package/dist/output/table.d.ts +28 -0
  58. package/dist/output/table.js +73 -0
  59. package/dist/run.d.ts +15 -0
  60. package/dist/run.js +161 -0
  61. package/dist/safety.d.ts +93 -0
  62. package/dist/safety.js +154 -0
  63. package/package.json +85 -0
@@ -0,0 +1,126 @@
1
+ import { KiteApi } from './core/api.js';
2
+ import { KiteClient } from './core/client.js';
3
+ import { endpointsFor, loadConfig, resolveEnv, SANDBOX_CREDENTIALS, } from './core/config.js';
4
+ import { getSecret } from './core/credentials.js';
5
+ import { AuthRequiredError, ExitCode, KiteCliError } from './core/errors.js';
6
+ import { InstrumentStore } from './core/instruments.js';
7
+ import { RateLimiter } from './core/ratelimit.js';
8
+ import { registerSecret } from './core/redact.js';
9
+ import { isExpired, loadSessionMeta } from './core/session.js';
10
+ import { Io } from './output/io.js';
11
+ export async function createContext(options, signal, streams) {
12
+ const config = await loadConfig();
13
+ const env = resolveEnv(options.env, config);
14
+ const endpoints = endpointsFor(env);
15
+ const io = new Io({
16
+ json: options.json ?? false,
17
+ color: options.color ?? config.output.color,
18
+ quiet: options.quiet ?? false,
19
+ // Threaded through so run() can be driven in-process by tests and by
20
+ // embedders. Without this every command would write to the real
21
+ // process streams regardless of what the caller asked for.
22
+ ...(streams ? { streams } : {}),
23
+ });
24
+ const apiKey = resolveApiKey(config, env);
25
+ const session = await loadSessionMeta();
26
+ const accessToken = await resolveAccessToken(env, session, apiKey, io);
27
+ const client = new KiteClient({
28
+ apiKey,
29
+ accessToken,
30
+ endpoints,
31
+ limiter: new RateLimiter(),
32
+ debug: options.debug ?? false,
33
+ onDebug: (message) => io.note(io.dim(message)),
34
+ });
35
+ const api = new KiteApi(client);
36
+ const instruments = new InstrumentStore(api, env);
37
+ const requireSession = () => {
38
+ if (!client.hasSession()) {
39
+ throw new AuthRequiredError(env === 'sandbox' ? 'No sandbox session. Run `kite login --env sandbox`.' : 'Not logged in.');
40
+ }
41
+ // A session file is absent when credentials came from the environment,
42
+ // which is the normal CI path — synthesise a minimal record.
43
+ if (!session) {
44
+ return {
45
+ userId: 'unknown',
46
+ env,
47
+ apiKey,
48
+ expiresAt: new Date(Date.now() + 3_600_000).toISOString(),
49
+ exchanges: [],
50
+ products: [],
51
+ };
52
+ }
53
+ return session;
54
+ };
55
+ const requireApiSecret = async () => {
56
+ if (env === 'sandbox')
57
+ return SANDBOX_CREDENTIALS.apiSecret;
58
+ const found = await getSecret('api_secret', { env });
59
+ if (!found) {
60
+ throw new KiteCliError('No API secret is stored.', ExitCode.Auth, 'Run `kite login` and paste your API secret when prompted, or set KITE_API_SECRET.');
61
+ }
62
+ return found.value;
63
+ };
64
+ return {
65
+ io,
66
+ config,
67
+ env,
68
+ endpoints,
69
+ client,
70
+ api,
71
+ instruments,
72
+ session,
73
+ options,
74
+ signal,
75
+ requireSession,
76
+ requireApiSecret,
77
+ };
78
+ }
79
+ function resolveApiKey(config, env) {
80
+ const fromEnv = process.env['KITE_API_KEY'];
81
+ if (fromEnv && fromEnv.trim() !== '')
82
+ return fromEnv;
83
+ if (env === 'sandbox')
84
+ return SANDBOX_CREDENTIALS.apiKey;
85
+ if (config.apiKey)
86
+ return config.apiKey;
87
+ // Deliberately not fatal here: `kite login` sets this up, and `kite config`
88
+ // must remain usable before it exists.
89
+ return '';
90
+ }
91
+ async function resolveAccessToken(env, session, apiKey, io) {
92
+ let found;
93
+ try {
94
+ found = await getSecret('access_token', { env });
95
+ }
96
+ catch (err) {
97
+ // A corrupt or wrong-passphrase credential file must not brick the CLI.
98
+ // This runs during context construction for EVERY command, so throwing
99
+ // here would break `kite login` and `kite logout` — the two commands that
100
+ // could actually fix the situation, and the ones the error tells you to run.
101
+ io.warn(err instanceof Error ? err.message : 'Could not read stored credentials.');
102
+ io.warn('Continuing without a session. Run `kite login` to re-authenticate.');
103
+ return undefined;
104
+ }
105
+ if (!found)
106
+ return undefined;
107
+ registerSecret(found.value);
108
+ // An env-supplied token is taken at face value: the caller is a script that
109
+ // knows what it is doing, and we have no metadata to validate against.
110
+ if (found.backend === 'env')
111
+ return found.value;
112
+ if (!session)
113
+ return found.value;
114
+ // The stored token belongs to a different environment or API key — treat it
115
+ // as absent rather than sending a token that will 403.
116
+ if (session.env !== env)
117
+ return undefined;
118
+ if (apiKey && session.apiKey && session.apiKey !== apiKey)
119
+ return undefined;
120
+ // Locally-known expiry is a floor, not a guarantee: a master logout from Kite
121
+ // web kills the token early and is undetectable until a 403 comes back. We
122
+ // still short-circuit the obvious case to save a round trip.
123
+ if (isExpired(session))
124
+ return undefined;
125
+ return found.value;
126
+ }