@mag.ni/process 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mag.ni
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 ADDED
@@ -0,0 +1,122 @@
1
+ # @mag.ni/process
2
+
3
+ MCP server for [Processes](https://process.mag.ni) — a platform where users design structured workflows that guide AI agents through sequential tasks, decision points, and reporting.
4
+
5
+ ## Quick Start
6
+
7
+ Add to your `.mcp.json` (project root or `~/.claude.json`):
8
+
9
+ ```json
10
+ {
11
+ "mcpServers": {
12
+ "process": {
13
+ "command": "npx",
14
+ "args": ["-y", "@mag.ni/process"]
15
+ }
16
+ }
17
+ }
18
+ ```
19
+
20
+ On first use, a browser window opens for authentication. After signing in, the token is stored locally and reused automatically.
21
+
22
+ ### Windows
23
+
24
+ ```json
25
+ {
26
+ "mcpServers": {
27
+ "process": {
28
+ "command": "cmd",
29
+ "args": ["/c", "npx", "-y", "@mag.ni/process"]
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### Auto-Updates
36
+
37
+ Using `npx -y` ensures you always run the latest version. Updates are picked up automatically when the MCP server restarts.
38
+
39
+ ## Configuration
40
+
41
+ All settings have sensible defaults. Override via the `env` block in `.mcp.json` if needed:
42
+
43
+ | Variable | Default | Description |
44
+ |----------|---------|-------------|
45
+ | `PROCESSES_API_URL` | `https://process.mag.ni` | Process API endpoint |
46
+ | `PROCESSES_AUTH_URL` | `https://auth.mag.ni` | OAuth authorization server |
47
+ | `PROCESSES_OAUTH_CLIENT_ID` | `process-mcp` | OAuth client ID |
48
+ | `PROCESSES_OAUTH_CALLBACK_PORT` | `19823` | Local port for OAuth callback |
49
+ | `SENTRY_DSN` | _(disabled)_ | Error reporting endpoint |
50
+
51
+ Example with custom API URL (e.g. for staging):
52
+
53
+ ```json
54
+ {
55
+ "mcpServers": {
56
+ "process": {
57
+ "command": "npx",
58
+ "args": ["-y", "@mag.ni/process"],
59
+ "env": {
60
+ "PROCESSES_API_URL": "https://process.office.mag.ni",
61
+ "PROCESSES_AUTH_URL": "https://auth.office.mag.ni"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ## Available Tools
69
+
70
+ ### Agent Management
71
+ | Tool | Description |
72
+ |------|-------------|
73
+ | `list_agent_users` | List all agent identities |
74
+ | `create_agent_user` | Create a new agent identity |
75
+ | `delete_agent_user` | Delete an unclaimed agent identity |
76
+
77
+ ### Session Management
78
+ | Tool | Description |
79
+ |------|-------------|
80
+ | `claim_user` | Claim an agent identity to start working |
81
+ | `heartbeat` | Extend session lease |
82
+ | `release_user` | Release claimed identity |
83
+ | `logout` | Clear session and stored credentials |
84
+
85
+ ### Workflow Execution
86
+ | Tool | Description |
87
+ |------|-------------|
88
+ | `get_my_instances` | Get workflow instances assigned to you |
89
+ | `get_instance_details` | Get current step, history, and metadata |
90
+ | `get_available_actions` | Get actions at the current step |
91
+ | `take_action` | Execute an action to advance the workflow |
92
+ | `get_diagram_context` | Get full workflow structure |
93
+ | `get_instance_notes` | Get notes on an instance |
94
+ | `add_instance_note` | Add a note to an instance |
95
+ | `get_node_details` | Get detailed instructions for steps |
96
+
97
+ ### Diagram Design
98
+ | Tool | Description |
99
+ |------|-------------|
100
+ | `enter_design_mode` | Enter design mode |
101
+ | `exit_design_mode` | Exit design mode |
102
+ | `list_diagrams` | List available diagrams |
103
+ | `get_diagram` | Get diagram details |
104
+ | `create_diagram` | Create a new diagram |
105
+ | `update_diagram` | Update diagram properties |
106
+ | `create_node` | Add a node to a diagram |
107
+ | `update_node` | Modify a node |
108
+ | `delete_node` | Remove a node |
109
+ | `create_arrow` | Connect two nodes |
110
+ | `update_arrow` | Modify a connection |
111
+ | `delete_arrow` | Remove a connection |
112
+ | `delete_diagram` | Delete a diagram |
113
+ | `duplicate_diagram` | Copy a diagram |
114
+
115
+ ## Requirements
116
+
117
+ - Node.js 18+
118
+ - An MCP-compatible client (e.g. [Claude Code](https://claude.com/claude-code))
119
+
120
+ ## License
121
+
122
+ MIT
package/dist/auth.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * MCP Processes - OAuth2 Authorization Code + PKCE Authentication
3
+ *
4
+ * Authenticates the MCP server as the user who runs it (like `gh auth login`).
5
+ * Flow:
6
+ * 1. Check for stored refresh token in ~/.config/mcp-processes/tokens.json
7
+ * 2. If no token: start local HTTP server, open browser to auth server
8
+ * 3. User logs in → auth server redirects to http://localhost:{port}/callback
9
+ * 4. Exchange auth code for access_token + refresh_token
10
+ * 5. Store refresh token locally for future sessions
11
+ */
12
+ export interface AuthConfig {
13
+ authUrl: string;
14
+ clientId: string;
15
+ clientSecret?: string;
16
+ callbackPort: number;
17
+ scopes: string[];
18
+ }
19
+ export declare function clearStoredTokens(authUrl?: string): void;
20
+ export declare class OAuthManager {
21
+ private config;
22
+ private accessToken;
23
+ private tokenExpiresAt;
24
+ private refreshToken;
25
+ constructor(config: AuthConfig);
26
+ /**
27
+ * Ensure we have a valid access token.
28
+ * If no token exists, triggers the browser-based login flow.
29
+ * If token is expired, uses refresh token to get a new one.
30
+ */
31
+ ensureAccessToken(): Promise<string>;
32
+ /**
33
+ * Start the interactive browser-based login flow
34
+ */
35
+ private interactiveLogin;
36
+ /**
37
+ * Get the current access token (may be null if not yet authenticated)
38
+ */
39
+ getAccessToken(): string | null;
40
+ /**
41
+ * Check if we have a stored refresh token (can authenticate without browser)
42
+ */
43
+ hasStoredCredentials(): boolean;
44
+ /**
45
+ * Clear all in-memory tokens and remove stored credentials for this environment.
46
+ * After calling this, the next ensureAccessToken() will trigger interactive login.
47
+ */
48
+ clearCredentials(): void;
49
+ }
50
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA+BH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AA+CD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAmBxD;AAgRD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,YAAY,CAAuB;gBAE/B,MAAM,EAAE,UAAU;IAU9B;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAmC1C;;OAEG;YACW,gBAAgB;IAkD9B;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAO/B;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;;OAGG;IACH,gBAAgB,IAAI,IAAI;CAMzB"}
package/dist/auth.js ADDED
@@ -0,0 +1,421 @@
1
+ /**
2
+ * MCP Processes - OAuth2 Authorization Code + PKCE Authentication
3
+ *
4
+ * Authenticates the MCP server as the user who runs it (like `gh auth login`).
5
+ * Flow:
6
+ * 1. Check for stored refresh token in ~/.config/mcp-processes/tokens.json
7
+ * 2. If no token: start local HTTP server, open browser to auth server
8
+ * 3. User logs in → auth server redirects to http://localhost:{port}/callback
9
+ * 4. Exchange auth code for access_token + refresh_token
10
+ * 5. Store refresh token locally for future sessions
11
+ */
12
+ import * as http from 'node:http';
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import * as os from 'node:os';
16
+ import * as crypto from 'node:crypto';
17
+ import { spawn } from 'node:child_process';
18
+ // =============================================================================
19
+ // Token Storage
20
+ // =============================================================================
21
+ function getTokenFilePath() {
22
+ const configDir = process.platform === 'win32'
23
+ ? path.join(os.homedir(), '.config', 'mcp-processes')
24
+ : path.join(os.homedir(), '.config', 'mcp-processes');
25
+ return path.join(configDir, 'tokens.json');
26
+ }
27
+ function loadTokenStore() {
28
+ const filePath = getTokenFilePath();
29
+ try {
30
+ const data = fs.readFileSync(filePath, 'utf-8');
31
+ const parsed = JSON.parse(data);
32
+ // Migrate single-token format to multi-environment store
33
+ if (parsed.refreshToken && parsed.authUrl) {
34
+ return { [parsed.authUrl]: parsed };
35
+ }
36
+ return parsed;
37
+ }
38
+ catch {
39
+ return {};
40
+ }
41
+ }
42
+ function loadStoredTokens(authUrl) {
43
+ const store = loadTokenStore();
44
+ return store[authUrl] ?? null;
45
+ }
46
+ function saveTokens(tokens) {
47
+ const filePath = getTokenFilePath();
48
+ const dir = path.dirname(filePath);
49
+ fs.mkdirSync(dir, { recursive: true });
50
+ // Load existing store and merge
51
+ const store = loadTokenStore();
52
+ store[tokens.authUrl] = tokens;
53
+ fs.writeFileSync(filePath, JSON.stringify(store, null, 2), { mode: 0o600 });
54
+ }
55
+ export function clearStoredTokens(authUrl) {
56
+ if (!authUrl) {
57
+ // Clear all tokens
58
+ const filePath = getTokenFilePath();
59
+ try {
60
+ fs.unlinkSync(filePath);
61
+ }
62
+ catch {
63
+ // File doesn't exist, that's fine
64
+ }
65
+ return;
66
+ }
67
+ // Clear tokens for a specific auth URL
68
+ const store = loadTokenStore();
69
+ delete store[authUrl];
70
+ const filePath = getTokenFilePath();
71
+ const dir = path.dirname(filePath);
72
+ fs.mkdirSync(dir, { recursive: true });
73
+ fs.writeFileSync(filePath, JSON.stringify(store, null, 2), { mode: 0o600 });
74
+ }
75
+ // =============================================================================
76
+ // PKCE Helpers
77
+ // =============================================================================
78
+ function generateCodeVerifier() {
79
+ return crypto.randomBytes(32).toString('base64url');
80
+ }
81
+ function generateCodeChallenge(verifier) {
82
+ return crypto.createHash('sha256').update(verifier).digest('base64url');
83
+ }
84
+ // =============================================================================
85
+ // Browser Helpers
86
+ // =============================================================================
87
+ /**
88
+ * Open a URL in the default browser.
89
+ * On Windows, cmd.exe interprets & as a command separator, so we write
90
+ * a temp HTML file with a redirect and open that instead.
91
+ */
92
+ function openBrowser(url) {
93
+ try {
94
+ if (process.platform === 'win32') {
95
+ // Use PowerShell Start-Process — avoids cmd.exe's & interpretation issues with URLs
96
+ // Escape double quotes in URL to prevent PowerShell injection
97
+ const safeUrl = url.replace(/"/g, '`"');
98
+ spawn('powershell.exe', ['-NoProfile', '-Command', `Start-Process "${safeUrl}"`], {
99
+ stdio: 'ignore',
100
+ windowsHide: true,
101
+ });
102
+ }
103
+ else if (process.platform === 'darwin') {
104
+ spawn('open', [url], { stdio: 'ignore' });
105
+ }
106
+ else {
107
+ spawn('xdg-open', [url], { stdio: 'ignore' });
108
+ }
109
+ }
110
+ catch {
111
+ console.error(`\nPlease open this URL in your browser to authenticate:\n${url}\n`);
112
+ }
113
+ }
114
+ // =============================================================================
115
+ // HTML Page Helpers
116
+ // =============================================================================
117
+ function escapeHtml(str) {
118
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
119
+ }
120
+ function renderErrorPage(title, message, details) {
121
+ const timestamp = new Date().toISOString();
122
+ const reportBody = `Error: ${title}\nMessage: ${message}\nDetails: ${details}\nTimestamp: ${timestamp}\nPlatform: ${process.platform}\nNode: ${process.version}`;
123
+ return `<!DOCTYPE html>
124
+ <html><head><meta charset="utf-8"><title>MCP Processes — Error</title>
125
+ <link rel="icon" href="https://mag.ni/favicon.ico" />
126
+ <style>
127
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #f8f9fa; color: #1a1a2e; }
128
+ .card { background: white; border-radius: 12px; padding: 48px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); text-align: center; max-width: 520px; }
129
+ .icon { font-size: 48px; margin-bottom: 16px; }
130
+ h1 { font-size: 22px; font-weight: 600; margin: 0 0 12px; color: #c0392b; }
131
+ p { color: #555; line-height: 1.6; margin: 0; }
132
+ .details { margin-top: 16px; padding: 12px 16px; background: #f1f3f5; border-radius: 8px; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; font-size: 12px; color: #666; text-align: left; word-break: break-all; }
133
+ .actions { margin-top: 24px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
134
+ .btn { display: inline-block; padding: 10px 20px; border-radius: 8px; font-size: 14px; font-weight: 500; text-decoration: none; cursor: pointer; border: none; transition: background 0.2s; }
135
+ .btn-primary { background: #3b82f6; color: white; }
136
+ .btn-primary:hover { background: #2563eb; }
137
+ .btn-secondary { background: #e5e7eb; color: #374151; }
138
+ .btn-secondary:hover { background: #d1d5db; }
139
+ .hint { margin-top: 20px; font-size: 13px; color: #888; }
140
+ .copied { color: #16a34a; font-weight: 500; }
141
+ </style></head>
142
+ <body><div class="card">
143
+ <div class="icon">&#9888;</div>
144
+ <h1>${escapeHtml(title)}</h1>
145
+ <p>${escapeHtml(message)}</p>
146
+ <div class="details">
147
+ <div>${escapeHtml(details)}</div>
148
+ <div style="margin-top:4px;color:#999">${escapeHtml(timestamp)}</div>
149
+ </div>
150
+ <div class="actions">
151
+ <button class="btn btn-primary" onclick="copyReport()">Copy Error Report</button>
152
+ <a class="btn btn-secondary" href="mailto:tech-success@magnifinance.com?subject=${encodeURIComponent('MCP Processes Auth Error: ' + title)}&body=${encodeURIComponent(reportBody)}">Email Report</a>
153
+ </div>
154
+ <p class="hint" id="hint">Copy the error report and send it to the development team so we can help.</p>
155
+ </div>
156
+ <script>
157
+ function copyReport() {
158
+ const report = ${JSON.stringify(reportBody)};
159
+ navigator.clipboard.writeText(report).then(function() {
160
+ document.getElementById('hint').innerHTML = '<span class="copied">Copied to clipboard!</span> Paste it in a message to the dev team.';
161
+ }).catch(function() {
162
+ // Fallback: select text in details box
163
+ var range = document.createRange();
164
+ range.selectNodeContents(document.querySelector('.details'));
165
+ var sel = window.getSelection();
166
+ sel.removeAllRanges();
167
+ sel.addRange(range);
168
+ document.getElementById('hint').textContent = 'Select and copy the error details above.';
169
+ });
170
+ }
171
+ </script>
172
+ </body></html>`;
173
+ }
174
+ // =============================================================================
175
+ // Authorization Code Flow
176
+ // =============================================================================
177
+ /**
178
+ * Start a local HTTP server and wait for the OAuth callback.
179
+ * Opens the browser to the authorization URL.
180
+ * Returns the authorization code.
181
+ */
182
+ function waitForAuthorizationCode(authorizationUrl, port, expectedState) {
183
+ return new Promise((resolve, reject) => {
184
+ const server = http.createServer((req, res) => {
185
+ if (!req.url?.startsWith('/callback')) {
186
+ res.writeHead(404);
187
+ res.end('Not found');
188
+ return;
189
+ }
190
+ const url = new URL(req.url, `http://localhost:${port}`);
191
+ const code = url.searchParams.get('code');
192
+ const state = url.searchParams.get('state');
193
+ const error = url.searchParams.get('error');
194
+ const errorDescription = url.searchParams.get('error_description');
195
+ if (error) {
196
+ res.writeHead(400, { 'Content-Type': 'text/html' });
197
+ res.end(renderErrorPage('Authentication Failed', errorDescription || error, `OAuth error code: ${error}`));
198
+ server.close();
199
+ reject(new Error(`OAuth error: ${error} - ${errorDescription}`));
200
+ return;
201
+ }
202
+ if (state !== expectedState) {
203
+ console.error(`State mismatch — expected: ${expectedState.substring(0, 8)}..., received: ${(state || 'null').substring(0, 8)}...`);
204
+ res.writeHead(400, { 'Content-Type': 'text/html' });
205
+ res.end(renderErrorPage('Invalid State', 'CSRF state mismatch. This can happen if you took too long to log in or opened multiple login tabs.', `Expected: ${expectedState.substring(0, 8)}..., Received: ${(state || 'null').substring(0, 8)}...`));
206
+ server.close();
207
+ reject(new Error('OAuth state mismatch'));
208
+ return;
209
+ }
210
+ if (!code) {
211
+ res.writeHead(400, { 'Content-Type': 'text/html' });
212
+ res.end(renderErrorPage('Missing Authorization Code', 'The authorization server did not return an authorization code.', 'No authorization code was present in the callback response.'));
213
+ server.close();
214
+ reject(new Error('No authorization code received'));
215
+ return;
216
+ }
217
+ res.writeHead(200, { 'Content-Type': 'text/html' });
218
+ res.end(`<!DOCTYPE html>
219
+ <html><head><meta charset="utf-8"><title>MCP Processes — Authenticated</title>
220
+ <link rel="icon" href="https://mag.ni/favicon.ico" />
221
+ <style>
222
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #f8f9fa; color: #1a1a2e; }
223
+ .card { background: white; border-radius: 12px; padding: 48px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); text-align: center; max-width: 440px; }
224
+ .icon { font-size: 48px; margin-bottom: 16px; }
225
+ h1 { font-size: 22px; font-weight: 600; margin: 0 0 12px; }
226
+ p { color: #555; line-height: 1.6; margin: 0; }
227
+ .hint { margin-top: 20px; font-size: 13px; color: #888; }
228
+ </style></head>
229
+ <body><div class="card">
230
+ <div class="icon">&#10003;</div>
231
+ <h1>You're signed in to MCP Processes</h1>
232
+ <p>Your session token has been saved. The MCP server is now authenticated with your identity and tenant context.</p>
233
+ <p class="hint">You can close this tab and return to your terminal.</p>
234
+ </div></body></html>`);
235
+ server.close();
236
+ resolve(code);
237
+ });
238
+ server.listen(port, '127.0.0.1', () => {
239
+ // Open browser to authorization URL
240
+ openBrowser(authorizationUrl);
241
+ });
242
+ // Timeout after 2 minutes
243
+ setTimeout(() => {
244
+ server.close();
245
+ reject(new Error('Authentication timed out (2 minutes). Please try again.'));
246
+ }, 120000);
247
+ });
248
+ }
249
+ /**
250
+ * Exchange authorization code for tokens
251
+ */
252
+ async function exchangeCodeForTokens(config, code, codeVerifier) {
253
+ const tokenUrl = `${config.authUrl}/connect/token`;
254
+ const params = {
255
+ grant_type: 'authorization_code',
256
+ client_id: config.clientId,
257
+ code,
258
+ redirect_uri: `http://localhost:${config.callbackPort}/callback`,
259
+ code_verifier: codeVerifier,
260
+ };
261
+ if (config.clientSecret) {
262
+ params.client_secret = config.clientSecret;
263
+ }
264
+ const body = new URLSearchParams(params);
265
+ const response = await fetch(tokenUrl, {
266
+ method: 'POST',
267
+ headers: {
268
+ 'Content-Type': 'application/x-www-form-urlencoded',
269
+ 'User-Agent': 'MCP-Processes/1.0',
270
+ },
271
+ body: body.toString(),
272
+ });
273
+ if (!response.ok) {
274
+ const errorText = await response.text();
275
+ throw new Error(`Token exchange failed (${response.status}): ${errorText}`);
276
+ }
277
+ return response.json();
278
+ }
279
+ /**
280
+ * Use refresh token to get a new access token
281
+ */
282
+ async function refreshAccessToken(config, refreshToken) {
283
+ const tokenUrl = `${config.authUrl}/connect/token`;
284
+ const params = {
285
+ grant_type: 'refresh_token',
286
+ client_id: config.clientId,
287
+ refresh_token: refreshToken,
288
+ };
289
+ if (config.clientSecret) {
290
+ params.client_secret = config.clientSecret;
291
+ }
292
+ const body = new URLSearchParams(params);
293
+ const response = await fetch(tokenUrl, {
294
+ method: 'POST',
295
+ headers: {
296
+ 'Content-Type': 'application/x-www-form-urlencoded',
297
+ 'User-Agent': 'MCP-Processes/1.0',
298
+ },
299
+ body: body.toString(),
300
+ });
301
+ if (!response.ok) {
302
+ const errorText = await response.text();
303
+ throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
304
+ }
305
+ return response.json();
306
+ }
307
+ // =============================================================================
308
+ // OAuth Manager
309
+ // =============================================================================
310
+ export class OAuthManager {
311
+ config;
312
+ accessToken = null;
313
+ tokenExpiresAt = 0;
314
+ refreshToken = null;
315
+ constructor(config) {
316
+ this.config = config;
317
+ // Try to load stored refresh token for this environment
318
+ const stored = loadStoredTokens(config.authUrl);
319
+ if (stored && stored.clientId === config.clientId) {
320
+ this.refreshToken = stored.refreshToken;
321
+ }
322
+ }
323
+ /**
324
+ * Ensure we have a valid access token.
325
+ * If no token exists, triggers the browser-based login flow.
326
+ * If token is expired, uses refresh token to get a new one.
327
+ */
328
+ async ensureAccessToken() {
329
+ // Token still valid (with 30s buffer)
330
+ if (this.accessToken && Date.now() < this.tokenExpiresAt - 30000) {
331
+ return this.accessToken;
332
+ }
333
+ // Try refresh token first
334
+ if (this.refreshToken) {
335
+ try {
336
+ const tokenResponse = await refreshAccessToken(this.config, this.refreshToken);
337
+ this.accessToken = tokenResponse.access_token;
338
+ this.tokenExpiresAt = Date.now() + tokenResponse.expires_in * 1000;
339
+ // Update stored refresh token if a new one was issued
340
+ if (tokenResponse.refresh_token) {
341
+ this.refreshToken = tokenResponse.refresh_token;
342
+ saveTokens({
343
+ refreshToken: this.refreshToken,
344
+ authUrl: this.config.authUrl,
345
+ clientId: this.config.clientId,
346
+ });
347
+ }
348
+ return this.accessToken;
349
+ }
350
+ catch (error) {
351
+ // Refresh failed — fall through to interactive login
352
+ console.error('Token refresh failed, initiating login flow...');
353
+ this.refreshToken = null;
354
+ }
355
+ }
356
+ // No valid token — start interactive login
357
+ return this.interactiveLogin();
358
+ }
359
+ /**
360
+ * Start the interactive browser-based login flow
361
+ */
362
+ async interactiveLogin() {
363
+ const codeVerifier = generateCodeVerifier();
364
+ const codeChallenge = generateCodeChallenge(codeVerifier);
365
+ const state = crypto.randomBytes(16).toString('hex');
366
+ const authParams = new URLSearchParams({
367
+ client_id: this.config.clientId,
368
+ redirect_uri: `http://localhost:${this.config.callbackPort}/callback`,
369
+ response_type: 'code',
370
+ scope: this.config.scopes.join(' '),
371
+ code_challenge: codeChallenge,
372
+ code_challenge_method: 'S256',
373
+ state,
374
+ });
375
+ const authorizationUrl = `${this.config.authUrl}/connect/authorize?${authParams.toString()}`;
376
+ console.error('Opening browser for authentication...');
377
+ // Wait for the user to authenticate and get the code
378
+ const code = await waitForAuthorizationCode(authorizationUrl, this.config.callbackPort, state);
379
+ // Exchange code for tokens
380
+ const tokenResponse = await exchangeCodeForTokens(this.config, code, codeVerifier);
381
+ this.accessToken = tokenResponse.access_token;
382
+ this.tokenExpiresAt = Date.now() + tokenResponse.expires_in * 1000;
383
+ // Store refresh token for future sessions
384
+ if (tokenResponse.refresh_token) {
385
+ this.refreshToken = tokenResponse.refresh_token;
386
+ saveTokens({
387
+ refreshToken: this.refreshToken,
388
+ authUrl: this.config.authUrl,
389
+ clientId: this.config.clientId,
390
+ });
391
+ }
392
+ console.error('Authentication successful!');
393
+ return this.accessToken;
394
+ }
395
+ /**
396
+ * Get the current access token (may be null if not yet authenticated)
397
+ */
398
+ getAccessToken() {
399
+ if (this.accessToken && Date.now() < this.tokenExpiresAt - 30000) {
400
+ return this.accessToken;
401
+ }
402
+ return null;
403
+ }
404
+ /**
405
+ * Check if we have a stored refresh token (can authenticate without browser)
406
+ */
407
+ hasStoredCredentials() {
408
+ return this.refreshToken !== null;
409
+ }
410
+ /**
411
+ * Clear all in-memory tokens and remove stored credentials for this environment.
412
+ * After calling this, the next ensureAccessToken() will trigger interactive login.
413
+ */
414
+ clearCredentials() {
415
+ this.accessToken = null;
416
+ this.tokenExpiresAt = 0;
417
+ this.refreshToken = null;
418
+ clearStoredTokens(this.config.authUrl);
419
+ }
420
+ }
421
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}