@botuyo/mcp 0.3.12 → 0.3.16
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/LICENSE +21 -0
- package/README.md +16 -2
- package/dist/__tests__/client.spec.d.ts +5 -0
- package/dist/__tests__/client.spec.js +139 -0
- package/dist/__tests__/client.spec.js.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +25 -7
- package/dist/client.js.map +1 -1
- package/dist/commands/__tests__/credentials.spec.d.ts +5 -0
- package/dist/commands/__tests__/credentials.spec.js +174 -0
- package/dist/commands/__tests__/credentials.spec.js.map +1 -0
- package/dist/commands/auth.js +17 -33
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/credentials.d.ts +38 -4
- package/dist/commands/credentials.js +80 -12
- package/dist/commands/credentials.js.map +1 -1
- package/dist/commands/login.js +26 -56
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/switch_tenant.js +11 -36
- package/dist/commands/switch_tenant.js.map +1 -1
- package/dist/commands/tenants.js +10 -19
- package/dist/commands/tenants.js.map +1 -1
- package/dist/index.js +13 -9
- package/dist/index.js.map +1 -1
- package/dist/tools/__tests__/agent_versions.spec.d.ts +1 -0
- package/dist/tools/__tests__/agent_versions.spec.js +59 -0
- package/dist/tools/__tests__/agent_versions.spec.js.map +1 -0
- package/dist/tools/__tests__/configure_avatar.spec.js +2 -3
- package/dist/tools/__tests__/configure_avatar.spec.js.map +1 -1
- package/dist/tools/configure_avatar.js +2 -3
- package/dist/tools/configure_avatar.js.map +1 -1
- package/dist/tools/example_agent.d.ts +82 -1
- package/dist/tools/example_agent.js +104 -7
- package/dist/tools/example_agent.js.map +1 -1
- package/dist/tools/import_agent_json.js +9 -2
- package/dist/tools/import_agent_json.js.map +1 -1
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/ingest_knowledge_url.d.ts +4 -0
- package/dist/tools/ingest_knowledge_url.js +35 -0
- package/dist/tools/ingest_knowledge_url.js.map +1 -0
- package/dist/tools/list_agent_versions.d.ts +4 -0
- package/dist/tools/list_agent_versions.js +16 -0
- package/dist/tools/list_agent_versions.js.map +1 -0
- package/dist/tools/restore_agent_version.d.ts +4 -0
- package/dist/tools/restore_agent_version.js +18 -0
- package/dist/tools/restore_agent_version.js.map +1 -0
- package/dist/tools/switch_tenant.d.ts +3 -0
- package/dist/tools/switch_tenant.js +17 -5
- package/dist/tools/switch_tenant.js.map +1 -1
- package/package.json +2 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BotUyo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -80,7 +80,8 @@ Use `get_agent_status` to check which channels are connected. It returns a direc
|
|
|
80
80
|
## Build from source
|
|
81
81
|
|
|
82
82
|
```sh
|
|
83
|
-
|
|
83
|
+
git clone https://github.com/MarcoAR1/botuyo-mcp.git
|
|
84
|
+
cd botuyo-mcp
|
|
84
85
|
npm install
|
|
85
86
|
npm run build
|
|
86
87
|
```
|
|
@@ -88,6 +89,19 @@ npm run build
|
|
|
88
89
|
## Test with MCP Inspector
|
|
89
90
|
|
|
90
91
|
```sh
|
|
91
|
-
cd packages/mcp
|
|
92
92
|
BOTUYO_API_KEY=pk_live_... npm run inspect
|
|
93
93
|
```
|
|
94
|
+
|
|
95
|
+
## Contributing
|
|
96
|
+
|
|
97
|
+
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
98
|
+
|
|
99
|
+
Please note that this project follows a [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
100
|
+
|
|
101
|
+
## Security
|
|
102
|
+
|
|
103
|
+
To report a vulnerability, see [SECURITY.md](SECURITY.md).
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
[MIT](LICENSE) © BotUyo
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BotuyoApiClient — Unit tests
|
|
3
|
+
* Tests for error handling, 401 detection, ApiError class
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { BotuyoApiClient, ApiError } from '../client.js';
|
|
7
|
+
// Mock global fetch
|
|
8
|
+
function mockFetch(status, body, ok) {
|
|
9
|
+
const fn = vi.fn().mockResolvedValue({
|
|
10
|
+
status,
|
|
11
|
+
ok: ok ?? (status >= 200 && status < 300),
|
|
12
|
+
text: async () => JSON.stringify(body),
|
|
13
|
+
json: async () => body
|
|
14
|
+
});
|
|
15
|
+
vi.stubGlobal('fetch', fn);
|
|
16
|
+
return fn;
|
|
17
|
+
}
|
|
18
|
+
describe('BotuyoApiClient', () => {
|
|
19
|
+
let client;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
client = new BotuyoApiClient({ apiUrl: 'http://localhost:8080', token: 'test-token' });
|
|
23
|
+
});
|
|
24
|
+
// ── ApiError class ──────────────────────────────────────────────────
|
|
25
|
+
describe('ApiError', () => {
|
|
26
|
+
it('is an instance of Error', () => {
|
|
27
|
+
const err = new ApiError('test', 401);
|
|
28
|
+
expect(err).toBeInstanceOf(Error);
|
|
29
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
30
|
+
});
|
|
31
|
+
it('stores the HTTP status code', () => {
|
|
32
|
+
const err = new ApiError('Unauthorized', 401);
|
|
33
|
+
expect(err.status).toBe(401);
|
|
34
|
+
expect(err.message).toBe('Unauthorized');
|
|
35
|
+
});
|
|
36
|
+
it('has a name of ApiError', () => {
|
|
37
|
+
const err = new ApiError('test', 500);
|
|
38
|
+
expect(err.name).toBe('ApiError');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
// ── handleResponse / 401 detection ──────────────────────────────────
|
|
42
|
+
describe('401 detection', () => {
|
|
43
|
+
it('throws ApiError with status 401 on unauthorized response', async () => {
|
|
44
|
+
mockFetch(401, { success: false, error: 'Invalid or expired token' });
|
|
45
|
+
try {
|
|
46
|
+
await client.get('/api/v1/mcp/agents');
|
|
47
|
+
expect.fail('should have thrown');
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
51
|
+
expect(err.status).toBe(401);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it('throws ApiError with status 403 on forbidden response', async () => {
|
|
55
|
+
mockFetch(403, { success: false, error: 'Forbidden' });
|
|
56
|
+
try {
|
|
57
|
+
await client.get('/api/v1/mcp/agents');
|
|
58
|
+
expect.fail('should have thrown');
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
62
|
+
expect(err.status).toBe(403);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it('throws ApiError with status 500 on server error', async () => {
|
|
66
|
+
mockFetch(500, { success: false, error: 'Internal error' });
|
|
67
|
+
try {
|
|
68
|
+
await client.get('/api/v1/mcp/agents');
|
|
69
|
+
expect.fail('should have thrown');
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
73
|
+
expect(err.status).toBe(500);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
it('does NOT throw on successful 200 responses', async () => {
|
|
77
|
+
mockFetch(200, { success: true, data: { agents: [] } });
|
|
78
|
+
const result = await client.get('/api/v1/mcp/agents');
|
|
79
|
+
expect(result.success).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ── verify() ────────────────────────────────────────────────────────
|
|
83
|
+
describe('verify', () => {
|
|
84
|
+
it('returns AuthInfo on successful /api/auth/me', async () => {
|
|
85
|
+
mockFetch(200, {
|
|
86
|
+
success: true,
|
|
87
|
+
data: {
|
|
88
|
+
user: {
|
|
89
|
+
email: 'test@example.com',
|
|
90
|
+
tenantIds: ['t1'],
|
|
91
|
+
roles: [{ tenantId: 't1', role: 'owner' }]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const info = await client.verify();
|
|
96
|
+
expect(info.email).toBe('test@example.com');
|
|
97
|
+
expect(info.tenantId).toBe('t1');
|
|
98
|
+
expect(info.role).toBe('owner');
|
|
99
|
+
});
|
|
100
|
+
it('throws on 401 from /api/auth/me', async () => {
|
|
101
|
+
mockFetch(401, { success: false, error: 'Token expired' });
|
|
102
|
+
await expect(client.verify()).rejects.toThrow();
|
|
103
|
+
});
|
|
104
|
+
it('caches authInfo after first successful call', async () => {
|
|
105
|
+
const fetchFn = mockFetch(200, {
|
|
106
|
+
success: true,
|
|
107
|
+
data: {
|
|
108
|
+
user: {
|
|
109
|
+
email: 'test@example.com',
|
|
110
|
+
tenantIds: ['t1'],
|
|
111
|
+
roles: [{ tenantId: 't1', role: 'owner' }]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await client.verify();
|
|
116
|
+
await client.verify();
|
|
117
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
// ── Non-JSON responses ──────────────────────────────────────────────
|
|
121
|
+
describe('non-JSON responses', () => {
|
|
122
|
+
it('throws ApiError with status code when response is not JSON', async () => {
|
|
123
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
124
|
+
status: 502,
|
|
125
|
+
ok: false,
|
|
126
|
+
text: async () => '<html>Bad Gateway</html>'
|
|
127
|
+
}));
|
|
128
|
+
try {
|
|
129
|
+
await client.get('/api/v1/mcp/agents');
|
|
130
|
+
expect.fail('should have thrown');
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
134
|
+
expect(err.status).toBe(502);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=client.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.js","sourceRoot":"","sources":["../../src/__tests__/client.spec.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Uses a JWT token directly (obtained via `npx @botuyo/mcp auth` or `npx @botuyo/mcp login`).
|
|
6
6
|
* Requires Node 18+ (native fetch).
|
|
7
7
|
*/
|
|
8
|
+
export declare class ApiError extends Error {
|
|
9
|
+
readonly status: number;
|
|
10
|
+
constructor(message: string, status: number);
|
|
11
|
+
}
|
|
8
12
|
export interface BotuyoClientConfig {
|
|
9
13
|
apiUrl: string;
|
|
10
14
|
token: string;
|
package/dist/client.js
CHANGED
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
* Uses a JWT token directly (obtained via `npx @botuyo/mcp auth` or `npx @botuyo/mcp login`).
|
|
6
6
|
* Requires Node 18+ (native fetch).
|
|
7
7
|
*/
|
|
8
|
+
export class ApiError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
constructor(message, status) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'ApiError';
|
|
13
|
+
this.status = status;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
8
16
|
export class BotuyoApiClient {
|
|
9
17
|
config;
|
|
10
18
|
authInfo = null;
|
|
@@ -82,19 +90,29 @@ export class BotuyoApiClient {
|
|
|
82
90
|
return this.handleResponse(res);
|
|
83
91
|
}
|
|
84
92
|
async handleResponse(res) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
const text = await res.text();
|
|
94
|
+
let json;
|
|
95
|
+
try {
|
|
96
|
+
json = JSON.parse(text);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw new ApiError(`HTTP ${res.status}: ${text.slice(0, 200)}`, res.status);
|
|
100
|
+
}
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
const msg = json.error || `HTTP ${res.status}`;
|
|
103
|
+
throw new ApiError(msg, res.status);
|
|
89
104
|
}
|
|
90
105
|
return json;
|
|
91
106
|
}
|
|
92
107
|
/** Upload a file via multipart POST to the media API */
|
|
93
108
|
async uploadMedia(fileBuffer, fileName, category) {
|
|
109
|
+
// Auto-inject tenantId from JWT so callers don't need to provide it explicitly
|
|
110
|
+
const auth = await this.verify();
|
|
94
111
|
const blob = new Blob([new Uint8Array(fileBuffer)]);
|
|
95
112
|
const formData = new FormData();
|
|
96
113
|
formData.append('file', blob, fileName);
|
|
97
114
|
formData.append('category', category);
|
|
115
|
+
formData.append('tenantId', auth.tenantId);
|
|
98
116
|
const res = await fetch(`${this.config.apiUrl}/api/media/upload`, {
|
|
99
117
|
method: 'POST',
|
|
100
118
|
headers: {
|
|
@@ -114,14 +132,14 @@ export class BotuyoApiClient {
|
|
|
114
132
|
try {
|
|
115
133
|
const json = JSON.parse(text);
|
|
116
134
|
if (!res.ok && !json.success) {
|
|
117
|
-
throw new
|
|
135
|
+
throw new ApiError(json.error || `HTTP ${res.status}`, res.status);
|
|
118
136
|
}
|
|
119
137
|
return json;
|
|
120
138
|
}
|
|
121
139
|
catch (e) {
|
|
122
|
-
if (e instanceof
|
|
140
|
+
if (e instanceof ApiError)
|
|
123
141
|
throw e;
|
|
124
|
-
throw new
|
|
142
|
+
throw new ApiError(`HTTP ${res.status}: ${text.slice(0, 200)}`, res.status);
|
|
125
143
|
}
|
|
126
144
|
}
|
|
127
145
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* credentials.ts — Unit tests
|
|
3
|
+
* Tests for apiUrl persistence, resolveApiUrl, and checkExistingSession
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
// We'll mock fs/promises to avoid touching the real filesystem
|
|
9
|
+
vi.mock('fs/promises', () => ({
|
|
10
|
+
readFile: vi.fn(),
|
|
11
|
+
writeFile: vi.fn(),
|
|
12
|
+
mkdir: vi.fn(),
|
|
13
|
+
unlink: vi.fn()
|
|
14
|
+
}));
|
|
15
|
+
// Import after mocking
|
|
16
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
17
|
+
import { readCredentials, saveCredentials, resolveToken, resolveApiUrl, checkExistingSession } from '../credentials.js';
|
|
18
|
+
const CREDS_PATH = join(homedir(), '.botuyo', 'credentials.json');
|
|
19
|
+
function makeCreds(overrides = {}) {
|
|
20
|
+
return {
|
|
21
|
+
token: 'test-jwt-token',
|
|
22
|
+
tenantId: 'tenant-123',
|
|
23
|
+
tenantName: 'My Tenant',
|
|
24
|
+
role: 'owner',
|
|
25
|
+
email: 'user@test.com',
|
|
26
|
+
savedAt: new Date().toISOString(),
|
|
27
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
28
|
+
apiUrl: 'http://localhost:8080',
|
|
29
|
+
...overrides
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
describe('credentials', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
vi.resetAllMocks();
|
|
35
|
+
// Clean env vars between tests
|
|
36
|
+
delete process.env.BOTUYO_TOKEN;
|
|
37
|
+
delete process.env.BOTUYO_API_URL;
|
|
38
|
+
});
|
|
39
|
+
// ── apiUrl persistence ──────────────────────────────────────────────
|
|
40
|
+
describe('apiUrl in credentials', () => {
|
|
41
|
+
it('saveCredentials includes apiUrl in stored JSON', async () => {
|
|
42
|
+
const creds = makeCreds({ apiUrl: 'http://localhost:8080' });
|
|
43
|
+
await saveCredentials(creds);
|
|
44
|
+
expect(writeFile).toHaveBeenCalledWith(CREDS_PATH, expect.stringContaining('"apiUrl": "http://localhost:8080"'), 'utf8');
|
|
45
|
+
});
|
|
46
|
+
it('readCredentials returns apiUrl from stored JSON', async () => {
|
|
47
|
+
const creds = makeCreds({ apiUrl: 'https://api.botuyo.com' });
|
|
48
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(creds));
|
|
49
|
+
const result = await readCredentials();
|
|
50
|
+
expect(result?.apiUrl).toBe('https://api.botuyo.com');
|
|
51
|
+
});
|
|
52
|
+
it('readCredentials returns null apiUrl for legacy credentials without apiUrl', async () => {
|
|
53
|
+
// Simulate old credentials.json that doesn't have apiUrl
|
|
54
|
+
const legacy = {
|
|
55
|
+
token: 'old-token',
|
|
56
|
+
tenantId: 't1',
|
|
57
|
+
tenantName: 'T1',
|
|
58
|
+
role: 'owner',
|
|
59
|
+
email: 'a@b.com',
|
|
60
|
+
savedAt: new Date().toISOString(),
|
|
61
|
+
expiresAt: new Date(Date.now() + 86400000).toISOString()
|
|
62
|
+
};
|
|
63
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(legacy));
|
|
64
|
+
const result = await readCredentials();
|
|
65
|
+
expect(result).not.toBeNull();
|
|
66
|
+
expect(result?.apiUrl).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
// ── resolveApiUrl ───────────────────────────────────────────────────
|
|
70
|
+
describe('resolveApiUrl', () => {
|
|
71
|
+
it('returns BOTUYO_API_URL env var when set (highest priority)', async () => {
|
|
72
|
+
process.env.BOTUYO_API_URL = 'https://env-override.com';
|
|
73
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(makeCreds({ apiUrl: 'http://localhost:8080' })));
|
|
74
|
+
const url = await resolveApiUrl();
|
|
75
|
+
expect(url).toBe('https://env-override.com');
|
|
76
|
+
});
|
|
77
|
+
it('returns apiUrl from credentials when env var is not set', async () => {
|
|
78
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(makeCreds({ apiUrl: 'http://localhost:8080' })));
|
|
79
|
+
const url = await resolveApiUrl();
|
|
80
|
+
expect(url).toBe('http://localhost:8080');
|
|
81
|
+
});
|
|
82
|
+
it('returns default https://api.botuyo.com when no env var and no credentials', async () => {
|
|
83
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
84
|
+
const url = await resolveApiUrl();
|
|
85
|
+
expect(url).toBe('https://api.botuyo.com');
|
|
86
|
+
});
|
|
87
|
+
it('returns default when credentials exist but apiUrl is missing (legacy)', async () => {
|
|
88
|
+
const legacy = { token: 'x', tenantId: 'y', tenantName: 'z', role: 'a', email: 'b', savedAt: 'c', expiresAt: 'd' };
|
|
89
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(legacy));
|
|
90
|
+
const url = await resolveApiUrl();
|
|
91
|
+
expect(url).toBe('https://api.botuyo.com');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// ── checkExistingSession ────────────────────────────────────────────
|
|
95
|
+
describe('checkExistingSession', () => {
|
|
96
|
+
it('returns null when no credentials exist', async () => {
|
|
97
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
98
|
+
const result = await checkExistingSession('http://localhost:8080', false);
|
|
99
|
+
expect(result).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
it('returns null and clears when credentials are locally expired', async () => {
|
|
102
|
+
const expired = makeCreds({ expiresAt: new Date(Date.now() - 1000).toISOString() });
|
|
103
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(expired));
|
|
104
|
+
const result = await checkExistingSession('http://localhost:8080', false);
|
|
105
|
+
expect(result).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
it('returns credentials when valid and not forced', async () => {
|
|
108
|
+
const valid = makeCreds();
|
|
109
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(valid));
|
|
110
|
+
// Mock global fetch for server verification
|
|
111
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
112
|
+
ok: true,
|
|
113
|
+
json: async () => ({ success: true })
|
|
114
|
+
});
|
|
115
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
116
|
+
const result = await checkExistingSession('http://localhost:8080', false);
|
|
117
|
+
expect(result).not.toBeNull();
|
|
118
|
+
expect(result?.token).toBe('test-jwt-token');
|
|
119
|
+
vi.unstubAllGlobals();
|
|
120
|
+
});
|
|
121
|
+
it('returns null when --force is true even if credentials are valid', async () => {
|
|
122
|
+
const valid = makeCreds();
|
|
123
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(valid));
|
|
124
|
+
const result = await checkExistingSession('http://localhost:8080', true);
|
|
125
|
+
expect(result).toBeNull();
|
|
126
|
+
});
|
|
127
|
+
it('returns null when server rejects the token (401)', async () => {
|
|
128
|
+
const valid = makeCreds();
|
|
129
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(valid));
|
|
130
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
131
|
+
ok: false,
|
|
132
|
+
json: async () => ({ success: false, error: 'Invalid token' })
|
|
133
|
+
});
|
|
134
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
135
|
+
const result = await checkExistingSession('http://localhost:8080', false);
|
|
136
|
+
expect(result).toBeNull();
|
|
137
|
+
vi.unstubAllGlobals();
|
|
138
|
+
});
|
|
139
|
+
it('returns credentials when server is unreachable (network error = assume valid)', async () => {
|
|
140
|
+
const valid = makeCreds();
|
|
141
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(valid));
|
|
142
|
+
const mockFetch = vi.fn().mockRejectedValue(new Error('ECONNREFUSED'));
|
|
143
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
144
|
+
const result = await checkExistingSession('http://localhost:8080', false);
|
|
145
|
+
expect(result).not.toBeNull();
|
|
146
|
+
vi.unstubAllGlobals();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
// ── resolveToken (existing, ensure no regression) ──────────────────
|
|
150
|
+
describe('resolveToken', () => {
|
|
151
|
+
it('returns BOTUYO_TOKEN env var when set', async () => {
|
|
152
|
+
process.env.BOTUYO_TOKEN = 'env-token';
|
|
153
|
+
const token = await resolveToken();
|
|
154
|
+
expect(token).toBe('env-token');
|
|
155
|
+
});
|
|
156
|
+
it('returns token from credentials when env var is not set', async () => {
|
|
157
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(makeCreds()));
|
|
158
|
+
const token = await resolveToken();
|
|
159
|
+
expect(token).toBe('test-jwt-token');
|
|
160
|
+
});
|
|
161
|
+
it('returns null when no credentials and no env var', async () => {
|
|
162
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
163
|
+
const token = await resolveToken();
|
|
164
|
+
expect(token).toBeNull();
|
|
165
|
+
});
|
|
166
|
+
it('returns null and clears when credentials are expired', async () => {
|
|
167
|
+
const expired = makeCreds({ expiresAt: new Date(Date.now() - 1000).toISOString() });
|
|
168
|
+
vi.mocked(readFile).mockResolvedValue(JSON.stringify(expired));
|
|
169
|
+
const token = await resolveToken();
|
|
170
|
+
expect(token).toBeNull();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
//# sourceMappingURL=credentials.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.spec.js","sourceRoot":"","sources":["../../../src/commands/__tests__/credentials.spec.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/auth.js
CHANGED
|
@@ -17,31 +17,23 @@
|
|
|
17
17
|
import http from 'http';
|
|
18
18
|
import { URL } from 'url';
|
|
19
19
|
import { execSync } from 'child_process';
|
|
20
|
-
import {
|
|
20
|
+
import { saveCredentials, checkExistingSession, resolveApiUrl, resolveTenantName } from './credentials.js';
|
|
21
21
|
import os from 'os';
|
|
22
22
|
const ADMIN_URL = process.env.BOTUYO_ADMIN_URL || 'https://botuyo.com';
|
|
23
|
-
const API_URL = process.env.BOTUYO_API_URL || 'https://api.botuyo.com';
|
|
24
23
|
export async function runAuth(args) {
|
|
25
24
|
console.log('\n🤖 BotUyo MCP — Autenticación por Browser\n');
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
console.log(` Tenant: ${existing.tenantName} (${existing.role})`);
|
|
39
|
-
console.log('\n Usá --force para re-autenticarte.');
|
|
40
|
-
console.log(' O usá `npx @botuyo/mcp login` para login por terminal.\n');
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
console.log('⚠️ Tu sesión ya no es válida en el servidor. Vamos a re-autenticarte.\n');
|
|
44
|
-
}
|
|
25
|
+
const API_URL = process.env.BOTUYO_API_URL || await resolveApiUrl();
|
|
26
|
+
const force = args.includes('--force');
|
|
27
|
+
const existing = await checkExistingSession(API_URL, force);
|
|
28
|
+
if (existing) {
|
|
29
|
+
console.log(`✅ Ya estás autenticado como: ${existing.email || 'usuario'}`);
|
|
30
|
+
console.log(` Tenant: ${existing.tenantName} (${existing.role})`);
|
|
31
|
+
console.log('\n Usá --force para re-autenticarte.');
|
|
32
|
+
console.log(' O usá `npx @botuyo/mcp login` para login por terminal.\n');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!force) {
|
|
36
|
+
console.log('⚠️ Sesión expirada o inválida. Vamos a re-autenticarte.\n');
|
|
45
37
|
}
|
|
46
38
|
// Start local callback server
|
|
47
39
|
const { port, waitForCode } = await startCallbackServer();
|
|
@@ -75,20 +67,12 @@ export async function runAuth(args) {
|
|
|
75
67
|
role: tokenData.data.role || 'viewer',
|
|
76
68
|
email: tokenData.data.callerEmail || '',
|
|
77
69
|
savedAt: new Date().toISOString(),
|
|
78
|
-
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // 7 days
|
|
70
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days
|
|
71
|
+
apiUrl: API_URL
|
|
79
72
|
};
|
|
80
|
-
// Resolve the real tenant name via
|
|
73
|
+
// Resolve the real tenant name via shared helper
|
|
81
74
|
if (creds.tenantName === creds.tenantId) {
|
|
82
|
-
|
|
83
|
-
const tRes = await fetch(`${API_URL}/api/tenants/${creds.tenantId}`, {
|
|
84
|
-
headers: { Authorization: `Bearer ${creds.token}` }
|
|
85
|
-
});
|
|
86
|
-
const tData = (await tRes.json());
|
|
87
|
-
const name = tData.data?.name || tData.data?.tenant?.name;
|
|
88
|
-
if (name)
|
|
89
|
-
creds.tenantName = name;
|
|
90
|
-
}
|
|
91
|
-
catch { /* keep ID as fallback */ }
|
|
75
|
+
creds.tenantName = await resolveTenantName(API_URL, creds.token, creds.tenantId);
|
|
92
76
|
}
|
|
93
77
|
await saveCredentials(creds);
|
|
94
78
|
console.log(`\n✅ ¡Autenticado exitosamente!`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|