@lindblad/complai-mcp 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.
- package/README.md +303 -0
- package/dist/api/complai-client.d.ts +46 -0
- package/dist/api/complai-client.d.ts.map +1 -0
- package/dist/api/complai-client.js +113 -0
- package/dist/api/complai-client.js.map +1 -0
- package/dist/auth/device-auth.d.ts +98 -0
- package/dist/auth/device-auth.d.ts.map +1 -0
- package/dist/auth/device-auth.js +274 -0
- package/dist/auth/device-auth.js.map +1 -0
- package/dist/auth/pkce-auth.d.ts +67 -0
- package/dist/auth/pkce-auth.d.ts.map +1 -0
- package/dist/auth/pkce-auth.js +311 -0
- package/dist/auth/pkce-auth.js.map +1 -0
- package/dist/auth/token-manager.d.ts +58 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +131 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/config/config-loader.d.ts +21 -0
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/config/config-loader.js +152 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +483 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/compliance-brief.d.ts +8 -0
- package/dist/tools/compliance-brief.d.ts.map +1 -0
- package/dist/tools/compliance-brief.js +122 -0
- package/dist/tools/compliance-brief.js.map +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# COMPLAI MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that provides compliance overview data to AI assistants.
|
|
4
|
+
|
|
5
|
+
**Package:** `@lindblad/complai-mcp`
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Compliance overview**: `complai_compliance_brief` - Get organization-wide compliance status
|
|
10
|
+
- **User authentication**: Log in with your COMPLAI credentials via browser (no secrets needed)
|
|
11
|
+
- **M2M authentication**: Alternative machine-to-machine auth for automation
|
|
12
|
+
- **AI-optimized responses**: Structured data with human-readable alerts
|
|
13
|
+
- **Mock mode**: Test without API credentials
|
|
14
|
+
- **Persistent sessions**: Login is saved locally - no need to re-authenticate
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### From npm (Recommended)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Install globally
|
|
22
|
+
npm install -g @lindblad/complai-mcp
|
|
23
|
+
|
|
24
|
+
# Or run directly with npx
|
|
25
|
+
npx @lindblad/complai-mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### From Source
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone <repo-url>
|
|
32
|
+
cd mcps/complai-brief
|
|
33
|
+
npm install
|
|
34
|
+
npm run build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start with Cursor/Claude Desktop
|
|
38
|
+
|
|
39
|
+
### Using npx (Easiest)
|
|
40
|
+
|
|
41
|
+
Add to your MCP configuration (`.cursor/mcp.json` or `claude_desktop_config.json`):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"complai": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["@lindblad/complai-mcp"],
|
|
49
|
+
"env": {
|
|
50
|
+
"COMPLAI_API_URL": "https://api.complai.com",
|
|
51
|
+
"COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
|
|
52
|
+
"COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
|
|
53
|
+
"COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
|
|
54
|
+
"COMPLAI_ORGANIZATION_ID": "org_xxxxx"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Using Global Install
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"complai": {
|
|
67
|
+
"command": "complai-mcp",
|
|
68
|
+
"env": {
|
|
69
|
+
"COMPLAI_API_URL": "https://api.complai.com",
|
|
70
|
+
"COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
|
|
71
|
+
"COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
|
|
72
|
+
"COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
|
|
73
|
+
"COMPLAI_ORGANIZATION_ID": "org_xxxxx"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Authentication Modes
|
|
81
|
+
|
|
82
|
+
### User Authentication (Recommended)
|
|
83
|
+
|
|
84
|
+
No client secret required. Users authenticate via browser using their COMPLAI credentials.
|
|
85
|
+
|
|
86
|
+
1. Configure without `COMPLAI_AUTH0_CLIENT_SECRET`:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"complai": {
|
|
92
|
+
"command": "npx",
|
|
93
|
+
"args": ["@lindblad/complai-mcp"],
|
|
94
|
+
"env": {
|
|
95
|
+
"COMPLAI_API_URL": "https://api.complai.com",
|
|
96
|
+
"COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
|
|
97
|
+
"COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
|
|
98
|
+
"COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
|
|
99
|
+
"COMPLAI_ORGANIZATION_ID": "org_xxxxx"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
2. When you first use a COMPLAI tool, use `complai_login`:
|
|
107
|
+
- You'll get a URL and code
|
|
108
|
+
- Open the URL in your browser
|
|
109
|
+
- Enter the code and log in with your COMPLAI credentials
|
|
110
|
+
- Done! Your session is saved to `~/.complai/`
|
|
111
|
+
|
|
112
|
+
### M2M Authentication (For Automation)
|
|
113
|
+
|
|
114
|
+
For scripts, CI/CD, or shared environments. Requires a client secret.
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"complai": {
|
|
120
|
+
"command": "npx",
|
|
121
|
+
"args": ["@lindblad/complai-mcp"],
|
|
122
|
+
"env": {
|
|
123
|
+
"COMPLAI_API_URL": "https://api.complai.com",
|
|
124
|
+
"COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
|
|
125
|
+
"COMPLAI_AUTH0_CLIENT_ID": "your-m2m-client-id",
|
|
126
|
+
"COMPLAI_AUTH0_CLIENT_SECRET": "your-m2m-client-secret",
|
|
127
|
+
"COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
|
|
128
|
+
"COMPLAI_ORGANIZATION_ID": "org_xxxxx"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Mock Mode
|
|
136
|
+
|
|
137
|
+
For testing without any API connection:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"mcpServers": {
|
|
142
|
+
"complai": {
|
|
143
|
+
"command": "npx",
|
|
144
|
+
"args": ["@lindblad/complai-mcp"],
|
|
145
|
+
"env": {
|
|
146
|
+
"COMPLAI_MOCK_MODE": "true"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Authentication Flow
|
|
154
|
+
|
|
155
|
+
### First Time Setup (User Auth Mode)
|
|
156
|
+
|
|
157
|
+
When you start the server for the first time, it will prompt for authentication:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
COMPLAI MCP Server v0.1.0
|
|
161
|
+
─────────────────────────
|
|
162
|
+
API: https://api.test.complai.com
|
|
163
|
+
Auth: User (Device Flow)
|
|
164
|
+
|
|
165
|
+
Authentication required. Starting device authorization flow...
|
|
166
|
+
|
|
167
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
168
|
+
│ Please complete authentication in your browser: │
|
|
169
|
+
│ │
|
|
170
|
+
│ 1. Open: https://complai-test.eu.auth0.com/activate │
|
|
171
|
+
│ 2. Enter: ABCD-EFGH │
|
|
172
|
+
│ │
|
|
173
|
+
│ Waiting for authentication... │
|
|
174
|
+
└─────────────────────────────────────────────────────────────┘
|
|
175
|
+
|
|
176
|
+
✓ Authentication successful!
|
|
177
|
+
|
|
178
|
+
Starting server...
|
|
179
|
+
✓ Server ready
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
After logging in once, your session is saved to `~/.complai/` and you won't need to log in again.
|
|
183
|
+
|
|
184
|
+
### Logging Out
|
|
185
|
+
|
|
186
|
+
To log out, delete the stored credentials:
|
|
187
|
+
```bash
|
|
188
|
+
rm -rf ~/.complai/.credentials.enc
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Available Tools
|
|
192
|
+
|
|
193
|
+
### `complai_list_organizations`
|
|
194
|
+
|
|
195
|
+
List all COMPLAI organizations the user has access to.
|
|
196
|
+
|
|
197
|
+
**Parameters:** None
|
|
198
|
+
|
|
199
|
+
**Response:**
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"organizations": [
|
|
203
|
+
{ "id": "org_xxx", "name": "Acme Corp" },
|
|
204
|
+
{ "id": "org_yyy", "name": "Beta Inc" }
|
|
205
|
+
],
|
|
206
|
+
"message": "User has access to 2 organizations. Ask which one to check."
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `complai_compliance_brief`
|
|
211
|
+
|
|
212
|
+
Get compliance status overview for a specific organization.
|
|
213
|
+
|
|
214
|
+
**Parameters:**
|
|
215
|
+
| Parameter | Type | Required | Description |
|
|
216
|
+
|-----------|------|----------|-------------|
|
|
217
|
+
| `organizationId` | string | Yes | The organization ID (from `complai_list_organizations`) |
|
|
218
|
+
| `workspaceId` | string | No | Filter results to a specific workspace |
|
|
219
|
+
|
|
220
|
+
**Response:**
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"summary": {
|
|
224
|
+
"description": "Compliance overview as of 2026-01-15",
|
|
225
|
+
"dataRooms": 24,
|
|
226
|
+
"assets": 156,
|
|
227
|
+
"manufacturers": 42,
|
|
228
|
+
"totalTasks": 89,
|
|
229
|
+
"overdueActions": 7
|
|
230
|
+
},
|
|
231
|
+
"riskDistribution": [
|
|
232
|
+
{ "level": "High", "count": 3, "percentage": 12.5 },
|
|
233
|
+
{ "level": "Medium", "count": 8, "percentage": 33.3 },
|
|
234
|
+
{ "level": "Low", "count": 13, "percentage": 54.2 }
|
|
235
|
+
],
|
|
236
|
+
"taskStatus": {
|
|
237
|
+
"overdue": 12,
|
|
238
|
+
"dueThisWeek": 8,
|
|
239
|
+
"onTrack": 45,
|
|
240
|
+
"noDeadline": 24
|
|
241
|
+
},
|
|
242
|
+
"alerts": [
|
|
243
|
+
"7 corrective actions are past their deadline",
|
|
244
|
+
"12 tasks are overdue"
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Development
|
|
250
|
+
|
|
251
|
+
### Testing with MCP Inspector
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
npm run inspector
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Project Structure
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
complai-brief/
|
|
261
|
+
├── src/
|
|
262
|
+
│ ├── index.ts # MCP server entry point
|
|
263
|
+
│ ├── types.ts # TypeScript interfaces
|
|
264
|
+
│ ├── tools/
|
|
265
|
+
│ │ └── compliance-brief.ts # Tool implementation
|
|
266
|
+
│ ├── auth/
|
|
267
|
+
│ │ ├── token-manager.ts # Unified token management
|
|
268
|
+
│ │ └── device-auth.ts # Device authorization flow
|
|
269
|
+
│ ├── api/
|
|
270
|
+
│ │ └── complai-client.ts # API client
|
|
271
|
+
│ └── config/
|
|
272
|
+
│ └── config-loader.ts # Configuration loading
|
|
273
|
+
├── package.json
|
|
274
|
+
├── tsconfig.json
|
|
275
|
+
└── README.md
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Error Handling
|
|
279
|
+
|
|
280
|
+
The server returns AI-friendly error messages:
|
|
281
|
+
|
|
282
|
+
| Error | Message |
|
|
283
|
+
|-------|---------|
|
|
284
|
+
| Authentication failed | "Authentication failed. Check your client credentials." |
|
|
285
|
+
| Network error | "Cannot reach COMPLAI API. Check your network connection." |
|
|
286
|
+
| Rate limited | "Rate limit exceeded. Try again in X seconds." |
|
|
287
|
+
| Permission denied | "You don't have access to this organization." |
|
|
288
|
+
|
|
289
|
+
## Security
|
|
290
|
+
|
|
291
|
+
- **User auth mode**: Refresh tokens are stored encrypted in `~/.complai/` with AES-256-GCM
|
|
292
|
+
- **M2M mode**: Client secrets should be stored securely (environment variables recommended)
|
|
293
|
+
- Encryption keys are stored with restrictive permissions (600)
|
|
294
|
+
- Access tokens are cached in memory only (not persisted)
|
|
295
|
+
- All API calls use HTTPS
|
|
296
|
+
- MCP respects the same permissions as the COMPLAI web UI
|
|
297
|
+
|
|
298
|
+
### Stored Files (User Auth Mode)
|
|
299
|
+
|
|
300
|
+
| File | Purpose |
|
|
301
|
+
|------|---------|
|
|
302
|
+
| `~/.complai/.credentials.enc` | Encrypted refresh token |
|
|
303
|
+
| `~/.complai/.key` | Encryption key (600 permissions) |
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ComplaiConfig, DashboardOverviewResponse, UserProfile, AuditRoomsResponse } from '../types.js';
|
|
2
|
+
import { TokenManager } from '../auth/token-manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* HTTP client for COMPLAI api-auth0 endpoints.
|
|
5
|
+
* Handles authentication, organization context, and error handling.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ComplaiClient {
|
|
8
|
+
private readonly tokenManager;
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
private readonly defaultOrganizationId?;
|
|
11
|
+
constructor(config: ComplaiConfig, tokenManager: TokenManager);
|
|
12
|
+
/**
|
|
13
|
+
* Get the default organization ID if configured
|
|
14
|
+
*/
|
|
15
|
+
getDefaultOrganizationId(): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Get current user profile including their organizations
|
|
18
|
+
*/
|
|
19
|
+
getMe(): Promise<UserProfile>;
|
|
20
|
+
/**
|
|
21
|
+
* Get dashboard overview data for a specific organization
|
|
22
|
+
*/
|
|
23
|
+
getDashboardOverview(organizationId: string, workspaceId?: string): Promise<DashboardOverviewResponse>;
|
|
24
|
+
/**
|
|
25
|
+
* Get audit rooms list with status overview
|
|
26
|
+
* Returns rooms with risk rating, engagement, task completion
|
|
27
|
+
*/
|
|
28
|
+
getAuditRooms(organizationId: string, page?: number, pageSize?: number): Promise<AuditRoomsResponse>;
|
|
29
|
+
/**
|
|
30
|
+
* Make a GET request to the COMPLAI API
|
|
31
|
+
*/
|
|
32
|
+
private get;
|
|
33
|
+
/**
|
|
34
|
+
* Make a POST request to the COMPLAI API
|
|
35
|
+
*/
|
|
36
|
+
private post;
|
|
37
|
+
/**
|
|
38
|
+
* Make an authenticated request with retry on 401
|
|
39
|
+
*/
|
|
40
|
+
private request;
|
|
41
|
+
/**
|
|
42
|
+
* Handle API errors with AI-friendly messages
|
|
43
|
+
*/
|
|
44
|
+
private handleError;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=complai-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complai-client.d.ts","sourceRoot":"","sources":["../../src/api/complai-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAS;gBAEpC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY;IAM7D;;OAEG;IACH,wBAAwB,IAAI,MAAM,GAAG,SAAS;IAI9C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAInC;;OAEG;IACG,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAQ5G;;;OAGG;IACG,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKjH;;OAEG;YACW,GAAG;IAIjB;;OAEG;YACW,IAAI;IAIlB;;OAEG;YACW,OAAO;IA4CrB;;OAEG;YACW,WAAW;CAqB1B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for COMPLAI api-auth0 endpoints.
|
|
3
|
+
* Handles authentication, organization context, and error handling.
|
|
4
|
+
*/
|
|
5
|
+
export class ComplaiClient {
|
|
6
|
+
tokenManager;
|
|
7
|
+
baseUrl;
|
|
8
|
+
defaultOrganizationId;
|
|
9
|
+
constructor(config, tokenManager) {
|
|
10
|
+
this.tokenManager = tokenManager;
|
|
11
|
+
this.baseUrl = config.api.baseUrl.replace(/\/$/, ''); // Remove trailing slash
|
|
12
|
+
this.defaultOrganizationId = config.api.organizationId;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the default organization ID if configured
|
|
16
|
+
*/
|
|
17
|
+
getDefaultOrganizationId() {
|
|
18
|
+
return this.defaultOrganizationId;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get current user profile including their organizations
|
|
22
|
+
*/
|
|
23
|
+
async getMe() {
|
|
24
|
+
return this.get('/api/v2/me');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get dashboard overview data for a specific organization
|
|
28
|
+
*/
|
|
29
|
+
async getDashboardOverview(organizationId, workspaceId) {
|
|
30
|
+
const filters = workspaceId
|
|
31
|
+
? { items: [{ field: 'workspaceId', value: workspaceId }] }
|
|
32
|
+
: { items: [] };
|
|
33
|
+
return this.post('/api/v2/dashboards/charts/overview', { filters }, organizationId);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get audit rooms list with status overview
|
|
37
|
+
* Returns rooms with risk rating, engagement, task completion
|
|
38
|
+
*/
|
|
39
|
+
async getAuditRooms(organizationId, page = 1, pageSize = 20) {
|
|
40
|
+
const url = `/api/v2/audit-rooms?page=${page}&pageSize=${pageSize}&orderField=name&order=ASC`;
|
|
41
|
+
return this.get(url, organizationId);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Make a GET request to the COMPLAI API
|
|
45
|
+
*/
|
|
46
|
+
async get(path, organizationId) {
|
|
47
|
+
return this.request('GET', path, undefined, organizationId);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Make a POST request to the COMPLAI API
|
|
51
|
+
*/
|
|
52
|
+
async post(path, body, organizationId) {
|
|
53
|
+
return this.request('POST', path, body, organizationId);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Make an authenticated request with retry on 401
|
|
57
|
+
*/
|
|
58
|
+
async request(method, path, body, organizationId) {
|
|
59
|
+
const makeRequest = async (token) => {
|
|
60
|
+
const url = `${this.baseUrl}${path}`;
|
|
61
|
+
const headers = {
|
|
62
|
+
'Authorization': `Bearer ${token}`,
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
};
|
|
65
|
+
// Add organization context header if specified
|
|
66
|
+
if (organizationId) {
|
|
67
|
+
headers['x-organization-id'] = organizationId;
|
|
68
|
+
}
|
|
69
|
+
const options = {
|
|
70
|
+
method,
|
|
71
|
+
headers,
|
|
72
|
+
};
|
|
73
|
+
if (body !== undefined) {
|
|
74
|
+
options.body = JSON.stringify(body);
|
|
75
|
+
}
|
|
76
|
+
return fetch(url, options);
|
|
77
|
+
};
|
|
78
|
+
// First attempt
|
|
79
|
+
let token = await this.tokenManager.getToken();
|
|
80
|
+
let response = await makeRequest(token);
|
|
81
|
+
// Retry once on 401 with fresh token
|
|
82
|
+
if (response.status === 401) {
|
|
83
|
+
this.tokenManager.invalidate();
|
|
84
|
+
token = await this.tokenManager.refreshToken();
|
|
85
|
+
response = await makeRequest(token);
|
|
86
|
+
}
|
|
87
|
+
// Handle errors
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
await this.handleError(response);
|
|
90
|
+
}
|
|
91
|
+
return (await response.json());
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Handle API errors with AI-friendly messages
|
|
95
|
+
*/
|
|
96
|
+
async handleError(response) {
|
|
97
|
+
const status = response.status;
|
|
98
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
99
|
+
console.error(`[DEBUG] API Error ${status}: ${errorText}`);
|
|
100
|
+
if (status === 401 || status === 403) {
|
|
101
|
+
throw new Error(`Access denied (${status}): ${errorText}`);
|
|
102
|
+
}
|
|
103
|
+
if (status === 429) {
|
|
104
|
+
const retryAfter = response.headers.get('Retry-After') || '60';
|
|
105
|
+
throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
|
|
106
|
+
}
|
|
107
|
+
if (status >= 500) {
|
|
108
|
+
throw new Error('COMPLAI API is temporarily unavailable. Try again later.');
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`API error (${status}): ${errorText}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=complai-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complai-client.js","sourceRoot":"","sources":["../../src/api/complai-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Authorization Flow for Auth0
|
|
3
|
+
* Allows users to authenticate via browser without exposing client secrets
|
|
4
|
+
*/
|
|
5
|
+
export interface DeviceAuthConfig {
|
|
6
|
+
domain: string;
|
|
7
|
+
clientId: string;
|
|
8
|
+
audience: string;
|
|
9
|
+
scope?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DeviceCodeResponse {
|
|
12
|
+
device_code: string;
|
|
13
|
+
user_code: string;
|
|
14
|
+
verification_uri: string;
|
|
15
|
+
verification_uri_complete: string;
|
|
16
|
+
expires_in: number;
|
|
17
|
+
interval: number;
|
|
18
|
+
}
|
|
19
|
+
export interface TokenResponse {
|
|
20
|
+
access_token: string;
|
|
21
|
+
refresh_token?: string;
|
|
22
|
+
token_type: string;
|
|
23
|
+
expires_in: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Device Authorization Manager
|
|
27
|
+
* Handles the device code flow and token storage
|
|
28
|
+
*/
|
|
29
|
+
export declare class DeviceAuthManager {
|
|
30
|
+
private config;
|
|
31
|
+
private cachedAccessToken;
|
|
32
|
+
constructor(config: DeviceAuthConfig);
|
|
33
|
+
/**
|
|
34
|
+
* Get a valid access token, prompting for login if needed
|
|
35
|
+
*/
|
|
36
|
+
getAccessToken(): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Initiate device authorization flow
|
|
39
|
+
* Returns user instructions for completing authentication
|
|
40
|
+
*/
|
|
41
|
+
initiateDeviceAuthorization(): Promise<{
|
|
42
|
+
userCode: string;
|
|
43
|
+
verificationUri: string;
|
|
44
|
+
verificationUriComplete: string;
|
|
45
|
+
expiresIn: number;
|
|
46
|
+
pollForToken: () => Promise<TokenResponse>;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Poll Auth0 for token after user completes authentication
|
|
50
|
+
*/
|
|
51
|
+
private pollForToken;
|
|
52
|
+
/**
|
|
53
|
+
* Refresh the access token using a refresh token
|
|
54
|
+
*/
|
|
55
|
+
private refreshAccessToken;
|
|
56
|
+
/**
|
|
57
|
+
* Cache access token in memory
|
|
58
|
+
*/
|
|
59
|
+
private cacheToken;
|
|
60
|
+
/**
|
|
61
|
+
* Store refresh token encrypted on disk
|
|
62
|
+
*/
|
|
63
|
+
private storeCredentials;
|
|
64
|
+
/**
|
|
65
|
+
* Load stored credentials from disk
|
|
66
|
+
*/
|
|
67
|
+
private loadStoredCredentials;
|
|
68
|
+
/**
|
|
69
|
+
* Clear stored credentials (logout)
|
|
70
|
+
*/
|
|
71
|
+
clearCredentials(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Check if user is authenticated
|
|
74
|
+
*/
|
|
75
|
+
isAuthenticated(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get or create encryption key
|
|
78
|
+
*/
|
|
79
|
+
private getEncryptionKey;
|
|
80
|
+
/**
|
|
81
|
+
* Encrypt data using AES-256-GCM
|
|
82
|
+
*/
|
|
83
|
+
private encrypt;
|
|
84
|
+
/**
|
|
85
|
+
* Decrypt data using AES-256-GCM
|
|
86
|
+
*/
|
|
87
|
+
private decrypt;
|
|
88
|
+
private sleep;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Error thrown when authentication is required
|
|
92
|
+
*/
|
|
93
|
+
export declare class AuthenticationRequiredError extends Error {
|
|
94
|
+
readonly domain: string;
|
|
95
|
+
readonly clientId: string;
|
|
96
|
+
constructor(message: string, domain: string, clientId: string);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=device-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-auth.d.ts","sourceRoot":"","sources":["../../src/auth/device-auth.ts"],"names":[],"mappings":"AAKA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAAqD;gBAElE,MAAM,EAAE,gBAAgB;IAOpC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiCvC;;;OAGG;IACG,2BAA2B,IAAI,OAAO,CAAC;QAC3C,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;QACxB,uBAAuB,EAAE,MAAM,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;KAC5C,CAAC;IA2BF;;OAEG;YACW,YAAY;IAmD1B;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAOxB;;OAEG;IACH,eAAe,IAAI,OAAO;IAO1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,OAAO;IAaf;;OAEG;IACH,OAAO,CAAC,OAAO;IAqBf,OAAO,CAAC,KAAK;CAGd;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;aAGlC,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;gBAFhC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;CAKnC"}
|