@axonflow/sdk 2.0.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 +142 -86
- 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/policies.d.ts +14 -1
- package/dist/cjs/types/policies.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 +143 -87
- 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/policies.d.ts +14 -1
- package/dist/esm/types/policies.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,23 +1027,19 @@ 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
|
-
// Always include tenant ID for policy APIs
|
|
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
|
-
headers['X-
|
|
1047
|
-
}
|
|
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;
|
|
1042
|
+
headers['X-Org-ID'] = this.config.tenant;
|
|
1055
1043
|
}
|
|
1056
1044
|
return headers;
|
|
1057
1045
|
}
|
|
@@ -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();
|
|
@@ -1315,7 +1303,16 @@ export class AxonFlow {
|
|
|
1315
1303
|
debugLog('Getting static policy versions', { id });
|
|
1316
1304
|
}
|
|
1317
1305
|
const response = await this.policyRequest('GET', `/api/v1/static-policies/${id}/versions`);
|
|
1318
|
-
|
|
1306
|
+
// Transform snake_case API response to camelCase
|
|
1307
|
+
return response.versions.map(v => ({
|
|
1308
|
+
version: v.version,
|
|
1309
|
+
changedBy: v.changed_by,
|
|
1310
|
+
changedAt: v.changed_at,
|
|
1311
|
+
changeType: v.change_type,
|
|
1312
|
+
changeDescription: v.change_description,
|
|
1313
|
+
previousValues: v.previous_values,
|
|
1314
|
+
newValues: v.new_values,
|
|
1315
|
+
}));
|
|
1319
1316
|
}
|
|
1320
1317
|
// ============================================================================
|
|
1321
1318
|
// Policy Override Methods (Enterprise)
|
|
@@ -1420,7 +1417,10 @@ export class AxonFlow {
|
|
|
1420
1417
|
if (this.config.debug) {
|
|
1421
1418
|
debugLog('Listing dynamic policies', { options });
|
|
1422
1419
|
}
|
|
1423
|
-
|
|
1420
|
+
// API returns {"policies": [...]} wrapper via Agent proxy
|
|
1421
|
+
const response = await this.orchestratorRequest('GET', path);
|
|
1422
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1423
|
+
return Array.isArray(response) ? response : response.policies || [];
|
|
1424
1424
|
}
|
|
1425
1425
|
/**
|
|
1426
1426
|
* Get a specific dynamic policy by ID.
|
|
@@ -1432,7 +1432,10 @@ export class AxonFlow {
|
|
|
1432
1432
|
if (this.config.debug) {
|
|
1433
1433
|
debugLog('Getting dynamic policy', { id });
|
|
1434
1434
|
}
|
|
1435
|
-
|
|
1435
|
+
// API returns {"policy": {...}} wrapper via Agent proxy
|
|
1436
|
+
const response = await this.orchestratorRequest('GET', `/api/v1/dynamic-policies/${id}`);
|
|
1437
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1438
|
+
return 'policy' in response ? response.policy : response;
|
|
1436
1439
|
}
|
|
1437
1440
|
/**
|
|
1438
1441
|
* Create a new dynamic policy.
|
|
@@ -1457,7 +1460,10 @@ export class AxonFlow {
|
|
|
1457
1460
|
if (this.config.debug) {
|
|
1458
1461
|
debugLog('Creating dynamic policy', { name: policy.name });
|
|
1459
1462
|
}
|
|
1460
|
-
|
|
1463
|
+
// API returns {"policy": {...}} wrapper via Agent proxy
|
|
1464
|
+
const response = await this.orchestratorRequest('POST', '/api/v1/dynamic-policies', policy);
|
|
1465
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1466
|
+
return 'policy' in response ? response.policy : response;
|
|
1461
1467
|
}
|
|
1462
1468
|
/**
|
|
1463
1469
|
* Update an existing dynamic policy.
|
|
@@ -1470,7 +1476,10 @@ export class AxonFlow {
|
|
|
1470
1476
|
if (this.config.debug) {
|
|
1471
1477
|
debugLog('Updating dynamic policy', { id, updates: Object.keys(policy) });
|
|
1472
1478
|
}
|
|
1473
|
-
|
|
1479
|
+
// API returns {"policy": {...}} wrapper via Agent proxy
|
|
1480
|
+
const response = await this.orchestratorRequest('PUT', `/api/v1/dynamic-policies/${id}`, policy);
|
|
1481
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1482
|
+
return 'policy' in response ? response.policy : response;
|
|
1474
1483
|
}
|
|
1475
1484
|
/**
|
|
1476
1485
|
* Delete a dynamic policy.
|
|
@@ -1494,9 +1503,10 @@ export class AxonFlow {
|
|
|
1494
1503
|
if (this.config.debug) {
|
|
1495
1504
|
debugLog('Toggling dynamic policy', { id, enabled });
|
|
1496
1505
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1506
|
+
// API returns {"policy": {...}} wrapper via Agent proxy
|
|
1507
|
+
const response = await this.orchestratorRequest('PUT', `/api/v1/dynamic-policies/${id}`, { enabled });
|
|
1508
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1509
|
+
return 'policy' in response ? response.policy : response;
|
|
1500
1510
|
}
|
|
1501
1511
|
/**
|
|
1502
1512
|
* Get effective dynamic policies with tier inheritance applied.
|
|
@@ -1515,7 +1525,10 @@ export class AxonFlow {
|
|
|
1515
1525
|
if (this.config.debug) {
|
|
1516
1526
|
debugLog('Getting effective dynamic policies', { options });
|
|
1517
1527
|
}
|
|
1518
|
-
|
|
1528
|
+
// API returns {"policies": [...]} wrapper via Agent proxy
|
|
1529
|
+
const response = await this.orchestratorRequest('GET', path);
|
|
1530
|
+
// Handle both wrapped and unwrapped responses for compatibility
|
|
1531
|
+
return Array.isArray(response) ? response : response.policies || [];
|
|
1519
1532
|
}
|
|
1520
1533
|
// ============================================================================
|
|
1521
1534
|
// Portal Authentication Methods (Enterprise)
|
|
@@ -1900,6 +1913,49 @@ export class AxonFlow {
|
|
|
1900
1913
|
providerType: response.provider_type,
|
|
1901
1914
|
};
|
|
1902
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
|
+
}
|
|
1903
1959
|
/**
|
|
1904
1960
|
* Sync PR status with the Git provider.
|
|
1905
1961
|
* This updates the local record with the current state from GitHub/GitLab/Bitbucket.
|
|
@@ -2093,8 +2149,8 @@ export class AxonFlow {
|
|
|
2093
2149
|
}
|
|
2094
2150
|
throw new APIError(response.status, response.statusText, errorText);
|
|
2095
2151
|
}
|
|
2096
|
-
// Handle
|
|
2097
|
-
if (response.status === 204
|
|
2152
|
+
// Handle 204 No Content responses
|
|
2153
|
+
if (response.status === 204) {
|
|
2098
2154
|
return undefined;
|
|
2099
2155
|
}
|
|
2100
2156
|
return response.json();
|
|
@@ -2137,8 +2193,8 @@ export class AxonFlow {
|
|
|
2137
2193
|
}
|
|
2138
2194
|
throw new APIError(response.status, response.statusText, errorText);
|
|
2139
2195
|
}
|
|
2140
|
-
// Handle
|
|
2141
|
-
if (response.status === 204
|
|
2196
|
+
// Handle 204 No Content responses
|
|
2197
|
+
if (response.status === 204) {
|
|
2142
2198
|
return undefined;
|
|
2143
2199
|
}
|
|
2144
2200
|
return response.json();
|