@axonflow/sdk 2.1.0 → 2.2.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 +39 -36
- package/dist/cjs/client.d.ts +32 -2
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +108 -77
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/errors.d.ts +93 -6
- package/dist/cjs/errors.d.ts.map +1 -1
- package/dist/cjs/errors.js +126 -12
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/code-governance.d.ts +2 -0
- package/dist/cjs/types/code-governance.d.ts.map +1 -1
- package/dist/cjs/types/config.d.ts +15 -7
- package/dist/cjs/types/config.d.ts.map +1 -1
- package/dist/cjs/types/proxy.d.ts +2 -2
- package/dist/cjs/types/proxy.d.ts.map +1 -1
- package/dist/esm/client.d.ts +32 -2
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +109 -78
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/errors.d.ts +93 -6
- package/dist/esm/errors.d.ts.map +1 -1
- package/dist/esm/errors.js +121 -11
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/code-governance.d.ts +2 -0
- package/dist/esm/types/code-governance.d.ts.map +1 -1
- package/dist/esm/types/config.d.ts +15 -7
- package/dist/esm/types/config.d.ts.map +1 -1
- package/dist/esm/types/proxy.d.ts +2 -2
- package/dist/esm/types/proxy.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/esm/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthenticationError, APIError, PolicyViolationError } from './errors.js';
|
|
1
|
+
import { AuthenticationError, APIError, PolicyViolationError, ConfigurationError, ConnectorError, PlanExecutionError, } from './errors.js';
|
|
2
2
|
import { OpenAIInterceptor } from './interceptors/openai.js';
|
|
3
3
|
import { AnthropicInterceptor } from './interceptors/anthropic.js';
|
|
4
4
|
import { generateRequestId, debugLog } from './utils/helpers.js';
|
|
@@ -9,15 +9,19 @@ export class AxonFlow {
|
|
|
9
9
|
constructor(config) {
|
|
10
10
|
this.interceptors = [];
|
|
11
11
|
this.sessionCookie = null;
|
|
12
|
+
// Configuration validation
|
|
13
|
+
if (config.clientSecret && !config.clientId) {
|
|
14
|
+
throw new ConfigurationError('clientSecret requires clientId to be set. ' +
|
|
15
|
+
'Provide both clientId and clientSecret for OAuth2-style authentication.');
|
|
16
|
+
}
|
|
12
17
|
// Set defaults first to determine endpoint
|
|
13
18
|
const endpoint = config.endpoint || 'https://staging-eu.getaxonflow.com';
|
|
14
|
-
// Credentials
|
|
15
|
-
|
|
16
|
-
const hasCredentials = !!(config.licenseKey || config.apiKey);
|
|
19
|
+
// Credentials check: OAuth2-style (clientId/clientSecret)
|
|
20
|
+
const hasCredentials = !!(config.clientId && config.clientSecret);
|
|
17
21
|
// Set configuration
|
|
18
22
|
this.config = {
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
clientId: config.clientId,
|
|
24
|
+
clientSecret: config.clientSecret,
|
|
21
25
|
endpoint,
|
|
22
26
|
mode: config.mode || (hasCredentials ? 'production' : 'sandbox'),
|
|
23
27
|
tenant: config.tenant || 'default',
|
|
@@ -37,17 +41,33 @@ export class AxonFlow {
|
|
|
37
41
|
// Initialize interceptors
|
|
38
42
|
this.interceptors = [new OpenAIInterceptor(), new AnthropicInterceptor()];
|
|
39
43
|
if (this.config.debug) {
|
|
44
|
+
// Determine auth method for logging
|
|
45
|
+
const authMethod = hasCredentials ? 'client-credentials' : 'community (no auth)';
|
|
40
46
|
debugLog('AxonFlow initialized', {
|
|
41
47
|
mode: this.config.mode,
|
|
42
48
|
endpoint: this.config.endpoint,
|
|
43
|
-
authMethod
|
|
44
|
-
? this.config.licenseKey
|
|
45
|
-
? 'license-key'
|
|
46
|
-
: 'api-key'
|
|
47
|
-
: 'community (no auth)',
|
|
49
|
+
authMethod,
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Get authentication headers based on configured credentials.
|
|
55
|
+
*
|
|
56
|
+
* Uses OAuth2-style Basic auth: Authorization: Basic base64(clientId:clientSecret)
|
|
57
|
+
* Also adds X-Tenant-ID header from clientId for tenant context.
|
|
58
|
+
*
|
|
59
|
+
* @returns Headers object with authentication headers
|
|
60
|
+
*/
|
|
61
|
+
getAuthHeaders() {
|
|
62
|
+
const headers = {};
|
|
63
|
+
// OAuth2-style client credentials
|
|
64
|
+
if (this.config.clientId && this.config.clientSecret) {
|
|
65
|
+
const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
66
|
+
headers['Authorization'] = `Basic ${credentials}`;
|
|
67
|
+
headers['X-Tenant-ID'] = this.config.clientId;
|
|
68
|
+
}
|
|
69
|
+
return headers;
|
|
70
|
+
}
|
|
51
71
|
/**
|
|
52
72
|
* Main method to protect AI calls with governance
|
|
53
73
|
* @param aiCall The AI call to protect
|
|
@@ -166,8 +186,8 @@ export class AxonFlow {
|
|
|
166
186
|
// Transform SDK request to Agent API format
|
|
167
187
|
const agentRequest = {
|
|
168
188
|
query: request.aiRequest.prompt,
|
|
169
|
-
user_token:
|
|
170
|
-
client_id: this.config.tenant,
|
|
189
|
+
user_token: '',
|
|
190
|
+
client_id: this.config.clientId || this.config.tenant,
|
|
171
191
|
request_type: 'llm_chat',
|
|
172
192
|
context: {
|
|
173
193
|
provider: request.aiRequest.provider,
|
|
@@ -179,12 +199,8 @@ export class AxonFlow {
|
|
|
179
199
|
};
|
|
180
200
|
const headers = {
|
|
181
201
|
'Content-Type': 'application/json',
|
|
202
|
+
...this.getAuthHeaders(),
|
|
182
203
|
};
|
|
183
|
-
// Add auth headers only when credentials are provided
|
|
184
|
-
// Community/self-hosted mode works without credentials
|
|
185
|
-
if (this.config.licenseKey) {
|
|
186
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
187
|
-
}
|
|
188
204
|
const response = await fetch(url, {
|
|
189
205
|
method: 'POST',
|
|
190
206
|
headers,
|
|
@@ -247,9 +263,10 @@ export class AxonFlow {
|
|
|
247
263
|
/**
|
|
248
264
|
* Create a sandbox client for testing
|
|
249
265
|
*/
|
|
250
|
-
static sandbox(
|
|
266
|
+
static sandbox(clientId = 'demo-client', clientSecret = 'demo-secret') {
|
|
251
267
|
return new AxonFlow({
|
|
252
|
-
|
|
268
|
+
clientId,
|
|
269
|
+
clientSecret,
|
|
253
270
|
mode: 'sandbox',
|
|
254
271
|
endpoint: 'https://staging-eu.getaxonflow.com',
|
|
255
272
|
debug: true,
|
|
@@ -386,9 +403,11 @@ export class AxonFlow {
|
|
|
386
403
|
* ```
|
|
387
404
|
*/
|
|
388
405
|
async executeQuery(options) {
|
|
406
|
+
// Default to "anonymous" if userToken is empty/undefined (community mode)
|
|
407
|
+
const effectiveUserToken = options.userToken || 'anonymous';
|
|
389
408
|
const agentRequest = {
|
|
390
409
|
query: options.query,
|
|
391
|
-
user_token:
|
|
410
|
+
user_token: effectiveUserToken,
|
|
392
411
|
client_id: this.config.tenant,
|
|
393
412
|
request_type: options.requestType,
|
|
394
413
|
context: options.context || {},
|
|
@@ -396,15 +415,8 @@ export class AxonFlow {
|
|
|
396
415
|
const url = `${this.config.endpoint}/api/request`;
|
|
397
416
|
const headers = {
|
|
398
417
|
'Content-Type': 'application/json',
|
|
418
|
+
...this.getAuthHeaders(),
|
|
399
419
|
};
|
|
400
|
-
// Add auth headers only when credentials are provided
|
|
401
|
-
// Community/self-hosted mode works without credentials
|
|
402
|
-
if (this.config.licenseKey) {
|
|
403
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
404
|
-
}
|
|
405
|
-
else if (this.config.apiKey) {
|
|
406
|
-
headers['X-Client-Secret'] = this.config.apiKey;
|
|
407
|
-
}
|
|
408
420
|
if (this.config.debug) {
|
|
409
421
|
debugLog('Proxy Mode: executeQuery', {
|
|
410
422
|
requestType: options.requestType,
|
|
@@ -529,8 +541,8 @@ export class AxonFlow {
|
|
|
529
541
|
async queryConnector(connectorName, query, params) {
|
|
530
542
|
const agentRequest = {
|
|
531
543
|
query,
|
|
532
|
-
user_token:
|
|
533
|
-
client_id: this.config.tenant,
|
|
544
|
+
user_token: '',
|
|
545
|
+
client_id: this.config.clientId || this.config.tenant,
|
|
534
546
|
request_type: 'mcp-query',
|
|
535
547
|
context: {
|
|
536
548
|
connector: connectorName,
|
|
@@ -540,10 +552,8 @@ export class AxonFlow {
|
|
|
540
552
|
const url = `${this.config.endpoint}/api/request`;
|
|
541
553
|
const headers = {
|
|
542
554
|
'Content-Type': 'application/json',
|
|
555
|
+
...this.getAuthHeaders(),
|
|
543
556
|
};
|
|
544
|
-
if (this.config.licenseKey) {
|
|
545
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
546
|
-
}
|
|
547
557
|
const response = await fetch(url, {
|
|
548
558
|
method: 'POST',
|
|
549
559
|
headers,
|
|
@@ -552,7 +562,7 @@ export class AxonFlow {
|
|
|
552
562
|
});
|
|
553
563
|
if (!response.ok) {
|
|
554
564
|
const errorText = await response.text();
|
|
555
|
-
throw new
|
|
565
|
+
throw new ConnectorError(`Connector query failed: ${response.status} ${response.statusText} - ${errorText}`, connectorName, 'query');
|
|
556
566
|
}
|
|
557
567
|
const agentResponse = await response.json();
|
|
558
568
|
if (this.config.debug) {
|
|
@@ -582,10 +592,8 @@ export class AxonFlow {
|
|
|
582
592
|
const url = `${this.config.endpoint}/api/request`;
|
|
583
593
|
const headers = {
|
|
584
594
|
'Content-Type': 'application/json',
|
|
595
|
+
...this.getAuthHeaders(),
|
|
585
596
|
};
|
|
586
|
-
if (this.config.licenseKey) {
|
|
587
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
588
|
-
}
|
|
589
597
|
// Use mapTimeout for MAP operations (default 2 minutes)
|
|
590
598
|
const response = await fetch(url, {
|
|
591
599
|
method: 'POST',
|
|
@@ -595,11 +603,11 @@ export class AxonFlow {
|
|
|
595
603
|
});
|
|
596
604
|
if (!response.ok) {
|
|
597
605
|
const errorText = await response.text();
|
|
598
|
-
throw new
|
|
606
|
+
throw new PlanExecutionError(`Plan generation failed: ${response.status} ${response.statusText} - ${errorText}`, undefined, 'generation');
|
|
599
607
|
}
|
|
600
608
|
const agentResponse = await response.json();
|
|
601
609
|
if (!agentResponse.success) {
|
|
602
|
-
throw new
|
|
610
|
+
throw new PlanExecutionError(`Plan generation failed: ${agentResponse.error}`, undefined, 'generation');
|
|
603
611
|
}
|
|
604
612
|
// plan_id can be at top level or inside data
|
|
605
613
|
const planId = agentResponse.plan_id || agentResponse.data?.plan_id;
|
|
@@ -631,10 +639,8 @@ export class AxonFlow {
|
|
|
631
639
|
const url = `${this.config.endpoint}/api/request`;
|
|
632
640
|
const headers = {
|
|
633
641
|
'Content-Type': 'application/json',
|
|
642
|
+
...this.getAuthHeaders(),
|
|
634
643
|
};
|
|
635
|
-
if (this.config.licenseKey) {
|
|
636
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
637
|
-
}
|
|
638
644
|
// Use mapTimeout for MAP operations (default 2 minutes)
|
|
639
645
|
const response = await fetch(url, {
|
|
640
646
|
method: 'POST',
|
|
@@ -644,7 +650,7 @@ export class AxonFlow {
|
|
|
644
650
|
});
|
|
645
651
|
if (!response.ok) {
|
|
646
652
|
const errorText = await response.text();
|
|
647
|
-
throw new
|
|
653
|
+
throw new PlanExecutionError(`Plan execution failed: ${response.status} ${response.statusText} - ${errorText}`, planId, 'execution');
|
|
648
654
|
}
|
|
649
655
|
const agentResponse = await response.json();
|
|
650
656
|
if (this.config.debug) {
|
|
@@ -663,7 +669,7 @@ export class AxonFlow {
|
|
|
663
669
|
* Get the status of a running or completed plan
|
|
664
670
|
*/
|
|
665
671
|
async getPlanStatus(planId) {
|
|
666
|
-
const url = `${this.config.endpoint}/api/
|
|
672
|
+
const url = `${this.config.endpoint}/api/v1/plan/${planId}`;
|
|
667
673
|
const response = await fetch(url, {
|
|
668
674
|
method: 'GET',
|
|
669
675
|
signal: AbortSignal.timeout(this.config.timeout),
|
|
@@ -746,15 +752,8 @@ export class AxonFlow {
|
|
|
746
752
|
};
|
|
747
753
|
const headers = {
|
|
748
754
|
'Content-Type': 'application/json',
|
|
755
|
+
...this.getAuthHeaders(),
|
|
749
756
|
};
|
|
750
|
-
// Add auth headers only when credentials are provided
|
|
751
|
-
// Community/self-hosted mode works without credentials
|
|
752
|
-
if (this.config.licenseKey) {
|
|
753
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
754
|
-
}
|
|
755
|
-
else if (this.config.apiKey) {
|
|
756
|
-
headers['X-Client-Secret'] = this.config.apiKey;
|
|
757
|
-
}
|
|
758
757
|
if (this.config.debug) {
|
|
759
758
|
debugLog('Gateway Mode: Pre-check', { query: options.query.substring(0, 50) });
|
|
760
759
|
}
|
|
@@ -845,15 +844,8 @@ export class AxonFlow {
|
|
|
845
844
|
};
|
|
846
845
|
const headers = {
|
|
847
846
|
'Content-Type': 'application/json',
|
|
847
|
+
...this.getAuthHeaders(),
|
|
848
848
|
};
|
|
849
|
-
// Add auth headers only when credentials are provided
|
|
850
|
-
// Community/self-hosted mode works without credentials
|
|
851
|
-
if (this.config.licenseKey) {
|
|
852
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
853
|
-
}
|
|
854
|
-
else if (this.config.apiKey) {
|
|
855
|
-
headers['X-Client-Secret'] = this.config.apiKey;
|
|
856
|
-
}
|
|
857
849
|
if (this.config.debug) {
|
|
858
850
|
debugLog('Gateway Mode: Audit', {
|
|
859
851
|
contextId: options.contextId,
|
|
@@ -1035,24 +1027,20 @@ export class AxonFlow {
|
|
|
1035
1027
|
// Policy CRUD Methods - Static Policies
|
|
1036
1028
|
// ============================================================================
|
|
1037
1029
|
/**
|
|
1038
|
-
* Build authentication headers for API requests
|
|
1030
|
+
* Build authentication headers for API requests.
|
|
1031
|
+
* Includes Content-Type and X-Org-ID for policy APIs.
|
|
1032
|
+
* Uses getAuthHeaders() for authentication credentials.
|
|
1039
1033
|
*/
|
|
1040
1034
|
buildAuthHeaders() {
|
|
1041
1035
|
const headers = {
|
|
1042
1036
|
'Content-Type': 'application/json',
|
|
1037
|
+
...this.getAuthHeaders(),
|
|
1043
1038
|
};
|
|
1044
1039
|
// Always include tenant ID for policy APIs (X-Org-ID header for server compatibility)
|
|
1040
|
+
// Note: getAuthHeaders() already adds X-Tenant-ID when tenant is non-default
|
|
1045
1041
|
if (this.config.tenant) {
|
|
1046
1042
|
headers['X-Org-ID'] = this.config.tenant;
|
|
1047
1043
|
}
|
|
1048
|
-
// Add auth headers only when credentials are provided
|
|
1049
|
-
// Community/self-hosted mode works without credentials
|
|
1050
|
-
if (this.config.licenseKey) {
|
|
1051
|
-
headers['X-License-Key'] = this.config.licenseKey;
|
|
1052
|
-
}
|
|
1053
|
-
else if (this.config.apiKey) {
|
|
1054
|
-
headers['X-Client-Secret'] = this.config.apiKey;
|
|
1055
|
-
}
|
|
1056
1044
|
return headers;
|
|
1057
1045
|
}
|
|
1058
1046
|
/**
|
|
@@ -1077,8 +1065,8 @@ export class AxonFlow {
|
|
|
1077
1065
|
}
|
|
1078
1066
|
throw new APIError(response.status, response.statusText, errorText);
|
|
1079
1067
|
}
|
|
1080
|
-
// Handle
|
|
1081
|
-
if (response.status === 204
|
|
1068
|
+
// Handle 204 No Content responses
|
|
1069
|
+
if (response.status === 204) {
|
|
1082
1070
|
return undefined;
|
|
1083
1071
|
}
|
|
1084
1072
|
return response.json();
|
|
@@ -1432,7 +1420,7 @@ export class AxonFlow {
|
|
|
1432
1420
|
// API returns {"policies": [...]} wrapper via Agent proxy
|
|
1433
1421
|
const response = await this.orchestratorRequest('GET', path);
|
|
1434
1422
|
// Handle both wrapped and unwrapped responses for compatibility
|
|
1435
|
-
return Array.isArray(response) ? response : response.policies;
|
|
1423
|
+
return Array.isArray(response) ? response : response.policies || [];
|
|
1436
1424
|
}
|
|
1437
1425
|
/**
|
|
1438
1426
|
* Get a specific dynamic policy by ID.
|
|
@@ -1540,7 +1528,7 @@ export class AxonFlow {
|
|
|
1540
1528
|
// API returns {"policies": [...]} wrapper via Agent proxy
|
|
1541
1529
|
const response = await this.orchestratorRequest('GET', path);
|
|
1542
1530
|
// Handle both wrapped and unwrapped responses for compatibility
|
|
1543
|
-
return Array.isArray(response) ? response : response.policies;
|
|
1531
|
+
return Array.isArray(response) ? response : response.policies || [];
|
|
1544
1532
|
}
|
|
1545
1533
|
// ============================================================================
|
|
1546
1534
|
// Portal Authentication Methods (Enterprise)
|
|
@@ -1925,6 +1913,49 @@ export class AxonFlow {
|
|
|
1925
1913
|
providerType: response.provider_type,
|
|
1926
1914
|
};
|
|
1927
1915
|
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Close a PR without merging and optionally delete the branch.
|
|
1918
|
+
* Useful for cleaning up test PRs created by examples.
|
|
1919
|
+
*
|
|
1920
|
+
* @param prId - PR record ID
|
|
1921
|
+
* @param deleteBranch - Whether to delete the associated branch (default: true)
|
|
1922
|
+
* @returns Closed PR record
|
|
1923
|
+
*
|
|
1924
|
+
* @example
|
|
1925
|
+
* ```typescript
|
|
1926
|
+
* // Close PR and delete branch
|
|
1927
|
+
* const pr = await axonflow.closePR('pr_123');
|
|
1928
|
+
* console.log(`PR #${pr.prNumber} closed`);
|
|
1929
|
+
*
|
|
1930
|
+
* // Close PR but keep branch
|
|
1931
|
+
* const pr = await axonflow.closePR('pr_123', false);
|
|
1932
|
+
* ```
|
|
1933
|
+
*/
|
|
1934
|
+
async closePR(prId, deleteBranch = true) {
|
|
1935
|
+
if (this.config.debug) {
|
|
1936
|
+
debugLog('Closing PR', { prId, deleteBranch });
|
|
1937
|
+
}
|
|
1938
|
+
const query = deleteBranch ? '?delete_branch=true' : '';
|
|
1939
|
+
const response = await this.portalRequest('DELETE', `/api/v1/code-governance/prs/${prId}${query}`);
|
|
1940
|
+
return {
|
|
1941
|
+
id: response.id,
|
|
1942
|
+
prNumber: response.pr_number,
|
|
1943
|
+
prUrl: response.pr_url,
|
|
1944
|
+
title: response.title,
|
|
1945
|
+
state: response.state,
|
|
1946
|
+
owner: response.owner,
|
|
1947
|
+
repo: response.repo,
|
|
1948
|
+
headBranch: response.head_branch,
|
|
1949
|
+
baseBranch: response.base_branch,
|
|
1950
|
+
filesCount: response.files_count,
|
|
1951
|
+
secretsDetected: response.secrets_detected,
|
|
1952
|
+
unsafePatterns: response.unsafe_patterns,
|
|
1953
|
+
createdAt: response.created_at,
|
|
1954
|
+
closedAt: response.closed_at,
|
|
1955
|
+
createdBy: response.created_by,
|
|
1956
|
+
providerType: response.provider_type,
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1928
1959
|
/**
|
|
1929
1960
|
* Sync PR status with the Git provider.
|
|
1930
1961
|
* This updates the local record with the current state from GitHub/GitLab/Bitbucket.
|
|
@@ -2118,8 +2149,8 @@ export class AxonFlow {
|
|
|
2118
2149
|
}
|
|
2119
2150
|
throw new APIError(response.status, response.statusText, errorText);
|
|
2120
2151
|
}
|
|
2121
|
-
// Handle
|
|
2122
|
-
if (response.status === 204
|
|
2152
|
+
// Handle 204 No Content responses
|
|
2153
|
+
if (response.status === 204) {
|
|
2123
2154
|
return undefined;
|
|
2124
2155
|
}
|
|
2125
2156
|
return response.json();
|
|
@@ -2162,8 +2193,8 @@ export class AxonFlow {
|
|
|
2162
2193
|
}
|
|
2163
2194
|
throw new APIError(response.status, response.statusText, errorText);
|
|
2164
2195
|
}
|
|
2165
|
-
// Handle
|
|
2166
|
-
if (response.status === 204
|
|
2196
|
+
// Handle 204 No Content responses
|
|
2197
|
+
if (response.status === 204) {
|
|
2167
2198
|
return undefined;
|
|
2168
2199
|
}
|
|
2169
2200
|
return response.json();
|