minara 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 (61) hide show
  1. package/README.md +246 -0
  2. package/bin/minara.js +2 -0
  3. package/dist/api/auth.d.ts +30 -0
  4. package/dist/api/auth.js +46 -0
  5. package/dist/api/chat.d.ts +19 -0
  6. package/dist/api/chat.js +54 -0
  7. package/dist/api/client.d.ts +16 -0
  8. package/dist/api/client.js +133 -0
  9. package/dist/api/copytrade.d.ts +19 -0
  10. package/dist/api/copytrade.js +37 -0
  11. package/dist/api/crosschain.d.ts +19 -0
  12. package/dist/api/crosschain.js +43 -0
  13. package/dist/api/limitorder.d.ts +13 -0
  14. package/dist/api/limitorder.js +25 -0
  15. package/dist/api/perps.d.ts +27 -0
  16. package/dist/api/perps.js +53 -0
  17. package/dist/api/tokens.d.ts +20 -0
  18. package/dist/api/tokens.js +41 -0
  19. package/dist/api/tradeconfig.d.ts +9 -0
  20. package/dist/api/tradeconfig.js +17 -0
  21. package/dist/auth-refresh.d.ts +15 -0
  22. package/dist/auth-refresh.js +94 -0
  23. package/dist/commands/account.d.ts +2 -0
  24. package/dist/commands/account.js +44 -0
  25. package/dist/commands/assets.d.ts +2 -0
  26. package/dist/commands/assets.js +26 -0
  27. package/dist/commands/chat.d.ts +2 -0
  28. package/dist/commands/chat.js +184 -0
  29. package/dist/commands/config.d.ts +2 -0
  30. package/dist/commands/config.js +48 -0
  31. package/dist/commands/copy-trade.d.ts +2 -0
  32. package/dist/commands/copy-trade.js +190 -0
  33. package/dist/commands/deposit.d.ts +2 -0
  34. package/dist/commands/deposit.js +101 -0
  35. package/dist/commands/discover.d.ts +2 -0
  36. package/dist/commands/discover.js +88 -0
  37. package/dist/commands/limit-order.d.ts +2 -0
  38. package/dist/commands/limit-order.js +151 -0
  39. package/dist/commands/login.d.ts +2 -0
  40. package/dist/commands/login.js +189 -0
  41. package/dist/commands/logout.d.ts +2 -0
  42. package/dist/commands/logout.js +31 -0
  43. package/dist/commands/perps.d.ts +2 -0
  44. package/dist/commands/perps.js +280 -0
  45. package/dist/commands/swap.d.ts +2 -0
  46. package/dist/commands/swap.js +100 -0
  47. package/dist/commands/transfer.d.ts +2 -0
  48. package/dist/commands/transfer.js +76 -0
  49. package/dist/commands/withdraw.d.ts +2 -0
  50. package/dist/commands/withdraw.js +117 -0
  51. package/dist/config.d.ts +11 -0
  52. package/dist/config.js +67 -0
  53. package/dist/index.d.ts +2 -0
  54. package/dist/index.js +54 -0
  55. package/dist/oauth-server.d.ts +38 -0
  56. package/dist/oauth-server.js +136 -0
  57. package/dist/types.d.ts +246 -0
  58. package/dist/types.js +13 -0
  59. package/dist/utils.d.ts +12 -0
  60. package/dist/utils.js +62 -0
  61. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ <p align="center">
2
+ <h1 align="center">Minara CLI</h1>
3
+ <p align="center">
4
+ Your AI-powered digital finance assistant — from the terminal.
5
+ <br />
6
+ Trade, swap, chat, and manage your portfolio without leaving the command line.
7
+ </p>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://www.npmjs.com/package/minara"><img alt="npm version" src="https://img.shields.io/npm/v/minara?color=cb3837&label=npm"></a>
12
+ <a href="https://github.com/user/minara-cli/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
13
+ <img alt="Node.js" src="https://img.shields.io/badge/node-%3E%3D18-brightgreen">
14
+ <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6">
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## Features
20
+
21
+ - **Multi-method Login** — Email verification code, Google OAuth, or Apple ID
22
+ - **Deposit & Withdraw** — View deposit addresses across chains, withdraw to external wallets
23
+ - **Asset Management** — View wallet balances across all supported chains
24
+ - **AI Chat** — Stream conversations with Minara AI, with thinking and deep-research modes
25
+ - **Spot Trading** — Cross-chain token swaps with dry-run simulation
26
+ - **Perpetual Futures** — Deposit, withdraw, place/cancel orders, manage leverage (Hyperliquid)
27
+ - **Limit Orders** — Create, list, and cancel price-triggered orders
28
+ - **Copy Trading** — Follow wallet addresses with configurable bots
29
+ - **Market Discovery** — Trending tokens, Fear & Greed Index, Bitcoin metrics
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install -g minara
35
+ ```
36
+
37
+ Or run without installing:
38
+
39
+ ```bash
40
+ npx minara --help
41
+ ```
42
+
43
+ **Requires Node.js >= 18**
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # Login (interactive — choose email, Google, or Apple)
49
+ minara login
50
+
51
+ # Check your account
52
+ minara account
53
+
54
+ # View deposit addresses
55
+ minara deposit
56
+
57
+ # Chat with Minara AI
58
+ minara chat "What's the best DeFi yield right now?"
59
+
60
+ # Swap tokens
61
+ minara swap
62
+
63
+ # View trending tokens
64
+ minara discover trending
65
+ ```
66
+
67
+ ## Commands
68
+
69
+ ### Auth & Account
70
+
71
+ | Command | Description |
72
+ |---------|-------------|
73
+ | `minara login` | Login via email, Google, or Apple ID |
74
+ | `minara logout` | Logout and clear local credentials |
75
+ | `minara account` | View your account info and wallet addresses |
76
+
77
+ ```bash
78
+ minara login # Interactive method selection
79
+ minara login -e user@mail.com # Email verification code
80
+ minara login --google # Google OAuth (opens browser)
81
+ minara login --apple # Apple ID (opens browser)
82
+ ```
83
+
84
+ ### Wallet & Funds
85
+
86
+ | Command | Description |
87
+ |---------|-------------|
88
+ | `minara assets` | View wallet balances across all chains |
89
+ | `minara deposit` | Show deposit addresses and supported networks |
90
+ | `minara withdraw` | Withdraw tokens to an external wallet |
91
+
92
+ ```bash
93
+ minara deposit
94
+ minara withdraw -c solana -t <token> -a 10 --to <address>
95
+ minara withdraw # Interactive mode
96
+ ```
97
+
98
+ ### Spot Trading
99
+
100
+ | Command | Description |
101
+ |---------|-------------|
102
+ | `minara swap` | Swap tokens (cross-chain) |
103
+ | `minara transfer` | Transfer tokens to another address |
104
+
105
+ ```bash
106
+ minara swap # Interactive
107
+ minara swap -c solana -s buy -t <token> -a 100
108
+ minara swap --dry-run # Simulate without executing
109
+ ```
110
+
111
+ ### Perpetual Futures
112
+
113
+ | Command | Description |
114
+ |---------|-------------|
115
+ | `minara perps deposit` | Deposit USDC to Hyperliquid perps account |
116
+ | `minara perps withdraw` | Withdraw USDC from perps account |
117
+ | `minara perps positions` | View all open positions |
118
+ | `minara perps order` | Place an order (interactive builder) |
119
+ | `minara perps cancel` | Cancel open orders |
120
+ | `minara perps leverage` | Update leverage for a symbol |
121
+ | `minara perps trades` | View completed trade history |
122
+ | `minara perps fund-records` | View fund deposit/withdrawal records |
123
+
124
+ ```bash
125
+ minara perps deposit -a 100 # Deposit 100 USDC to perps
126
+ minara perps withdraw -a 50 # Withdraw 50 USDC from perps
127
+ minara perps positions # List current positions
128
+ minara perps order # Interactive: choose symbol, side, size, price
129
+ minara perps leverage # Interactive: set leverage for a trading pair
130
+ ```
131
+
132
+ ### Limit Orders
133
+
134
+ | Command | Description |
135
+ |---------|-------------|
136
+ | `minara limit-order create` | Create a price-triggered limit order |
137
+ | `minara limit-order list` | List all your limit orders |
138
+ | `minara limit-order cancel <id>` | Cancel a specific order by ID |
139
+
140
+ ```bash
141
+ minara limit-order create # Interactive: token, price, side, amount, expiry
142
+ minara limit-order list # Show all orders with status
143
+ minara limit-order cancel abc123 # Cancel order by ID
144
+ ```
145
+
146
+ ### Copy Trading
147
+
148
+ | Command | Description |
149
+ |---------|-------------|
150
+ | `minara copy-trade create` | Create a new copy-trade bot |
151
+ | `minara copy-trade list` | List all copy-trade bots |
152
+ | `minara copy-trade start <id>` | Start a paused bot |
153
+ | `minara copy-trade stop <id>` | Pause a running bot |
154
+ | `minara copy-trade delete <id>` | Delete a bot permanently |
155
+
156
+ ```bash
157
+ minara copy-trade create # Interactive: target wallet, chain, amount, options
158
+ minara copy-trade list # Show all bots with status
159
+ minara copy-trade start abc123 # Resume a paused bot
160
+ minara copy-trade stop abc123 # Pause a running bot
161
+ ```
162
+
163
+ ### AI Chat
164
+
165
+ | Command | Description |
166
+ |---------|-------------|
167
+ | `minara chat [message]` | Send a message (or enter interactive mode) |
168
+ | `minara chat --list` | List all your conversations |
169
+ | `minara chat --history <chatId>` | View messages in a conversation |
170
+
171
+ ```bash
172
+ minara chat "What is the current BTC price?" # Single question, streamed answer
173
+ minara chat # Enter interactive REPL mode
174
+ minara chat --thinking "Analyze ETH outlook" # Enable reasoning mode
175
+ minara chat --deep-research "DeFi yield trends"# Deep research mode
176
+ minara chat --list # List past conversations
177
+ minara chat --history <chatId> # Replay a specific conversation
178
+ ```
179
+
180
+ ### Market Discovery
181
+
182
+ | Command | Description |
183
+ |---------|-------------|
184
+ | `minara discover trending` | View currently trending tokens |
185
+ | `minara discover search <keyword>` | Search for tokens or stocks by name |
186
+ | `minara discover fear-greed` | View the crypto Fear & Greed Index |
187
+ | `minara discover btc-metrics` | View Bitcoin on-chain and market metrics |
188
+
189
+ ```bash
190
+ minara discover trending # Top trending tokens right now
191
+ minara discover search SOL # Search for tokens matching "SOL"
192
+ minara discover fear-greed # Current market sentiment index
193
+ minara discover btc-metrics # Bitcoin hashrate, supply, dominance, etc.
194
+ ```
195
+
196
+ ### Configuration
197
+
198
+ | Command | Description |
199
+ |---------|-------------|
200
+ | `minara config` | View or update CLI settings (e.g. API base URL) |
201
+
202
+ ## Supported Chains
203
+
204
+ Ethereum, Base, Arbitrum, Optimism, Polygon, Avalanche, Solana, BSC, Berachain, Blast, Manta, Mode, Sonic, and more.
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ # Install dependencies
210
+ npm install
211
+
212
+ # Build
213
+ npm run build
214
+
215
+ # Watch mode
216
+ npm run dev
217
+
218
+ # Run locally
219
+ node dist/index.js --help
220
+
221
+ # Link globally for testing
222
+ npm link
223
+ minara --help
224
+ ```
225
+
226
+ ## Testing
227
+
228
+ Test suite built with [Vitest](https://vitest.dev/) — 119 tests covering unit, API, and command integration layers.
229
+
230
+ ```bash
231
+ npm test # Run all tests
232
+ npm run test:watch # Watch mode
233
+ npm run test:coverage # With coverage report
234
+ ```
235
+
236
+ ## Security
237
+
238
+ - Credentials are stored in `~/.minara/credentials.json` with `0600` file permissions
239
+ - The `~/.minara/` directory is created with `0700` permissions
240
+ - Tokens are never logged or printed to the console
241
+ - OAuth login uses a temporary local server that shuts down after the callback
242
+ - Non-TTY environments (CI/pipes) skip interactive prompts and return errors directly
243
+
244
+ ## License
245
+
246
+ [MIT](LICENSE)
package/bin/minara.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,30 @@
1
+ import type { EmailCodeDto, EmailVerifyDto, AuthUser, FavoriteTokensPayload, OAuthProvider } from '../types.js';
2
+ /** Send email verification code */
3
+ export declare function sendEmailCode(dto: EmailCodeDto): Promise<import("../types.js").ApiResponse<void>>;
4
+ /** Verify email code → returns user + access_token */
5
+ export declare function verifyEmailCode(dto: EmailVerifyDto): Promise<import("../types.js").ApiResponse<AuthUser>>;
6
+ /** Get current user info */
7
+ export declare function getCurrentUser(token: string): Promise<import("../types.js").ApiResponse<AuthUser>>;
8
+ /** Logout */
9
+ export declare function logout(token: string): Promise<import("../types.js").ApiResponse<void>>;
10
+ /** Get OAuth authorization URL */
11
+ export declare function getOAuthUrl(provider: OAuthProvider, redirectUri: string): Promise<import("../types.js").ApiResponse<{
12
+ url: string;
13
+ }>>;
14
+ /**
15
+ * Exchange OAuth callback params for an access token.
16
+ * Some providers require a separate exchange step.
17
+ */
18
+ export declare function oauthCallback(provider: OAuthProvider, params: Record<string, string>): Promise<import("../types.js").ApiResponse<AuthUser>>;
19
+ /** Delete account */
20
+ export declare function deleteAccount(token: string): Promise<import("../types.js").ApiResponse<void>>;
21
+ /** Get favorite tokens */
22
+ export declare function getFavoriteTokens(token: string): Promise<import("../types.js").ApiResponse<{
23
+ tokens: string[];
24
+ }>>;
25
+ /** Add favorite tokens */
26
+ export declare function addFavoriteTokens(token: string, payload: FavoriteTokensPayload): Promise<import("../types.js").ApiResponse<{
27
+ tokens: string[];
28
+ }>>;
29
+ /** Get invite history */
30
+ export declare function getInviteHistory(token: string): Promise<import("../types.js").ApiResponse<unknown>>;
@@ -0,0 +1,46 @@
1
+ import { get, post, del } from './client.js';
2
+ /** Send email verification code */
3
+ export function sendEmailCode(dto) {
4
+ return post('/auth/email/code', { body: dto });
5
+ }
6
+ /** Verify email code → returns user + access_token */
7
+ export function verifyEmailCode(dto) {
8
+ return post('/auth/email/verify', { body: dto });
9
+ }
10
+ /** Get current user info */
11
+ export function getCurrentUser(token) {
12
+ return get('/auth/me', { token });
13
+ }
14
+ /** Logout */
15
+ export function logout(token) {
16
+ return post('/auth/logout', { token });
17
+ }
18
+ /** Get OAuth authorization URL */
19
+ export function getOAuthUrl(provider, redirectUri) {
20
+ return get(`/auth/${provider}/authorize`, {
21
+ query: { redirect_uri: redirectUri },
22
+ });
23
+ }
24
+ /**
25
+ * Exchange OAuth callback params for an access token.
26
+ * Some providers require a separate exchange step.
27
+ */
28
+ export function oauthCallback(provider, params) {
29
+ return get(`/auth/${provider}/callback`, { query: params });
30
+ }
31
+ /** Delete account */
32
+ export function deleteAccount(token) {
33
+ return del('/auth/delete-account', { token });
34
+ }
35
+ /** Get favorite tokens */
36
+ export function getFavoriteTokens(token) {
37
+ return get('/auth/favorite-tokens', { token });
38
+ }
39
+ /** Add favorite tokens */
40
+ export function addFavoriteTokens(token, payload) {
41
+ return post('/auth/favorite-tokens', { token, body: payload });
42
+ }
43
+ /** Get invite history */
44
+ export function getInviteHistory(token) {
45
+ return get('/auth/invite-history', { token });
46
+ }
@@ -0,0 +1,19 @@
1
+ import type { ChatRequestDTO, ChatInfo, ChatMemory } from '../types.js';
2
+ /** Send chat message — returns SSE stream (raw Response) */
3
+ export declare function sendChatStream(token: string, dto: ChatRequestDTO): Promise<Response>;
4
+ /** Stop a running chat */
5
+ export declare function stopChat(token: string, messageId: string): Promise<import("../types.js").ApiResponse<void>>;
6
+ /** List chats */
7
+ export declare function listChats(token: string, limit?: number, offset?: number): Promise<import("../types.js").ApiResponse<ChatInfo[]>>;
8
+ /** Get chat detail */
9
+ export declare function getChat(token: string, chatId: string): Promise<import("../types.js").ApiResponse<ChatInfo>>;
10
+ /** Get chat memories (messages) */
11
+ export declare function getMemories(token: string, chatId: string, limit?: number, nextCursor?: string): Promise<import("../types.js").ApiResponse<ChatMemory[]>>;
12
+ /** Update chat name */
13
+ export declare function updateChatName(token: string, chatId: string, name: string): Promise<import("../types.js").ApiResponse<void>>;
14
+ /** Delete chat */
15
+ export declare function deleteChat(token: string, chatId: string): Promise<import("../types.js").ApiResponse<void>>;
16
+ /** Search chats */
17
+ export declare function searchChats(token: string, query: string, limit?: number, offset?: number): Promise<import("../types.js").ApiResponse<unknown>>;
18
+ /** Get available chat models */
19
+ export declare function getChatModels(token: string): Promise<import("../types.js").ApiResponse<unknown>>;
@@ -0,0 +1,54 @@
1
+ import { get, post, put, del } from './client.js';
2
+ import { loadConfig } from '../config.js';
3
+ /** Send chat message — returns SSE stream (raw Response) */
4
+ export async function sendChatStream(token, dto) {
5
+ const config = loadConfig();
6
+ const base = config.baseUrl.replace(/\/$/, '');
7
+ const url = `${base}/v1/chat`;
8
+ const res = await fetch(url, {
9
+ method: 'POST',
10
+ headers: {
11
+ 'Content-Type': 'application/json',
12
+ 'Accept': 'text/event-stream',
13
+ 'Authorization': `Bearer ${token}`,
14
+ 'origin': 'https://minara.ai',
15
+ },
16
+ body: JSON.stringify(dto),
17
+ });
18
+ return res;
19
+ }
20
+ /** Stop a running chat */
21
+ export function stopChat(token, messageId) {
22
+ return post('/v1/chat/stop', { token, query: { messageId } });
23
+ }
24
+ /** List chats */
25
+ export function listChats(token, limit = 20, offset = 0) {
26
+ return get('/v1/chats', { token, query: { limit, offset } });
27
+ }
28
+ /** Get chat detail */
29
+ export function getChat(token, chatId) {
30
+ return get(`/v1/chat/${encodeURIComponent(chatId)}`, { token });
31
+ }
32
+ /** Get chat memories (messages) */
33
+ export function getMemories(token, chatId, limit, nextCursor) {
34
+ return get(`/v1/chat/${encodeURIComponent(chatId)}/memories`, {
35
+ token,
36
+ query: { limit, nextCursor },
37
+ });
38
+ }
39
+ /** Update chat name */
40
+ export function updateChatName(token, chatId, name) {
41
+ return put(`/v1/chat/${encodeURIComponent(chatId)}`, { token, body: { name } });
42
+ }
43
+ /** Delete chat */
44
+ export function deleteChat(token, chatId) {
45
+ return del(`/v1/chat/${encodeURIComponent(chatId)}`, { token });
46
+ }
47
+ /** Search chats */
48
+ export function searchChats(token, query, limit = 10, offset = 0) {
49
+ return get('/v1/chat/search', { token, query: { query, limit, offset } });
50
+ }
51
+ /** Get available chat models */
52
+ export function getChatModels(token) {
53
+ return get('/v1/chat/models', { token });
54
+ }
@@ -0,0 +1,16 @@
1
+ import type { ApiResponse } from '../types.js';
2
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
3
+ interface RequestOptions {
4
+ method?: HttpMethod;
5
+ body?: unknown;
6
+ query?: Record<string, string | number | undefined>;
7
+ token?: string;
8
+ headers?: Record<string, string>;
9
+ }
10
+ export declare function request<T>(path: string, opts?: RequestOptions): Promise<ApiResponse<T>>;
11
+ export declare function get<T>(path: string, opts?: Omit<RequestOptions, 'method'>): Promise<ApiResponse<T>>;
12
+ export declare function post<T>(path: string, opts?: Omit<RequestOptions, 'method'>): Promise<ApiResponse<T>>;
13
+ export declare function put<T>(path: string, opts?: Omit<RequestOptions, 'method'>): Promise<ApiResponse<T>>;
14
+ export declare function del<T>(path: string, opts?: Omit<RequestOptions, 'method'>): Promise<ApiResponse<T>>;
15
+ export declare function patch<T>(path: string, opts?: Omit<RequestOptions, 'method'>): Promise<ApiResponse<T>>;
16
+ export {};
@@ -0,0 +1,133 @@
1
+ import { loadConfig } from '../config.js';
2
+ function buildUrl(path, query) {
3
+ const config = loadConfig();
4
+ const base = config.baseUrl.replace(/\/$/, '');
5
+ const url = new URL(`${base}${path}`);
6
+ if (query) {
7
+ for (const [k, v] of Object.entries(query)) {
8
+ if (v !== undefined && v !== '') {
9
+ url.searchParams.set(k, String(v));
10
+ }
11
+ }
12
+ }
13
+ return url.toString();
14
+ }
15
+ // ── Core request implementation ───────────────────────────────────────────
16
+ /**
17
+ * @param isRetry When true, skip the 401 re-auth handler to prevent loops.
18
+ */
19
+ async function requestImpl(path, opts, isRetry) {
20
+ const { method = 'GET', body, query, token, headers: extraHeaders } = opts;
21
+ const url = buildUrl(path, query);
22
+ const headers = {
23
+ 'Content-Type': 'application/json',
24
+ 'Accept': 'application/json',
25
+ ...extraHeaders,
26
+ };
27
+ if (token) {
28
+ headers['Authorization'] = `Bearer ${token}`;
29
+ }
30
+ const init = { method, headers };
31
+ if (body && method !== 'GET') {
32
+ init.body = JSON.stringify(body);
33
+ }
34
+ try {
35
+ const res = await fetch(url, init);
36
+ // ── 401 interception ──────────────────────────────────────────────
37
+ // Only trigger when: (1) authenticated request, (2) not already a retry,
38
+ // (3) running in an interactive terminal (not piped / CI).
39
+ if (res.status === 401 && token && !isRetry) {
40
+ return handleAuthExpired(path, opts);
41
+ }
42
+ const text = await res.text();
43
+ let json;
44
+ try {
45
+ json = JSON.parse(text);
46
+ }
47
+ catch {
48
+ // non-JSON response
49
+ if (!res.ok) {
50
+ return { success: false, error: { code: res.status, message: text || res.statusText } };
51
+ }
52
+ return { success: true, data: text };
53
+ }
54
+ if (!res.ok) {
55
+ const errBody = json;
56
+ return {
57
+ success: false,
58
+ error: {
59
+ code: res.status,
60
+ message: (errBody.message ?? errBody.error ?? res.statusText),
61
+ },
62
+ };
63
+ }
64
+ // Adapt: if the API wraps data in { data: ... } or returns directly
65
+ const data = json.data ?? json;
66
+ return { success: true, data: data };
67
+ }
68
+ catch (err) {
69
+ const message = err instanceof Error ? err.message : String(err);
70
+ return { success: false, error: { code: 0, message } };
71
+ }
72
+ }
73
+ // ── 401 handler ───────────────────────────────────────────────────────────
74
+ /**
75
+ * Called when an authenticated request returns 401.
76
+ *
77
+ * - In a TTY (interactive terminal): prompts the user to re-login, then
78
+ * retries the original request with the fresh token.
79
+ * - In a non-TTY (pipe / CI): returns a friendly error immediately.
80
+ *
81
+ * Uses dynamic `import()` for `auth-refresh.ts` to break the circular
82
+ * dependency chain: client → auth-refresh → api/auth → client.
83
+ */
84
+ async function handleAuthExpired(path, opts) {
85
+ // Non-interactive environments: skip prompts
86
+ if (!process.stdin.isTTY) {
87
+ return {
88
+ success: false,
89
+ error: {
90
+ code: 401,
91
+ message: 'Session expired. Run `minara login` to refresh your credentials.',
92
+ },
93
+ };
94
+ }
95
+ try {
96
+ // Dynamic import — only loaded when needed, avoids circular deps
97
+ const { attemptReAuth } = await import('../auth-refresh.js');
98
+ const newToken = await attemptReAuth();
99
+ if (newToken) {
100
+ // Retry the original request with the new token (isRetry = true)
101
+ return requestImpl(path, { ...opts, token: newToken }, true);
102
+ }
103
+ }
104
+ catch {
105
+ // Module load failure or unexpected error — fall through
106
+ }
107
+ return {
108
+ success: false,
109
+ error: {
110
+ code: 401,
111
+ message: 'Session expired. Run `minara login` to refresh your credentials.',
112
+ },
113
+ };
114
+ }
115
+ // ── Public API ────────────────────────────────────────────────────────────
116
+ export async function request(path, opts = {}) {
117
+ return requestImpl(path, opts, false);
118
+ }
119
+ export function get(path, opts) {
120
+ return request(path, { ...opts, method: 'GET' });
121
+ }
122
+ export function post(path, opts) {
123
+ return request(path, { ...opts, method: 'POST' });
124
+ }
125
+ export function put(path, opts) {
126
+ return request(path, { ...opts, method: 'PUT' });
127
+ }
128
+ export function del(path, opts) {
129
+ return request(path, { ...opts, method: 'DELETE' });
130
+ }
131
+ export function patch(path, opts) {
132
+ return request(path, { ...opts, method: 'PATCH' });
133
+ }
@@ -0,0 +1,19 @@
1
+ import type { CreateCopyTradeDto, UpdateCopyTradeDto, CopyTradeInfo } from '../types.js';
2
+ /** Create copy trade */
3
+ export declare function createCopyTrade(token: string, dto: CreateCopyTradeDto): Promise<import("../types.js").ApiResponse<CopyTradeInfo>>;
4
+ /** List user's copy trades */
5
+ export declare function listCopyTrades(token: string): Promise<import("../types.js").ApiResponse<CopyTradeInfo[]>>;
6
+ /** Get copy trade by ID */
7
+ export declare function getCopyTrade(token: string, id: string): Promise<import("../types.js").ApiResponse<CopyTradeInfo>>;
8
+ /** Update copy trade */
9
+ export declare function updateCopyTrade(token: string, id: string, dto: UpdateCopyTradeDto): Promise<import("../types.js").ApiResponse<CopyTradeInfo>>;
10
+ /** Delete copy trade */
11
+ export declare function deleteCopyTrade(token: string, id: string): Promise<import("../types.js").ApiResponse<void>>;
12
+ /** Start copy trade */
13
+ export declare function startCopyTrade(token: string, id: string): Promise<import("../types.js").ApiResponse<void>>;
14
+ /** Stop copy trade */
15
+ export declare function stopCopyTrade(token: string, id: string): Promise<import("../types.js").ApiResponse<void>>;
16
+ /** Get copy trade activity */
17
+ export declare function getCopyTradeActivity(token: string, id: string): Promise<import("../types.js").ApiResponse<unknown>>;
18
+ /** Get copy trade PnL chart */
19
+ export declare function getCopyTradePnl(token: string, id: string): Promise<import("../types.js").ApiResponse<unknown>>;
@@ -0,0 +1,37 @@
1
+ import { get, post, patch, del } from './client.js';
2
+ /** Create copy trade */
3
+ export function createCopyTrade(token, dto) {
4
+ return post('/copy-trade', { token, body: dto });
5
+ }
6
+ /** List user's copy trades */
7
+ export function listCopyTrades(token) {
8
+ return get('/copy-trade', { token });
9
+ }
10
+ /** Get copy trade by ID */
11
+ export function getCopyTrade(token, id) {
12
+ return get(`/copy-trade/${encodeURIComponent(id)}`, { token });
13
+ }
14
+ /** Update copy trade */
15
+ export function updateCopyTrade(token, id, dto) {
16
+ return patch(`/copy-trade/${encodeURIComponent(id)}`, { token, body: dto });
17
+ }
18
+ /** Delete copy trade */
19
+ export function deleteCopyTrade(token, id) {
20
+ return del(`/copy-trade/${encodeURIComponent(id)}`, { token });
21
+ }
22
+ /** Start copy trade */
23
+ export function startCopyTrade(token, id) {
24
+ return patch(`/copy-trade/${encodeURIComponent(id)}/start`, { token });
25
+ }
26
+ /** Stop copy trade */
27
+ export function stopCopyTrade(token, id) {
28
+ return patch(`/copy-trade/${encodeURIComponent(id)}/stop`, { token });
29
+ }
30
+ /** Get copy trade activity */
31
+ export function getCopyTradeActivity(token, id) {
32
+ return get(`/copy-trade/${encodeURIComponent(id)}/activity`, { token });
33
+ }
34
+ /** Get copy trade PnL chart */
35
+ export function getCopyTradePnl(token, id) {
36
+ return get(`/copy-trade/${encodeURIComponent(id)}/pnl/chart`, { token });
37
+ }
@@ -0,0 +1,19 @@
1
+ import type { CrossChainSwapDto, CrossChainTransferDto, CrossChainActivitiesDto } from '../types.js';
2
+ /** Get cross-chain account info */
3
+ export declare function getAccount(token: string): Promise<import("../types.js").ApiResponse<unknown>>;
4
+ /** Get wallet assets */
5
+ export declare function getAssets(token: string): Promise<import("../types.js").ApiResponse<unknown>>;
6
+ /** Execute a single swap */
7
+ export declare function swap(token: string, dto: CrossChainSwapDto): Promise<import("../types.js").ApiResponse<unknown>>;
8
+ /** Execute multiple swaps */
9
+ export declare function swaps(token: string, swapList: CrossChainSwapDto[]): Promise<import("../types.js").ApiResponse<unknown>>;
10
+ /** Simulate swaps (dry-run) */
11
+ export declare function swapsSimulate(token: string, swapList: CrossChainSwapDto[]): Promise<import("../types.js").ApiResponse<unknown>>;
12
+ /** Transfer tokens */
13
+ export declare function transfer(token: string, dto: CrossChainTransferDto): Promise<import("../types.js").ApiResponse<unknown>>;
14
+ /** Get activities */
15
+ export declare function getActivities(token: string, dto: CrossChainActivitiesDto): Promise<import("../types.js").ApiResponse<unknown>>;
16
+ /** Get PnL history */
17
+ export declare function getPnlHistory(token: string, type: string): Promise<import("../types.js").ApiResponse<unknown>>;
18
+ /** Check transaction statuses */
19
+ export declare function getStatuses(token: string, transactionIds: string[]): Promise<import("../types.js").ApiResponse<unknown>>;
@@ -0,0 +1,43 @@
1
+ import { get, post } from './client.js';
2
+ /** Get cross-chain account info */
3
+ export function getAccount(token) {
4
+ return get('/v1/tx/cross-chain/account', { token });
5
+ }
6
+ /** Get wallet assets */
7
+ export function getAssets(token) {
8
+ return get('/v1/tx/cross-chain/assets', { token });
9
+ }
10
+ /** Execute a single swap */
11
+ export function swap(token, dto) {
12
+ return post('/v1/tx/cross-chain/swap', { token, body: dto });
13
+ }
14
+ /** Execute multiple swaps */
15
+ export function swaps(token, swapList) {
16
+ return post('/v1/tx/cross-chain/swaps', {
17
+ token,
18
+ body: { swaps: swapList },
19
+ });
20
+ }
21
+ /** Simulate swaps (dry-run) */
22
+ export function swapsSimulate(token, swapList) {
23
+ return post('/v1/tx/cross-chain/swaps-simulate', {
24
+ token,
25
+ body: { swaps: swapList },
26
+ });
27
+ }
28
+ /** Transfer tokens */
29
+ export function transfer(token, dto) {
30
+ return post('/v1/tx/cross-chain/transfer', { token, body: dto });
31
+ }
32
+ /** Get activities */
33
+ export function getActivities(token, dto) {
34
+ return post('/v1/tx/cross-chain/activities', { token, body: dto });
35
+ }
36
+ /** Get PnL history */
37
+ export function getPnlHistory(token, type) {
38
+ return get('/v1/tx/cross-chain/pnl/history', { token, query: { type } });
39
+ }
40
+ /** Check transaction statuses */
41
+ export function getStatuses(token, transactionIds) {
42
+ return post('/v1/tx/cross-chain/statuses', { token, body: { transactionIds } });
43
+ }