@axonflow/sdk 1.13.0 → 2.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/dist/cjs/client.d.ts +120 -5
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +363 -37
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/types/config.d.ts +2 -5
- package/dist/cjs/types/config.d.ts.map +1 -1
- package/dist/cjs/types/gateway.d.ts +83 -0
- package/dist/cjs/types/gateway.d.ts.map +1 -1
- package/dist/cjs/types/policies.d.ts +1 -1
- package/dist/cjs/types/policies.d.ts.map +1 -1
- package/dist/esm/client.d.ts +120 -5
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +363 -37
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/types/config.d.ts +2 -5
- package/dist/esm/types/config.d.ts.map +1 -1
- package/dist/esm/types/gateway.d.ts +83 -0
- package/dist/esm/types/gateway.d.ts.map +1 -1
- package/dist/esm/types/policies.d.ts +1 -1
- package/dist/esm/types/policies.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/client.js
CHANGED
|
@@ -11,6 +11,7 @@ const helpers_1 = require("./utils/helpers");
|
|
|
11
11
|
class AxonFlow {
|
|
12
12
|
constructor(config) {
|
|
13
13
|
this.interceptors = [];
|
|
14
|
+
this.sessionCookie = null;
|
|
14
15
|
// Set defaults first to determine endpoint
|
|
15
16
|
const endpoint = config.endpoint || 'https://staging-eu.getaxonflow.com';
|
|
16
17
|
// Credentials are optional for community/self-hosted deployments
|
|
@@ -21,7 +22,6 @@ class AxonFlow {
|
|
|
21
22
|
apiKey: config.apiKey,
|
|
22
23
|
licenseKey: config.licenseKey,
|
|
23
24
|
endpoint,
|
|
24
|
-
orchestratorEndpoint: config.orchestratorEndpoint,
|
|
25
25
|
mode: config.mode || (hasCredentials ? 'production' : 'sandbox'),
|
|
26
26
|
tenant: config.tenant || 'default',
|
|
27
27
|
debug: config.debug || false,
|
|
@@ -325,7 +325,7 @@ class AxonFlow {
|
|
|
325
325
|
* ```
|
|
326
326
|
*/
|
|
327
327
|
async orchestratorHealthCheck() {
|
|
328
|
-
const url = `${this.
|
|
328
|
+
const url = `${this.config.endpoint}/health`;
|
|
329
329
|
try {
|
|
330
330
|
const response = await fetch(url, {
|
|
331
331
|
method: 'GET',
|
|
@@ -783,6 +783,7 @@ class AxonFlow {
|
|
|
783
783
|
const result = {
|
|
784
784
|
contextId: data.context_id,
|
|
785
785
|
approved: data.approved,
|
|
786
|
+
requiresRedaction: data.requires_redaction || false,
|
|
786
787
|
approvedData: data.approved_data || {},
|
|
787
788
|
policies: data.policies || [],
|
|
788
789
|
expiresAt,
|
|
@@ -887,6 +888,153 @@ class AxonFlow {
|
|
|
887
888
|
return result;
|
|
888
889
|
}
|
|
889
890
|
// ============================================================================
|
|
891
|
+
// Audit Log Read Methods
|
|
892
|
+
// ============================================================================
|
|
893
|
+
/**
|
|
894
|
+
* Search audit logs with optional filters.
|
|
895
|
+
*
|
|
896
|
+
* Query the AxonFlow orchestrator for audit logs matching the specified
|
|
897
|
+
* criteria. Use this for compliance dashboards, security investigations,
|
|
898
|
+
* and operational monitoring.
|
|
899
|
+
*
|
|
900
|
+
* @param request - Search filters and pagination options
|
|
901
|
+
* @returns Promise resolving to audit search response
|
|
902
|
+
*
|
|
903
|
+
* @example
|
|
904
|
+
* ```typescript
|
|
905
|
+
* // Search for logs from a specific user in the last 24 hours
|
|
906
|
+
* const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
|
907
|
+
* const result = await client.searchAuditLogs({
|
|
908
|
+
* userEmail: 'analyst@company.com',
|
|
909
|
+
* startTime: yesterday,
|
|
910
|
+
* limit: 100,
|
|
911
|
+
* });
|
|
912
|
+
*
|
|
913
|
+
* for (const entry of result.entries) {
|
|
914
|
+
* console.log(`[${entry.timestamp}] ${entry.userEmail}: ${entry.querySummary}`);
|
|
915
|
+
* }
|
|
916
|
+
* ```
|
|
917
|
+
*/
|
|
918
|
+
async searchAuditLogs(request) {
|
|
919
|
+
const limit = Math.min(request?.limit ?? 100, 1000);
|
|
920
|
+
const offset = request?.offset ?? 0;
|
|
921
|
+
// Build request body with only defined values
|
|
922
|
+
const body = { limit };
|
|
923
|
+
if (request?.userEmail)
|
|
924
|
+
body.user_email = request.userEmail;
|
|
925
|
+
if (request?.clientId)
|
|
926
|
+
body.client_id = request.clientId;
|
|
927
|
+
if (request?.startTime)
|
|
928
|
+
body.start_time = request.startTime.toISOString();
|
|
929
|
+
if (request?.endTime)
|
|
930
|
+
body.end_time = request.endTime.toISOString();
|
|
931
|
+
if (request?.requestType)
|
|
932
|
+
body.request_type = request.requestType;
|
|
933
|
+
if (offset > 0)
|
|
934
|
+
body.offset = offset;
|
|
935
|
+
if (this.config.debug) {
|
|
936
|
+
(0, helpers_1.debugLog)('Searching audit logs', { limit, offset });
|
|
937
|
+
}
|
|
938
|
+
const response = await this.orchestratorRequest('POST', '/api/v1/audit/search', body);
|
|
939
|
+
// Handle both array and wrapped response formats
|
|
940
|
+
if (Array.isArray(response)) {
|
|
941
|
+
const entries = response.map(e => this.parseAuditLogEntry(e));
|
|
942
|
+
return {
|
|
943
|
+
entries,
|
|
944
|
+
total: entries.length,
|
|
945
|
+
limit,
|
|
946
|
+
offset,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
const data = response;
|
|
950
|
+
const entries = (data.entries || []).map(e => this.parseAuditLogEntry(e));
|
|
951
|
+
return {
|
|
952
|
+
entries,
|
|
953
|
+
total: data.total ?? entries.length,
|
|
954
|
+
limit: data.limit ?? limit,
|
|
955
|
+
offset: data.offset ?? offset,
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Get recent audit logs for a specific tenant.
|
|
960
|
+
*
|
|
961
|
+
* Convenience method for tenant-scoped audit queries. Use this when you
|
|
962
|
+
* need to view all recent activity for a specific tenant.
|
|
963
|
+
*
|
|
964
|
+
* @param tenantId - The tenant identifier to query
|
|
965
|
+
* @param options - Pagination options (limit, offset)
|
|
966
|
+
* @returns Promise resolving to audit search response
|
|
967
|
+
* @throws Error if tenantId is empty
|
|
968
|
+
*
|
|
969
|
+
* @example
|
|
970
|
+
* ```typescript
|
|
971
|
+
* // Get the last 50 audit logs for a tenant
|
|
972
|
+
* const result = await client.getAuditLogsByTenant('tenant-abc');
|
|
973
|
+
* console.log(`Found ${result.entries.length} entries`);
|
|
974
|
+
*
|
|
975
|
+
* // With custom options
|
|
976
|
+
* const result2 = await client.getAuditLogsByTenant('tenant-abc', {
|
|
977
|
+
* limit: 100,
|
|
978
|
+
* offset: 50,
|
|
979
|
+
* });
|
|
980
|
+
* ```
|
|
981
|
+
*/
|
|
982
|
+
async getAuditLogsByTenant(tenantId, options) {
|
|
983
|
+
if (!tenantId) {
|
|
984
|
+
throw new Error('tenantId is required');
|
|
985
|
+
}
|
|
986
|
+
const limit = Math.min(options?.limit ?? 50, 1000);
|
|
987
|
+
const offset = options?.offset ?? 0;
|
|
988
|
+
if (this.config.debug) {
|
|
989
|
+
(0, helpers_1.debugLog)('Getting audit logs for tenant', { tenantId, limit, offset });
|
|
990
|
+
}
|
|
991
|
+
const path = `/api/v1/audit/tenant/${encodeURIComponent(tenantId)}?limit=${limit}&offset=${offset}`;
|
|
992
|
+
const response = await this.orchestratorRequest('GET', path);
|
|
993
|
+
// Handle both array and wrapped response formats
|
|
994
|
+
if (Array.isArray(response)) {
|
|
995
|
+
const entries = response.map(e => this.parseAuditLogEntry(e));
|
|
996
|
+
return {
|
|
997
|
+
entries,
|
|
998
|
+
total: entries.length,
|
|
999
|
+
limit,
|
|
1000
|
+
offset,
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
const data = response;
|
|
1004
|
+
const entries = (data.entries || []).map(e => this.parseAuditLogEntry(e));
|
|
1005
|
+
return {
|
|
1006
|
+
entries,
|
|
1007
|
+
total: data.total ?? entries.length,
|
|
1008
|
+
limit: data.limit ?? limit,
|
|
1009
|
+
offset: data.offset ?? offset,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Parse a raw audit log entry from the API into the typed interface
|
|
1014
|
+
*/
|
|
1015
|
+
parseAuditLogEntry(raw) {
|
|
1016
|
+
const data = raw;
|
|
1017
|
+
return {
|
|
1018
|
+
id: data.id ?? '',
|
|
1019
|
+
requestId: data.request_id ?? '',
|
|
1020
|
+
timestamp: data.timestamp ? new Date(data.timestamp) : new Date(),
|
|
1021
|
+
userEmail: data.user_email ?? '',
|
|
1022
|
+
clientId: data.client_id ?? '',
|
|
1023
|
+
tenantId: data.tenant_id ?? '',
|
|
1024
|
+
requestType: data.request_type ?? '',
|
|
1025
|
+
querySummary: data.query_summary ?? '',
|
|
1026
|
+
success: data.success ?? true,
|
|
1027
|
+
blocked: data.blocked ?? false,
|
|
1028
|
+
riskScore: data.risk_score ?? 0,
|
|
1029
|
+
provider: data.provider ?? '',
|
|
1030
|
+
model: data.model ?? '',
|
|
1031
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
1032
|
+
latencyMs: data.latency_ms ?? 0,
|
|
1033
|
+
policyViolations: data.policy_violations ?? [],
|
|
1034
|
+
metadata: data.metadata ?? {},
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
// ============================================================================
|
|
890
1038
|
// Policy CRUD Methods - Static Policies
|
|
891
1039
|
// ============================================================================
|
|
892
1040
|
/**
|
|
@@ -1271,7 +1419,7 @@ class AxonFlow {
|
|
|
1271
1419
|
if (options?.search)
|
|
1272
1420
|
params.set('search', options.search);
|
|
1273
1421
|
const queryString = params.toString();
|
|
1274
|
-
const path = `/api/v1/policies
|
|
1422
|
+
const path = `/api/v1/dynamic-policies${queryString ? `?${queryString}` : ''}`;
|
|
1275
1423
|
if (this.config.debug) {
|
|
1276
1424
|
(0, helpers_1.debugLog)('Listing dynamic policies', { options });
|
|
1277
1425
|
}
|
|
@@ -1287,7 +1435,7 @@ class AxonFlow {
|
|
|
1287
1435
|
if (this.config.debug) {
|
|
1288
1436
|
(0, helpers_1.debugLog)('Getting dynamic policy', { id });
|
|
1289
1437
|
}
|
|
1290
|
-
return this.orchestratorRequest('GET', `/api/v1/policies
|
|
1438
|
+
return this.orchestratorRequest('GET', `/api/v1/dynamic-policies/${id}`);
|
|
1291
1439
|
}
|
|
1292
1440
|
/**
|
|
1293
1441
|
* Create a new dynamic policy.
|
|
@@ -1312,7 +1460,7 @@ class AxonFlow {
|
|
|
1312
1460
|
if (this.config.debug) {
|
|
1313
1461
|
(0, helpers_1.debugLog)('Creating dynamic policy', { name: policy.name });
|
|
1314
1462
|
}
|
|
1315
|
-
return this.orchestratorRequest('POST', '/api/v1/policies
|
|
1463
|
+
return this.orchestratorRequest('POST', '/api/v1/dynamic-policies', policy);
|
|
1316
1464
|
}
|
|
1317
1465
|
/**
|
|
1318
1466
|
* Update an existing dynamic policy.
|
|
@@ -1325,7 +1473,7 @@ class AxonFlow {
|
|
|
1325
1473
|
if (this.config.debug) {
|
|
1326
1474
|
(0, helpers_1.debugLog)('Updating dynamic policy', { id, updates: Object.keys(policy) });
|
|
1327
1475
|
}
|
|
1328
|
-
return this.orchestratorRequest('PUT', `/api/v1/policies
|
|
1476
|
+
return this.orchestratorRequest('PUT', `/api/v1/dynamic-policies/${id}`, policy);
|
|
1329
1477
|
}
|
|
1330
1478
|
/**
|
|
1331
1479
|
* Delete a dynamic policy.
|
|
@@ -1336,7 +1484,7 @@ class AxonFlow {
|
|
|
1336
1484
|
if (this.config.debug) {
|
|
1337
1485
|
(0, helpers_1.debugLog)('Deleting dynamic policy', { id });
|
|
1338
1486
|
}
|
|
1339
|
-
await this.orchestratorRequest('DELETE', `/api/v1/policies
|
|
1487
|
+
await this.orchestratorRequest('DELETE', `/api/v1/dynamic-policies/${id}`);
|
|
1340
1488
|
}
|
|
1341
1489
|
/**
|
|
1342
1490
|
* Toggle a dynamic policy's enabled status.
|
|
@@ -1349,7 +1497,7 @@ class AxonFlow {
|
|
|
1349
1497
|
if (this.config.debug) {
|
|
1350
1498
|
(0, helpers_1.debugLog)('Toggling dynamic policy', { id, enabled });
|
|
1351
1499
|
}
|
|
1352
|
-
return this.orchestratorRequest('PATCH', `/api/v1/policies
|
|
1500
|
+
return this.orchestratorRequest('PATCH', `/api/v1/dynamic-policies/${id}`, {
|
|
1353
1501
|
enabled,
|
|
1354
1502
|
});
|
|
1355
1503
|
}
|
|
@@ -1366,13 +1514,97 @@ class AxonFlow {
|
|
|
1366
1514
|
if (options?.includeDisabled)
|
|
1367
1515
|
params.set('include_disabled', 'true');
|
|
1368
1516
|
const queryString = params.toString();
|
|
1369
|
-
const path = `/api/v1/policies/
|
|
1517
|
+
const path = `/api/v1/dynamic-policies/effective${queryString ? `?${queryString}` : ''}`;
|
|
1370
1518
|
if (this.config.debug) {
|
|
1371
1519
|
(0, helpers_1.debugLog)('Getting effective dynamic policies', { options });
|
|
1372
1520
|
}
|
|
1373
1521
|
return this.orchestratorRequest('GET', path);
|
|
1374
1522
|
}
|
|
1375
1523
|
// ============================================================================
|
|
1524
|
+
// Portal Authentication Methods (Enterprise)
|
|
1525
|
+
// ============================================================================
|
|
1526
|
+
/**
|
|
1527
|
+
* Login to Customer Portal and store session cookie.
|
|
1528
|
+
* Required before using Code Governance methods.
|
|
1529
|
+
*
|
|
1530
|
+
* @param orgId - Organization ID
|
|
1531
|
+
* @param password - Organization password
|
|
1532
|
+
* @returns Login response with session info
|
|
1533
|
+
*
|
|
1534
|
+
* @example
|
|
1535
|
+
* ```typescript
|
|
1536
|
+
* const login = await axonflow.loginToPortal('test-org-001', 'test123');
|
|
1537
|
+
* console.log(`Logged in as ${login.name}`);
|
|
1538
|
+
*
|
|
1539
|
+
* // Now you can use Code Governance methods
|
|
1540
|
+
* const providers = await axonflow.listGitProviders();
|
|
1541
|
+
* ```
|
|
1542
|
+
*/
|
|
1543
|
+
async loginToPortal(orgId, password) {
|
|
1544
|
+
const url = `${this.config.endpoint}/api/v1/auth/login`;
|
|
1545
|
+
const response = await fetch(url, {
|
|
1546
|
+
method: 'POST',
|
|
1547
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1548
|
+
body: JSON.stringify({ org_id: orgId, password }),
|
|
1549
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
1550
|
+
});
|
|
1551
|
+
if (!response.ok) {
|
|
1552
|
+
const errorText = await response.text();
|
|
1553
|
+
throw new errors_1.AuthenticationError(`Login failed: ${errorText}`);
|
|
1554
|
+
}
|
|
1555
|
+
const result = (await response.json());
|
|
1556
|
+
// Extract session cookie from response
|
|
1557
|
+
const cookies = response.headers.get('set-cookie');
|
|
1558
|
+
if (cookies) {
|
|
1559
|
+
const match = cookies.match(/axonflow_session=([^;]+)/);
|
|
1560
|
+
if (match) {
|
|
1561
|
+
this.sessionCookie = match[1];
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
// Fallback to session_id in response body
|
|
1565
|
+
if (!this.sessionCookie && result.session_id) {
|
|
1566
|
+
this.sessionCookie = result.session_id;
|
|
1567
|
+
}
|
|
1568
|
+
if (this.config.debug) {
|
|
1569
|
+
(0, helpers_1.debugLog)('Portal login successful', { orgId });
|
|
1570
|
+
}
|
|
1571
|
+
return {
|
|
1572
|
+
sessionId: result.session_id,
|
|
1573
|
+
orgId: result.org_id,
|
|
1574
|
+
email: result.email,
|
|
1575
|
+
name: result.name,
|
|
1576
|
+
expiresAt: result.expires_at,
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Logout from Customer Portal and clear session cookie.
|
|
1581
|
+
*/
|
|
1582
|
+
async logoutFromPortal() {
|
|
1583
|
+
if (!this.sessionCookie) {
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
try {
|
|
1587
|
+
await fetch(`${this.config.endpoint}/api/v1/auth/logout`, {
|
|
1588
|
+
method: 'POST',
|
|
1589
|
+
headers: { Cookie: `axonflow_session=${this.sessionCookie}` },
|
|
1590
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
catch {
|
|
1594
|
+
// Ignore logout errors
|
|
1595
|
+
}
|
|
1596
|
+
this.sessionCookie = null;
|
|
1597
|
+
if (this.config.debug) {
|
|
1598
|
+
(0, helpers_1.debugLog)('Portal logout successful');
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Check if logged in to Customer Portal.
|
|
1603
|
+
*/
|
|
1604
|
+
isLoggedIn() {
|
|
1605
|
+
return this.sessionCookie !== null;
|
|
1606
|
+
}
|
|
1607
|
+
// ============================================================================
|
|
1376
1608
|
// Code Governance Methods (Enterprise)
|
|
1377
1609
|
// ============================================================================
|
|
1378
1610
|
/**
|
|
@@ -1414,7 +1646,7 @@ class AxonFlow {
|
|
|
1414
1646
|
apiRequest.installation_id = request.installationId;
|
|
1415
1647
|
if (request.privateKey)
|
|
1416
1648
|
apiRequest.private_key = request.privateKey;
|
|
1417
|
-
return this.
|
|
1649
|
+
return this.portalRequest('POST', '/api/v1/code-governance/git-providers/validate', apiRequest);
|
|
1418
1650
|
}
|
|
1419
1651
|
/**
|
|
1420
1652
|
* Configure a Git provider for code governance.
|
|
@@ -1465,7 +1697,7 @@ class AxonFlow {
|
|
|
1465
1697
|
apiRequest.installation_id = request.installationId;
|
|
1466
1698
|
if (request.privateKey)
|
|
1467
1699
|
apiRequest.private_key = request.privateKey;
|
|
1468
|
-
return this.
|
|
1700
|
+
return this.portalRequest('POST', '/api/v1/code-governance/git-providers', apiRequest);
|
|
1469
1701
|
}
|
|
1470
1702
|
/**
|
|
1471
1703
|
* List all configured Git providers for the tenant.
|
|
@@ -1483,7 +1715,7 @@ class AxonFlow {
|
|
|
1483
1715
|
if (this.config.debug) {
|
|
1484
1716
|
(0, helpers_1.debugLog)('Listing Git providers');
|
|
1485
1717
|
}
|
|
1486
|
-
return this.
|
|
1718
|
+
return this.portalRequest('GET', '/api/v1/code-governance/git-providers');
|
|
1487
1719
|
}
|
|
1488
1720
|
/**
|
|
1489
1721
|
* Delete a configured Git provider.
|
|
@@ -1499,7 +1731,7 @@ class AxonFlow {
|
|
|
1499
1731
|
if (this.config.debug) {
|
|
1500
1732
|
(0, helpers_1.debugLog)('Deleting Git provider', { type });
|
|
1501
1733
|
}
|
|
1502
|
-
await this.
|
|
1734
|
+
await this.portalRequest('DELETE', `/api/v1/code-governance/git-providers/${type}`);
|
|
1503
1735
|
}
|
|
1504
1736
|
/**
|
|
1505
1737
|
* Create a Pull Request from LLM-generated code.
|
|
@@ -1567,7 +1799,7 @@ class AxonFlow {
|
|
|
1567
1799
|
apiRequest.secrets_detected = request.secretsDetected;
|
|
1568
1800
|
if (request.unsafePatterns !== undefined)
|
|
1569
1801
|
apiRequest.unsafe_patterns = request.unsafePatterns;
|
|
1570
|
-
const response = await this.
|
|
1802
|
+
const response = await this.portalRequest('POST', '/api/v1/code-governance/prs', apiRequest);
|
|
1571
1803
|
// Transform snake_case response to camelCase
|
|
1572
1804
|
return {
|
|
1573
1805
|
prId: response.pr_id,
|
|
@@ -1612,10 +1844,10 @@ class AxonFlow {
|
|
|
1612
1844
|
if (this.config.debug) {
|
|
1613
1845
|
(0, helpers_1.debugLog)('Listing PRs', { options });
|
|
1614
1846
|
}
|
|
1615
|
-
const response = await this.
|
|
1847
|
+
const response = await this.portalRequest('GET', path);
|
|
1616
1848
|
// Transform snake_case response to camelCase
|
|
1617
1849
|
return {
|
|
1618
|
-
prs: response.prs.map(pr => ({
|
|
1850
|
+
prs: (response.prs || []).map(pr => ({
|
|
1619
1851
|
id: pr.id,
|
|
1620
1852
|
prNumber: pr.pr_number,
|
|
1621
1853
|
prUrl: pr.pr_url,
|
|
@@ -1651,7 +1883,7 @@ class AxonFlow {
|
|
|
1651
1883
|
if (this.config.debug) {
|
|
1652
1884
|
(0, helpers_1.debugLog)('Getting PR', { prId });
|
|
1653
1885
|
}
|
|
1654
|
-
const response = await this.
|
|
1886
|
+
const response = await this.portalRequest('GET', `/api/v1/code-governance/prs/${prId}`);
|
|
1655
1887
|
// Transform snake_case response to camelCase
|
|
1656
1888
|
return {
|
|
1657
1889
|
id: response.id,
|
|
@@ -1688,7 +1920,7 @@ class AxonFlow {
|
|
|
1688
1920
|
if (this.config.debug) {
|
|
1689
1921
|
(0, helpers_1.debugLog)('Syncing PR status', { prId });
|
|
1690
1922
|
}
|
|
1691
|
-
const response = await this.
|
|
1923
|
+
const response = await this.portalRequest('POST', `/api/v1/code-governance/prs/${prId}/sync`);
|
|
1692
1924
|
// Transform snake_case response to camelCase
|
|
1693
1925
|
return {
|
|
1694
1926
|
id: response.id,
|
|
@@ -1728,7 +1960,7 @@ class AxonFlow {
|
|
|
1728
1960
|
if (this.config.debug) {
|
|
1729
1961
|
(0, helpers_1.debugLog)('Getting code governance metrics');
|
|
1730
1962
|
}
|
|
1731
|
-
const response = await this.
|
|
1963
|
+
const response = await this.portalRequest('GET', '/api/v1/code-governance/metrics');
|
|
1732
1964
|
return {
|
|
1733
1965
|
tenantId: response.tenant_id,
|
|
1734
1966
|
totalPrs: response.total_prs,
|
|
@@ -1776,9 +2008,9 @@ class AxonFlow {
|
|
|
1776
2008
|
if (this.config.debug) {
|
|
1777
2009
|
(0, helpers_1.debugLog)('Exporting code governance data', { path });
|
|
1778
2010
|
}
|
|
1779
|
-
const response = await this.
|
|
2011
|
+
const response = await this.portalRequest('GET', path);
|
|
1780
2012
|
return {
|
|
1781
|
-
records: response.records.map(r => ({
|
|
2013
|
+
records: (response.records || []).map(r => ({
|
|
1782
2014
|
id: r.id,
|
|
1783
2015
|
prNumber: r.pr_number,
|
|
1784
2016
|
prUrl: r.pr_url,
|
|
@@ -1799,33 +2031,93 @@ class AxonFlow {
|
|
|
1799
2031
|
exportedAt: response.exported_at,
|
|
1800
2032
|
};
|
|
1801
2033
|
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Export code governance data as CSV.
|
|
2036
|
+
*
|
|
2037
|
+
* Returns raw CSV data suitable for saving to file or streaming.
|
|
2038
|
+
*
|
|
2039
|
+
* @param options - Export options (date filters, state filter)
|
|
2040
|
+
* @returns Raw CSV data
|
|
2041
|
+
*
|
|
2042
|
+
* @example
|
|
2043
|
+
* ```typescript
|
|
2044
|
+
* const csvData = await axonflow.exportCodeGovernanceDataCSV();
|
|
2045
|
+
* fs.writeFileSync('pr-audit.csv', csvData);
|
|
2046
|
+
* ```
|
|
2047
|
+
*/
|
|
2048
|
+
async exportCodeGovernanceDataCSV(options) {
|
|
2049
|
+
const params = new URLSearchParams();
|
|
2050
|
+
params.set('format', 'csv');
|
|
2051
|
+
if (options?.startDate)
|
|
2052
|
+
params.set('start_date', options.startDate);
|
|
2053
|
+
if (options?.endDate)
|
|
2054
|
+
params.set('end_date', options.endDate);
|
|
2055
|
+
if (options?.state)
|
|
2056
|
+
params.set('state', options.state);
|
|
2057
|
+
const query = params.toString();
|
|
2058
|
+
const path = `/api/v1/code-governance/export${query ? '?' + query : ''}`;
|
|
2059
|
+
if (this.config.debug) {
|
|
2060
|
+
(0, helpers_1.debugLog)('Exporting code governance data as CSV', { path });
|
|
2061
|
+
}
|
|
2062
|
+
return this.portalRequestText('GET', path);
|
|
2063
|
+
}
|
|
1802
2064
|
// ============================================================================
|
|
1803
2065
|
// Execution Replay Methods
|
|
1804
2066
|
// ============================================================================
|
|
1805
2067
|
/**
|
|
1806
|
-
* Get the
|
|
1807
|
-
*
|
|
2068
|
+
* Get the endpoint URL for API requests.
|
|
2069
|
+
* All routes now go through the single Agent endpoint (ADR-026).
|
|
2070
|
+
*/
|
|
2071
|
+
getEndpointUrl() {
|
|
2072
|
+
return this.config.endpoint;
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Generic HTTP request helper for APIs (routes through single endpoint per ADR-026)
|
|
1808
2076
|
*/
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
2077
|
+
async orchestratorRequest(method, path, body) {
|
|
2078
|
+
const url = `${this.config.endpoint}${path}`;
|
|
2079
|
+
const headers = this.buildAuthHeaders();
|
|
2080
|
+
const options = {
|
|
2081
|
+
method,
|
|
2082
|
+
headers,
|
|
2083
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
2084
|
+
};
|
|
2085
|
+
if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
|
2086
|
+
options.body = JSON.stringify(body);
|
|
1812
2087
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
const
|
|
1816
|
-
|
|
1817
|
-
|
|
2088
|
+
const response = await fetch(url, options);
|
|
2089
|
+
if (!response.ok) {
|
|
2090
|
+
const errorText = await response.text();
|
|
2091
|
+
if (response.status === 401 || response.status === 403) {
|
|
2092
|
+
throw new errors_1.AuthenticationError(`Request failed: ${errorText}`);
|
|
2093
|
+
}
|
|
2094
|
+
if (response.status === 404) {
|
|
2095
|
+
throw new errors_1.APIError(404, 'Not Found', errorText);
|
|
2096
|
+
}
|
|
2097
|
+
throw new errors_1.APIError(response.status, response.statusText, errorText);
|
|
1818
2098
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
2099
|
+
// Handle DELETE responses with no body
|
|
2100
|
+
if (response.status === 204 || method === 'DELETE') {
|
|
2101
|
+
return undefined;
|
|
1821
2102
|
}
|
|
2103
|
+
return response.json();
|
|
1822
2104
|
}
|
|
2105
|
+
// Note: getPortalUrl() was removed in v2.0.0 (ADR-026 Single Entry Point).
|
|
2106
|
+
// All routes now go through the single Agent endpoint (this.config.endpoint).
|
|
1823
2107
|
/**
|
|
1824
|
-
* Generic HTTP request helper for
|
|
2108
|
+
* Generic HTTP request helper for Customer Portal APIs (enterprise features).
|
|
2109
|
+
* Routes through single endpoint per ADR-026.
|
|
2110
|
+
* Requires prior authentication via loginToPortal().
|
|
1825
2111
|
*/
|
|
1826
|
-
async
|
|
1827
|
-
|
|
1828
|
-
|
|
2112
|
+
async portalRequest(method, path, body) {
|
|
2113
|
+
if (!this.sessionCookie) {
|
|
2114
|
+
throw new errors_1.AuthenticationError('Not logged in to Customer Portal. Call loginToPortal() first.');
|
|
2115
|
+
}
|
|
2116
|
+
const url = `${this.config.endpoint}${path}`;
|
|
2117
|
+
const headers = {
|
|
2118
|
+
'Content-Type': 'application/json',
|
|
2119
|
+
Cookie: `axonflow_session=${this.sessionCookie}`,
|
|
2120
|
+
};
|
|
1829
2121
|
const options = {
|
|
1830
2122
|
method,
|
|
1831
2123
|
headers,
|
|
@@ -1834,6 +2126,9 @@ class AxonFlow {
|
|
|
1834
2126
|
if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
|
1835
2127
|
options.body = JSON.stringify(body);
|
|
1836
2128
|
}
|
|
2129
|
+
if (this.config.debug) {
|
|
2130
|
+
(0, helpers_1.debugLog)('Portal request', { method, path });
|
|
2131
|
+
}
|
|
1837
2132
|
const response = await fetch(url, options);
|
|
1838
2133
|
if (!response.ok) {
|
|
1839
2134
|
const errorText = await response.text();
|
|
@@ -2407,6 +2702,37 @@ class AxonFlow {
|
|
|
2407
2702
|
},
|
|
2408
2703
|
};
|
|
2409
2704
|
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Generic HTTP request helper for Customer Portal APIs that returns raw text.
|
|
2707
|
+
* Used for CSV exports and other non-JSON responses.
|
|
2708
|
+
* Requires prior authentication via loginToPortal().
|
|
2709
|
+
*/
|
|
2710
|
+
async portalRequestText(method, path) {
|
|
2711
|
+
if (!this.sessionCookie) {
|
|
2712
|
+
throw new errors_1.AuthenticationError('Not logged in to Customer Portal. Call loginToPortal() first.');
|
|
2713
|
+
}
|
|
2714
|
+
const url = `${this.config.endpoint}${path}`;
|
|
2715
|
+
const headers = {
|
|
2716
|
+
Cookie: `axonflow_session=${this.sessionCookie}`,
|
|
2717
|
+
};
|
|
2718
|
+
const options = {
|
|
2719
|
+
method,
|
|
2720
|
+
headers,
|
|
2721
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
2722
|
+
};
|
|
2723
|
+
if (this.config.debug) {
|
|
2724
|
+
(0, helpers_1.debugLog)('Portal request (text)', { method, path });
|
|
2725
|
+
}
|
|
2726
|
+
const response = await fetch(url, options);
|
|
2727
|
+
if (!response.ok) {
|
|
2728
|
+
const errorText = await response.text();
|
|
2729
|
+
if (response.status === 401 || response.status === 403) {
|
|
2730
|
+
throw new errors_1.AuthenticationError(`Request failed: ${errorText}`);
|
|
2731
|
+
}
|
|
2732
|
+
throw new errors_1.APIError(response.status, response.statusText, errorText);
|
|
2733
|
+
}
|
|
2734
|
+
return response.text();
|
|
2735
|
+
}
|
|
2410
2736
|
}
|
|
2411
2737
|
exports.AxonFlow = AxonFlow;
|
|
2412
2738
|
//# sourceMappingURL=client.js.map
|