@axonflow/sdk 1.2.0 → 1.3.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 +21 -0
- package/README.md +313 -9
- package/dist/cjs/client.d.ts +106 -41
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +446 -198
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/errors.d.ts +51 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +84 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +16 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interceptors/anthropic.d.ts +1 -1
- package/dist/cjs/interceptors/anthropic.d.ts.map +1 -1
- package/dist/cjs/interceptors/anthropic.js +6 -6
- package/dist/cjs/interceptors/anthropic.js.map +1 -1
- package/dist/cjs/interceptors/bedrock.d.ts +141 -0
- package/dist/cjs/interceptors/bedrock.d.ts.map +1 -0
- package/dist/cjs/interceptors/bedrock.js +259 -0
- package/dist/cjs/interceptors/bedrock.js.map +1 -0
- package/dist/cjs/interceptors/gemini.d.ts +81 -0
- package/dist/cjs/interceptors/gemini.d.ts.map +1 -0
- package/dist/cjs/interceptors/gemini.js +110 -0
- package/dist/cjs/interceptors/gemini.js.map +1 -0
- package/dist/cjs/interceptors/ollama.d.ts +143 -0
- package/dist/cjs/interceptors/ollama.d.ts.map +1 -0
- package/dist/cjs/interceptors/ollama.js +150 -0
- package/dist/cjs/interceptors/ollama.js.map +1 -0
- package/dist/cjs/interceptors/openai.d.ts +1 -1
- package/dist/cjs/interceptors/openai.d.ts.map +1 -1
- package/dist/cjs/interceptors/openai.js +5 -5
- package/dist/cjs/interceptors/openai.js.map +1 -1
- package/dist/cjs/types/config.d.ts +7 -1
- package/dist/cjs/types/config.d.ts.map +1 -1
- package/dist/cjs/types/gateway.d.ts +51 -114
- package/dist/cjs/types/gateway.d.ts.map +1 -1
- package/dist/cjs/types/gateway.js +2 -7
- package/dist/cjs/types/gateway.js.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/proxy.d.ts +78 -0
- package/dist/cjs/types/proxy.d.ts.map +1 -0
- package/dist/cjs/types/proxy.js +9 -0
- package/dist/cjs/types/proxy.js.map +1 -0
- package/dist/cjs/utils/helpers.d.ts.map +1 -1
- package/dist/cjs/utils/helpers.js +3 -1
- package/dist/cjs/utils/helpers.js.map +1 -1
- package/dist/esm/client.d.ts +106 -41
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +446 -198
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/errors.d.ts +51 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +75 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +6 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +6 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interceptors/anthropic.d.ts +1 -1
- package/dist/esm/interceptors/anthropic.d.ts.map +1 -1
- package/dist/esm/interceptors/anthropic.js +6 -6
- package/dist/esm/interceptors/anthropic.js.map +1 -1
- package/dist/esm/interceptors/bedrock.d.ts +141 -0
- package/dist/esm/interceptors/bedrock.d.ts.map +1 -0
- package/dist/esm/interceptors/bedrock.js +220 -0
- package/dist/esm/interceptors/bedrock.js.map +1 -0
- package/dist/esm/interceptors/gemini.d.ts +81 -0
- package/dist/esm/interceptors/gemini.d.ts.map +1 -0
- package/dist/esm/interceptors/gemini.js +105 -0
- package/dist/esm/interceptors/gemini.js.map +1 -0
- package/dist/esm/interceptors/ollama.d.ts +143 -0
- package/dist/esm/interceptors/ollama.d.ts.map +1 -0
- package/dist/esm/interceptors/ollama.js +144 -0
- package/dist/esm/interceptors/ollama.js.map +1 -0
- package/dist/esm/interceptors/openai.d.ts +1 -1
- package/dist/esm/interceptors/openai.d.ts.map +1 -1
- package/dist/esm/interceptors/openai.js +5 -5
- package/dist/esm/interceptors/openai.js.map +1 -1
- package/dist/esm/types/config.d.ts +7 -1
- package/dist/esm/types/config.d.ts.map +1 -1
- package/dist/esm/types/gateway.d.ts +51 -114
- package/dist/esm/types/gateway.d.ts.map +1 -1
- package/dist/esm/types/gateway.js +2 -7
- package/dist/esm/types/gateway.js.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/proxy.d.ts +78 -0
- package/dist/esm/types/proxy.d.ts.map +1 -0
- package/dist/esm/types/proxy.js +8 -0
- package/dist/esm/types/proxy.js.map +1 -0
- package/dist/esm/utils/helpers.d.ts.map +1 -1
- package/dist/esm/utils/helpers.js +3 -1
- package/dist/esm/utils/helpers.js.map +1 -1
- package/package.json +22 -7
package/dist/esm/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthenticationError, APIError, PolicyViolationError } from './errors.js';
|
|
1
2
|
import { OpenAIInterceptor } from './interceptors/openai.js';
|
|
2
3
|
import { AnthropicInterceptor } from './interceptors/anthropic.js';
|
|
3
4
|
import { generateRequestId, debugLog } from './utils/helpers.js';
|
|
@@ -7,24 +8,49 @@ import { generateRequestId, debugLog } from './utils/helpers.js';
|
|
|
7
8
|
export class AxonFlow {
|
|
8
9
|
constructor(config) {
|
|
9
10
|
this.interceptors = [];
|
|
10
|
-
// Set defaults
|
|
11
|
+
// Set defaults first to determine endpoint
|
|
12
|
+
const endpoint = config.endpoint || 'https://staging-eu.getaxonflow.com';
|
|
13
|
+
// Check if running in self-hosted mode (localhost)
|
|
14
|
+
const isLocalhost = endpoint.includes('localhost') || endpoint.includes('127.0.0.1');
|
|
15
|
+
// License key is optional for self-hosted deployments
|
|
16
|
+
// When not provided, agent must have SELF_HOSTED_MODE=true
|
|
17
|
+
if (!isLocalhost && !config.licenseKey && !config.apiKey) {
|
|
18
|
+
throw new Error('Either licenseKey or apiKey must be provided for non-localhost endpoints');
|
|
19
|
+
}
|
|
20
|
+
if (isLocalhost && !config.licenseKey && !config.apiKey && config.debug) {
|
|
21
|
+
console.warn('[AxonFlow] No license key provided - ensure agent has SELF_HOSTED_MODE=true');
|
|
22
|
+
}
|
|
23
|
+
// Set configuration
|
|
11
24
|
this.config = {
|
|
12
25
|
apiKey: config.apiKey,
|
|
13
|
-
|
|
14
|
-
|
|
26
|
+
licenseKey: config.licenseKey,
|
|
27
|
+
endpoint,
|
|
28
|
+
mode: config.mode || (isLocalhost ? 'sandbox' : 'production'),
|
|
15
29
|
tenant: config.tenant || 'default',
|
|
16
30
|
debug: config.debug || false,
|
|
17
31
|
timeout: config.timeout || 30000,
|
|
18
|
-
retry:
|
|
19
|
-
|
|
32
|
+
retry: {
|
|
33
|
+
enabled: config.retry?.enabled !== false,
|
|
34
|
+
maxAttempts: config.retry?.maxAttempts || 3,
|
|
35
|
+
delay: config.retry?.delay || 1000,
|
|
36
|
+
},
|
|
37
|
+
cache: {
|
|
38
|
+
enabled: config.cache?.enabled !== false,
|
|
39
|
+
ttl: config.cache?.ttl || 60000,
|
|
40
|
+
},
|
|
20
41
|
};
|
|
21
42
|
// Initialize interceptors
|
|
22
|
-
this.interceptors = [
|
|
23
|
-
new OpenAIInterceptor(),
|
|
24
|
-
new AnthropicInterceptor()
|
|
25
|
-
];
|
|
43
|
+
this.interceptors = [new OpenAIInterceptor(), new AnthropicInterceptor()];
|
|
26
44
|
if (this.config.debug) {
|
|
27
|
-
debugLog('AxonFlow initialized', {
|
|
45
|
+
debugLog('AxonFlow initialized', {
|
|
46
|
+
mode: this.config.mode,
|
|
47
|
+
endpoint: this.config.endpoint,
|
|
48
|
+
authMethod: isLocalhost
|
|
49
|
+
? 'self-hosted (no auth)'
|
|
50
|
+
: this.config.licenseKey
|
|
51
|
+
? 'license-key'
|
|
52
|
+
: 'api-key',
|
|
53
|
+
});
|
|
28
54
|
}
|
|
29
55
|
}
|
|
30
56
|
/**
|
|
@@ -45,7 +71,7 @@ export class AxonFlow {
|
|
|
45
71
|
timestamp: Date.now(),
|
|
46
72
|
aiRequest,
|
|
47
73
|
mode: this.config.mode,
|
|
48
|
-
tenant: this.config.tenant
|
|
74
|
+
tenant: this.config.tenant,
|
|
49
75
|
};
|
|
50
76
|
// Check policies with AxonFlow Agent
|
|
51
77
|
const governanceResponse = await this.checkPolicies(governanceRequest);
|
|
@@ -90,7 +116,7 @@ export class AxonFlow {
|
|
|
90
116
|
provider: 'unknown',
|
|
91
117
|
model: 'unknown',
|
|
92
118
|
prompt: aiCall.toString(),
|
|
93
|
-
parameters: {}
|
|
119
|
+
parameters: {},
|
|
94
120
|
};
|
|
95
121
|
}
|
|
96
122
|
/**
|
|
@@ -101,7 +127,7 @@ export class AxonFlow {
|
|
|
101
127
|
// Transform SDK request to Agent API format
|
|
102
128
|
const agentRequest = {
|
|
103
129
|
query: request.aiRequest.prompt,
|
|
104
|
-
user_token: this.config.apiKey,
|
|
130
|
+
user_token: this.config.apiKey || '',
|
|
105
131
|
client_id: this.config.tenant,
|
|
106
132
|
request_type: 'llm_chat',
|
|
107
133
|
context: {
|
|
@@ -109,16 +135,23 @@ export class AxonFlow {
|
|
|
109
135
|
model: request.aiRequest.model,
|
|
110
136
|
parameters: request.aiRequest.parameters,
|
|
111
137
|
requestId: request.requestId,
|
|
112
|
-
mode: this.config.mode
|
|
113
|
-
}
|
|
138
|
+
mode: this.config.mode,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const headers = {
|
|
142
|
+
'Content-Type': 'application/json',
|
|
114
143
|
};
|
|
144
|
+
// Add license key header if available (preferred auth method)
|
|
145
|
+
// Skip auth headers for localhost (self-hosted mode)
|
|
146
|
+
const isLocalhost = this.config.endpoint.includes('localhost') || this.config.endpoint.includes('127.0.0.1');
|
|
147
|
+
if (!isLocalhost && this.config.licenseKey) {
|
|
148
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
149
|
+
}
|
|
115
150
|
const response = await fetch(url, {
|
|
116
151
|
method: 'POST',
|
|
117
|
-
headers
|
|
118
|
-
'Content-Type': 'application/json'
|
|
119
|
-
},
|
|
152
|
+
headers,
|
|
120
153
|
body: JSON.stringify(agentRequest),
|
|
121
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
154
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
122
155
|
});
|
|
123
156
|
if (!response.ok) {
|
|
124
157
|
const errorText = await response.text();
|
|
@@ -126,23 +159,29 @@ export class AxonFlow {
|
|
|
126
159
|
}
|
|
127
160
|
const agentResponse = await response.json();
|
|
128
161
|
// Transform Agent API response to SDK format
|
|
162
|
+
// Extract policy name from policy_info if available
|
|
163
|
+
const policyName = agentResponse.policy_info?.policies_evaluated?.[0] || 'agent-policy';
|
|
129
164
|
return {
|
|
130
165
|
requestId: request.requestId,
|
|
131
166
|
allowed: !agentResponse.blocked,
|
|
132
|
-
violations: agentResponse.blocked
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
167
|
+
violations: agentResponse.blocked
|
|
168
|
+
? [
|
|
169
|
+
{
|
|
170
|
+
type: 'security',
|
|
171
|
+
severity: 'high',
|
|
172
|
+
description: agentResponse.block_reason || 'Request blocked by policy',
|
|
173
|
+
policy: policyName,
|
|
174
|
+
action: 'blocked',
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
: [],
|
|
139
178
|
modifiedRequest: agentResponse.data,
|
|
140
|
-
policies: [],
|
|
179
|
+
policies: agentResponse.policy_info?.policies_evaluated || [],
|
|
141
180
|
audit: {
|
|
142
181
|
timestamp: Date.now(),
|
|
143
182
|
duration: parseInt(agentResponse.policy_info?.processing_time?.replace('ms', '') || '0'),
|
|
144
|
-
tenant: this.config.tenant
|
|
145
|
-
}
|
|
183
|
+
tenant: this.config.tenant,
|
|
184
|
+
},
|
|
146
185
|
};
|
|
147
186
|
}
|
|
148
187
|
/**
|
|
@@ -155,7 +194,7 @@ export class AxonFlow {
|
|
|
155
194
|
debugLog('Request processed', {
|
|
156
195
|
allowed: response.allowed,
|
|
157
196
|
violations: response.violations?.length || 0,
|
|
158
|
-
duration: response.audit.duration
|
|
197
|
+
duration: response.audit.duration,
|
|
159
198
|
});
|
|
160
199
|
}
|
|
161
200
|
}
|
|
@@ -163,9 +202,9 @@ export class AxonFlow {
|
|
|
163
202
|
* Check if an error is from AxonFlow (vs the AI provider)
|
|
164
203
|
*/
|
|
165
204
|
isAxonFlowError(error) {
|
|
166
|
-
return error?.message?.includes('AxonFlow') ||
|
|
205
|
+
return (error?.message?.includes('AxonFlow') ||
|
|
167
206
|
error?.message?.includes('governance') ||
|
|
168
|
-
error?.message?.includes('fetch');
|
|
207
|
+
error?.message?.includes('fetch'));
|
|
169
208
|
}
|
|
170
209
|
/**
|
|
171
210
|
* Create a sandbox client for testing
|
|
@@ -175,9 +214,176 @@ export class AxonFlow {
|
|
|
175
214
|
apiKey,
|
|
176
215
|
mode: 'sandbox',
|
|
177
216
|
endpoint: 'https://staging-eu.getaxonflow.com',
|
|
178
|
-
debug: true
|
|
217
|
+
debug: true,
|
|
179
218
|
});
|
|
180
219
|
}
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// Proxy Mode Methods
|
|
222
|
+
// ============================================================================
|
|
223
|
+
/**
|
|
224
|
+
* Check if AxonFlow Agent is healthy and available.
|
|
225
|
+
*
|
|
226
|
+
* @returns HealthStatus object with agent health information
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const health = await axonflow.healthCheck();
|
|
231
|
+
* if (health.status === 'healthy') {
|
|
232
|
+
* console.log('Agent is healthy');
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
async healthCheck() {
|
|
237
|
+
const url = `${this.config.endpoint}/health`;
|
|
238
|
+
try {
|
|
239
|
+
const response = await fetch(url, {
|
|
240
|
+
method: 'GET',
|
|
241
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
242
|
+
});
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
return {
|
|
245
|
+
status: 'unhealthy',
|
|
246
|
+
components: {
|
|
247
|
+
agent: { status: 'error', message: `HTTP ${response.status}` },
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const data = await response.json();
|
|
252
|
+
return {
|
|
253
|
+
status: data.status === 'healthy' ? 'healthy' : 'degraded',
|
|
254
|
+
version: data.version,
|
|
255
|
+
uptime: data.uptime,
|
|
256
|
+
components: data.components,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
if (this.config.debug) {
|
|
261
|
+
debugLog('Health check failed', error);
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
status: 'unhealthy',
|
|
265
|
+
components: {
|
|
266
|
+
agent: {
|
|
267
|
+
status: 'error',
|
|
268
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Execute a query through AxonFlow with policy enforcement (Proxy Mode).
|
|
276
|
+
*
|
|
277
|
+
* This is the primary method for Proxy Mode, where AxonFlow handles policy
|
|
278
|
+
* checking and optionally routes requests to LLM providers.
|
|
279
|
+
*
|
|
280
|
+
* @param options - Query execution options
|
|
281
|
+
* @returns ExecuteQueryResponse with results or error information
|
|
282
|
+
* @throws PolicyViolationError if request is blocked by policy
|
|
283
|
+
* @throws AuthenticationError if credentials are invalid
|
|
284
|
+
* @throws APIError for other API errors
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* const response = await axonflow.executeQuery({
|
|
289
|
+
* userToken: 'user-123',
|
|
290
|
+
* query: 'Explain quantum computing',
|
|
291
|
+
* requestType: 'chat',
|
|
292
|
+
* context: { provider: 'openai', model: 'gpt-4' }
|
|
293
|
+
* });
|
|
294
|
+
*
|
|
295
|
+
* if (response.success) {
|
|
296
|
+
* console.log('Response:', response.data);
|
|
297
|
+
* }
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
async executeQuery(options) {
|
|
301
|
+
const agentRequest = {
|
|
302
|
+
query: options.query,
|
|
303
|
+
user_token: options.userToken,
|
|
304
|
+
client_id: this.config.tenant,
|
|
305
|
+
request_type: options.requestType,
|
|
306
|
+
context: options.context || {},
|
|
307
|
+
};
|
|
308
|
+
const url = `${this.config.endpoint}/api/request`;
|
|
309
|
+
const headers = {
|
|
310
|
+
'Content-Type': 'application/json',
|
|
311
|
+
};
|
|
312
|
+
// Add authentication headers
|
|
313
|
+
const isLocalhost = this.config.endpoint.includes('localhost') || this.config.endpoint.includes('127.0.0.1');
|
|
314
|
+
if (!isLocalhost) {
|
|
315
|
+
if (this.config.licenseKey) {
|
|
316
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
317
|
+
}
|
|
318
|
+
else if (this.config.apiKey) {
|
|
319
|
+
headers['X-Client-Secret'] = this.config.apiKey;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (this.config.debug) {
|
|
323
|
+
debugLog('Proxy Mode: executeQuery', {
|
|
324
|
+
requestType: options.requestType,
|
|
325
|
+
query: options.query.substring(0, 50),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const response = await fetch(url, {
|
|
329
|
+
method: 'POST',
|
|
330
|
+
headers,
|
|
331
|
+
body: JSON.stringify(agentRequest),
|
|
332
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
333
|
+
});
|
|
334
|
+
if (!response.ok) {
|
|
335
|
+
const errorText = await response.text();
|
|
336
|
+
if (response.status === 401 || response.status === 403) {
|
|
337
|
+
// Try to parse as JSON for policy violation info
|
|
338
|
+
try {
|
|
339
|
+
const errorJson = JSON.parse(errorText);
|
|
340
|
+
if (errorJson.blocked || errorJson.block_reason) {
|
|
341
|
+
throw new PolicyViolationError(errorJson.block_reason || 'Request blocked by policy', errorJson.policy_info?.policies_evaluated);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
if (e instanceof PolicyViolationError)
|
|
346
|
+
throw e;
|
|
347
|
+
}
|
|
348
|
+
throw new AuthenticationError(`Request failed: ${errorText}`);
|
|
349
|
+
}
|
|
350
|
+
throw new APIError(response.status, response.statusText, errorText);
|
|
351
|
+
}
|
|
352
|
+
const data = await response.json();
|
|
353
|
+
// Check for policy violation in successful response (some blocked responses return 200)
|
|
354
|
+
if (data.blocked) {
|
|
355
|
+
throw new PolicyViolationError(data.block_reason || 'Request blocked by policy', data.policy_info?.policies_evaluated);
|
|
356
|
+
}
|
|
357
|
+
// Transform snake_case response to camelCase
|
|
358
|
+
const result = {
|
|
359
|
+
success: data.success,
|
|
360
|
+
data: data.data,
|
|
361
|
+
result: data.result,
|
|
362
|
+
planId: data.plan_id,
|
|
363
|
+
requestId: data.request_id,
|
|
364
|
+
metadata: data.metadata || {},
|
|
365
|
+
error: data.error,
|
|
366
|
+
blocked: data.blocked || false,
|
|
367
|
+
blockReason: data.block_reason,
|
|
368
|
+
};
|
|
369
|
+
// Parse policy info if present
|
|
370
|
+
if (data.policy_info) {
|
|
371
|
+
result.policyInfo = {
|
|
372
|
+
policiesEvaluated: data.policy_info.policies_evaluated || [],
|
|
373
|
+
staticChecks: data.policy_info.static_checks || [],
|
|
374
|
+
processingTime: data.policy_info.processing_time || '',
|
|
375
|
+
tenantId: data.policy_info.tenant_id || '',
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
if (this.config.debug) {
|
|
379
|
+
debugLog('Proxy Mode: executeQuery result', {
|
|
380
|
+
success: result.success,
|
|
381
|
+
blocked: result.blocked,
|
|
382
|
+
hasData: !!result.data,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
181
387
|
/**
|
|
182
388
|
* List all available MCP connectors from the marketplace
|
|
183
389
|
*/
|
|
@@ -185,7 +391,7 @@ export class AxonFlow {
|
|
|
185
391
|
const url = `${this.config.endpoint}/api/connectors`;
|
|
186
392
|
const response = await fetch(url, {
|
|
187
393
|
method: 'GET',
|
|
188
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
394
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
189
395
|
});
|
|
190
396
|
if (!response.ok) {
|
|
191
397
|
throw new Error(`Failed to list connectors: ${response.status} ${response.statusText}`);
|
|
@@ -201,14 +407,21 @@ export class AxonFlow {
|
|
|
201
407
|
*/
|
|
202
408
|
async installConnector(request) {
|
|
203
409
|
const url = `${this.config.endpoint}/api/connectors/install`;
|
|
410
|
+
const headers = {
|
|
411
|
+
'Content-Type': 'application/json',
|
|
412
|
+
};
|
|
413
|
+
// Add authentication headers
|
|
414
|
+
if (this.config.licenseKey) {
|
|
415
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
416
|
+
}
|
|
417
|
+
else if (this.config.apiKey) {
|
|
418
|
+
headers['X-Client-Secret'] = this.config.apiKey;
|
|
419
|
+
}
|
|
204
420
|
const response = await fetch(url, {
|
|
205
421
|
method: 'POST',
|
|
206
|
-
headers
|
|
207
|
-
'Content-Type': 'application/json',
|
|
208
|
-
'X-Client-Secret': this.config.apiKey
|
|
209
|
-
},
|
|
422
|
+
headers,
|
|
210
423
|
body: JSON.stringify(request),
|
|
211
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
424
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
212
425
|
});
|
|
213
426
|
if (!response.ok) {
|
|
214
427
|
const errorText = await response.text();
|
|
@@ -224,22 +437,26 @@ export class AxonFlow {
|
|
|
224
437
|
async queryConnector(connectorName, query, params) {
|
|
225
438
|
const agentRequest = {
|
|
226
439
|
query,
|
|
227
|
-
user_token: this.config.apiKey,
|
|
440
|
+
user_token: this.config.apiKey || '',
|
|
228
441
|
client_id: this.config.tenant,
|
|
229
442
|
request_type: 'mcp-query',
|
|
230
443
|
context: {
|
|
231
444
|
connector: connectorName,
|
|
232
|
-
params: params || {}
|
|
233
|
-
}
|
|
445
|
+
params: params || {},
|
|
446
|
+
},
|
|
234
447
|
};
|
|
235
448
|
const url = `${this.config.endpoint}/api/request`;
|
|
449
|
+
const headers = {
|
|
450
|
+
'Content-Type': 'application/json',
|
|
451
|
+
};
|
|
452
|
+
if (this.config.licenseKey) {
|
|
453
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
454
|
+
}
|
|
236
455
|
const response = await fetch(url, {
|
|
237
456
|
method: 'POST',
|
|
238
|
-
headers
|
|
239
|
-
'Content-Type': 'application/json'
|
|
240
|
-
},
|
|
457
|
+
headers,
|
|
241
458
|
body: JSON.stringify(agentRequest),
|
|
242
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
459
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
243
460
|
});
|
|
244
461
|
if (!response.ok) {
|
|
245
462
|
const errorText = await response.text();
|
|
@@ -253,28 +470,35 @@ export class AxonFlow {
|
|
|
253
470
|
success: agentResponse.success,
|
|
254
471
|
data: agentResponse.data,
|
|
255
472
|
error: agentResponse.error,
|
|
256
|
-
meta: agentResponse.metadata
|
|
473
|
+
meta: agentResponse.metadata,
|
|
257
474
|
};
|
|
258
475
|
}
|
|
259
476
|
/**
|
|
260
477
|
* Generate a multi-agent execution plan from a natural language query
|
|
478
|
+
* @param query - Natural language query describing the task
|
|
479
|
+
* @param domain - Optional domain hint (travel, healthcare, etc.)
|
|
480
|
+
* @param userToken - Optional user token for authentication (defaults to tenant/client_id)
|
|
261
481
|
*/
|
|
262
|
-
async generatePlan(query, domain) {
|
|
482
|
+
async generatePlan(query, domain, userToken) {
|
|
263
483
|
const agentRequest = {
|
|
264
484
|
query,
|
|
265
|
-
user_token: this.config.
|
|
485
|
+
user_token: userToken || this.config.tenant,
|
|
266
486
|
client_id: this.config.tenant,
|
|
267
487
|
request_type: 'multi-agent-plan',
|
|
268
|
-
context: domain ? { domain } : {}
|
|
488
|
+
context: domain ? { domain } : {},
|
|
269
489
|
};
|
|
270
490
|
const url = `${this.config.endpoint}/api/request`;
|
|
491
|
+
const headers = {
|
|
492
|
+
'Content-Type': 'application/json',
|
|
493
|
+
};
|
|
494
|
+
if (this.config.licenseKey) {
|
|
495
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
496
|
+
}
|
|
271
497
|
const response = await fetch(url, {
|
|
272
498
|
method: 'POST',
|
|
273
|
-
headers
|
|
274
|
-
'Content-Type': 'application/json'
|
|
275
|
-
},
|
|
499
|
+
headers,
|
|
276
500
|
body: JSON.stringify(agentRequest),
|
|
277
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
501
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
278
502
|
});
|
|
279
503
|
if (!response.ok) {
|
|
280
504
|
const errorText = await response.text();
|
|
@@ -293,28 +517,34 @@ export class AxonFlow {
|
|
|
293
517
|
domain: agentResponse.data?.domain || domain || 'generic',
|
|
294
518
|
complexity: agentResponse.data?.complexity || 0,
|
|
295
519
|
parallel: agentResponse.data?.parallel || false,
|
|
296
|
-
metadata: agentResponse.metadata || {}
|
|
520
|
+
metadata: agentResponse.metadata || {},
|
|
297
521
|
};
|
|
298
522
|
}
|
|
299
523
|
/**
|
|
300
524
|
* Execute a previously generated multi-agent plan
|
|
525
|
+
* @param planId - ID of the plan to execute
|
|
526
|
+
* @param userToken - Optional user token for authentication (defaults to tenant/client_id)
|
|
301
527
|
*/
|
|
302
|
-
async executePlan(planId) {
|
|
528
|
+
async executePlan(planId, userToken) {
|
|
303
529
|
const agentRequest = {
|
|
304
530
|
query: '',
|
|
305
|
-
user_token: this.config.
|
|
531
|
+
user_token: userToken || this.config.tenant,
|
|
306
532
|
client_id: this.config.tenant,
|
|
307
533
|
request_type: 'execute-plan',
|
|
308
|
-
context: { plan_id: planId }
|
|
534
|
+
context: { plan_id: planId },
|
|
309
535
|
};
|
|
310
536
|
const url = `${this.config.endpoint}/api/request`;
|
|
537
|
+
const headers = {
|
|
538
|
+
'Content-Type': 'application/json',
|
|
539
|
+
};
|
|
540
|
+
if (this.config.licenseKey) {
|
|
541
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
542
|
+
}
|
|
311
543
|
const response = await fetch(url, {
|
|
312
544
|
method: 'POST',
|
|
313
|
-
headers
|
|
314
|
-
'Content-Type': 'application/json'
|
|
315
|
-
},
|
|
545
|
+
headers,
|
|
316
546
|
body: JSON.stringify(agentRequest),
|
|
317
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
547
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
318
548
|
});
|
|
319
549
|
if (!response.ok) {
|
|
320
550
|
const errorText = await response.text();
|
|
@@ -330,7 +560,7 @@ export class AxonFlow {
|
|
|
330
560
|
result: agentResponse.result,
|
|
331
561
|
stepResults: agentResponse.metadata?.step_results,
|
|
332
562
|
error: agentResponse.error,
|
|
333
|
-
duration: agentResponse.metadata?.duration
|
|
563
|
+
duration: agentResponse.metadata?.duration,
|
|
334
564
|
};
|
|
335
565
|
}
|
|
336
566
|
/**
|
|
@@ -340,7 +570,7 @@ export class AxonFlow {
|
|
|
340
570
|
const url = `${this.config.endpoint}/api/plans/${planId}`;
|
|
341
571
|
const response = await fetch(url, {
|
|
342
572
|
method: 'GET',
|
|
343
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
573
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
344
574
|
});
|
|
345
575
|
if (!response.ok) {
|
|
346
576
|
const errorText = await response.text();
|
|
@@ -353,191 +583,209 @@ export class AxonFlow {
|
|
|
353
583
|
result: status.result,
|
|
354
584
|
stepResults: status.step_results,
|
|
355
585
|
error: status.error,
|
|
356
|
-
duration: status.duration
|
|
586
|
+
duration: status.duration,
|
|
357
587
|
};
|
|
358
588
|
}
|
|
359
|
-
//
|
|
360
|
-
// Gateway Mode
|
|
361
|
-
//
|
|
362
|
-
// Gateway Mode allows clients to make LLM calls directly while still using
|
|
363
|
-
// AxonFlow for policy enforcement and audit logging.
|
|
364
|
-
//
|
|
365
|
-
// Usage:
|
|
366
|
-
// 1. Call getPolicyApprovedContext() before making LLM call
|
|
367
|
-
// 2. Make LLM call directly to your provider (using returned approved data)
|
|
368
|
-
// 3. Call auditLLMCall() after to record the call for compliance
|
|
369
|
-
//
|
|
370
|
-
// Example:
|
|
371
|
-
// const ctx = await axonflow.getPolicyApprovedContext({
|
|
372
|
-
// userToken: 'user-jwt',
|
|
373
|
-
// dataSources: ['postgres'],
|
|
374
|
-
// query: 'Find patients with diabetes'
|
|
375
|
-
// });
|
|
376
|
-
// if (!ctx.approved) throw new Error(ctx.blockReason);
|
|
377
|
-
//
|
|
378
|
-
// const llmResp = await openai.chat.completions.create({...}); // Your LLM call
|
|
379
|
-
//
|
|
380
|
-
// await axonflow.auditLLMCall({
|
|
381
|
-
// contextId: ctx.contextId,
|
|
382
|
-
// responseSummary: 'Found 5 patients',
|
|
383
|
-
// provider: 'openai',
|
|
384
|
-
// model: 'gpt-4',
|
|
385
|
-
// tokenUsage: { promptTokens: 100, completionTokens: 50, totalTokens: 150 },
|
|
386
|
-
// latencyMs: 250
|
|
387
|
-
// });
|
|
589
|
+
// ============================================================================
|
|
590
|
+
// Gateway Mode Methods
|
|
591
|
+
// ============================================================================
|
|
388
592
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
|
|
392
|
-
|
|
593
|
+
* Gateway Mode: Pre-check policy approval before making a direct LLM call.
|
|
594
|
+
* Alias for getPolicyApprovedContext() for simpler API.
|
|
595
|
+
*/
|
|
596
|
+
async preCheck(options) {
|
|
597
|
+
return this.getPolicyApprovedContext(options);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Gateway Mode: Get policy-approved context before making a direct LLM call.
|
|
393
601
|
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
602
|
+
* Use this when you want to:
|
|
603
|
+
* - Make direct LLM calls (not through AxonFlow proxy)
|
|
604
|
+
* - Have full control over your LLM provider/model selection
|
|
605
|
+
* - Minimize latency by calling LLM directly
|
|
396
606
|
*
|
|
397
607
|
* @example
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* query: '
|
|
608
|
+
* ```typescript
|
|
609
|
+
* const ctx = await axonflow.getPolicyApprovedContext({
|
|
610
|
+
* userToken: 'user-jwt',
|
|
611
|
+
* query: 'Analyze this customer data',
|
|
612
|
+
* dataSources: ['postgres']
|
|
402
613
|
* });
|
|
403
614
|
*
|
|
404
|
-
* if (!
|
|
405
|
-
* throw new Error(`
|
|
615
|
+
* if (!ctx.approved) {
|
|
616
|
+
* throw new Error(`Blocked: ${ctx.blockReason}`);
|
|
406
617
|
* }
|
|
407
618
|
*
|
|
408
|
-
* //
|
|
409
|
-
* const
|
|
619
|
+
* // Make direct LLM call with approved data
|
|
620
|
+
* const response = await openai.chat.completions.create({
|
|
621
|
+
* model: 'gpt-4',
|
|
622
|
+
* messages: [{ role: 'user', content: JSON.stringify(ctx.approvedData) }]
|
|
623
|
+
* });
|
|
624
|
+
*
|
|
625
|
+
* // Audit the call
|
|
626
|
+
* await axonflow.auditLLMCall({
|
|
627
|
+
* contextId: ctx.contextId,
|
|
628
|
+
* responseSummary: response.choices[0].message.content.substring(0, 100),
|
|
629
|
+
* provider: 'openai',
|
|
630
|
+
* model: 'gpt-4',
|
|
631
|
+
* tokenUsage: {
|
|
632
|
+
* promptTokens: response.usage.prompt_tokens,
|
|
633
|
+
* completionTokens: response.usage.completion_tokens,
|
|
634
|
+
* totalTokens: response.usage.total_tokens
|
|
635
|
+
* },
|
|
636
|
+
* latencyMs: 250
|
|
637
|
+
* });
|
|
638
|
+
* ```
|
|
410
639
|
*/
|
|
411
|
-
async getPolicyApprovedContext(
|
|
640
|
+
async getPolicyApprovedContext(options) {
|
|
412
641
|
const url = `${this.config.endpoint}/api/policy/pre-check`;
|
|
413
|
-
const
|
|
414
|
-
user_token:
|
|
642
|
+
const requestBody = {
|
|
643
|
+
user_token: options.userToken,
|
|
415
644
|
client_id: this.config.tenant,
|
|
416
|
-
query:
|
|
417
|
-
data_sources:
|
|
418
|
-
context:
|
|
645
|
+
query: options.query,
|
|
646
|
+
data_sources: options.dataSources || [],
|
|
647
|
+
context: options.context || {},
|
|
648
|
+
};
|
|
649
|
+
const headers = {
|
|
650
|
+
'Content-Type': 'application/json',
|
|
419
651
|
};
|
|
652
|
+
// Add authentication headers
|
|
653
|
+
const isLocalhost = this.config.endpoint.includes('localhost') || this.config.endpoint.includes('127.0.0.1');
|
|
654
|
+
if (!isLocalhost) {
|
|
655
|
+
if (this.config.licenseKey) {
|
|
656
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
657
|
+
}
|
|
658
|
+
else if (this.config.apiKey) {
|
|
659
|
+
headers['X-Client-Secret'] = this.config.apiKey;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
420
662
|
if (this.config.debug) {
|
|
421
|
-
debugLog('Gateway
|
|
422
|
-
query: request.query.substring(0, 50),
|
|
423
|
-
dataSources: request.dataSources
|
|
424
|
-
});
|
|
663
|
+
debugLog('Gateway Mode: Pre-check', { query: options.query.substring(0, 50) });
|
|
425
664
|
}
|
|
426
|
-
const startTime = Date.now();
|
|
427
665
|
const response = await fetch(url, {
|
|
428
666
|
method: 'POST',
|
|
429
|
-
headers
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
'X-License-Key': this.config.apiKey
|
|
433
|
-
},
|
|
434
|
-
body: JSON.stringify(body),
|
|
435
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
667
|
+
headers,
|
|
668
|
+
body: JSON.stringify(requestBody),
|
|
669
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
436
670
|
});
|
|
437
|
-
const duration = Date.now() - startTime;
|
|
438
671
|
if (!response.ok) {
|
|
439
672
|
const errorText = await response.text();
|
|
440
|
-
|
|
673
|
+
if (response.status === 401 || response.status === 403) {
|
|
674
|
+
throw new AuthenticationError(`Policy pre-check authentication failed: ${errorText}`);
|
|
675
|
+
}
|
|
676
|
+
throw new APIError(response.status, response.statusText, errorText);
|
|
441
677
|
}
|
|
442
678
|
const data = await response.json();
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
return {
|
|
679
|
+
// Transform snake_case response to camelCase
|
|
680
|
+
// Default expiration to 5 minutes from now if not provided
|
|
681
|
+
const expiresAt = data.expires_at
|
|
682
|
+
? new Date(data.expires_at)
|
|
683
|
+
: new Date(Date.now() + 5 * 60 * 1000);
|
|
684
|
+
const result = {
|
|
451
685
|
contextId: data.context_id,
|
|
452
686
|
approved: data.approved,
|
|
453
|
-
approvedData: data.approved_data,
|
|
687
|
+
approvedData: data.approved_data || {},
|
|
454
688
|
policies: data.policies || [],
|
|
455
|
-
|
|
689
|
+
expiresAt,
|
|
690
|
+
blockReason: data.block_reason,
|
|
691
|
+
};
|
|
692
|
+
// Parse rate limit info if present
|
|
693
|
+
if (data.rate_limit) {
|
|
694
|
+
result.rateLimitInfo = {
|
|
456
695
|
limit: data.rate_limit.limit,
|
|
457
696
|
remaining: data.rate_limit.remaining,
|
|
458
|
-
resetAt: new Date(data.rate_limit.reset_at)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
697
|
+
resetAt: new Date(data.rate_limit.reset_at),
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
if (this.config.debug) {
|
|
701
|
+
debugLog('Gateway Mode: Pre-check result', {
|
|
702
|
+
approved: result.approved,
|
|
703
|
+
contextId: result.contextId,
|
|
704
|
+
policies: result.policies.length,
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
return result;
|
|
463
708
|
}
|
|
464
709
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* This is the second step in Gateway Mode. Call this after making your
|
|
468
|
-
* LLM call to record it in the audit trail.
|
|
710
|
+
* Gateway Mode: Audit an LLM call after completion.
|
|
469
711
|
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
* @param provider LLM provider name
|
|
473
|
-
* @param model Model name
|
|
474
|
-
* @param tokenUsage Token counts from LLM response
|
|
475
|
-
* @param latencyMs Time taken for LLM call in milliseconds
|
|
476
|
-
* @param metadata Optional additional metadata
|
|
477
|
-
* @returns AuditResult confirming the audit was recorded
|
|
712
|
+
* Call this after making a direct LLM call to log the audit trail.
|
|
713
|
+
* This is required for compliance and monitoring.
|
|
478
714
|
*
|
|
479
715
|
* @example
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
* '
|
|
484
|
-
* '
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
716
|
+
* ```typescript
|
|
717
|
+
* await axonflow.auditLLMCall({
|
|
718
|
+
* contextId: ctx.contextId,
|
|
719
|
+
* responseSummary: 'Generated report with 5 items',
|
|
720
|
+
* provider: 'openai',
|
|
721
|
+
* model: 'gpt-4',
|
|
722
|
+
* tokenUsage: {
|
|
723
|
+
* promptTokens: 100,
|
|
724
|
+
* completionTokens: 50,
|
|
725
|
+
* totalTokens: 150
|
|
726
|
+
* },
|
|
727
|
+
* latencyMs: 250
|
|
728
|
+
* });
|
|
729
|
+
* ```
|
|
489
730
|
*/
|
|
490
|
-
async auditLLMCall(
|
|
731
|
+
async auditLLMCall(options) {
|
|
491
732
|
const url = `${this.config.endpoint}/api/audit/llm-call`;
|
|
492
|
-
const
|
|
493
|
-
context_id: contextId,
|
|
733
|
+
const requestBody = {
|
|
734
|
+
context_id: options.contextId,
|
|
494
735
|
client_id: this.config.tenant,
|
|
495
|
-
response_summary: responseSummary,
|
|
496
|
-
provider,
|
|
497
|
-
model,
|
|
736
|
+
response_summary: options.responseSummary,
|
|
737
|
+
provider: options.provider,
|
|
738
|
+
model: options.model,
|
|
498
739
|
token_usage: {
|
|
499
|
-
prompt_tokens: tokenUsage.promptTokens,
|
|
500
|
-
completion_tokens: tokenUsage.completionTokens,
|
|
501
|
-
total_tokens: tokenUsage.totalTokens
|
|
740
|
+
prompt_tokens: options.tokenUsage.promptTokens,
|
|
741
|
+
completion_tokens: options.tokenUsage.completionTokens,
|
|
742
|
+
total_tokens: options.tokenUsage.totalTokens,
|
|
502
743
|
},
|
|
503
|
-
latency_ms: latencyMs,
|
|
504
|
-
metadata
|
|
744
|
+
latency_ms: options.latencyMs,
|
|
745
|
+
metadata: options.metadata || {},
|
|
746
|
+
};
|
|
747
|
+
const headers = {
|
|
748
|
+
'Content-Type': 'application/json',
|
|
505
749
|
};
|
|
750
|
+
// Add authentication headers
|
|
751
|
+
const isLocalhost = this.config.endpoint.includes('localhost') || this.config.endpoint.includes('127.0.0.1');
|
|
752
|
+
if (!isLocalhost) {
|
|
753
|
+
if (this.config.licenseKey) {
|
|
754
|
+
headers['X-License-Key'] = this.config.licenseKey;
|
|
755
|
+
}
|
|
756
|
+
else if (this.config.apiKey) {
|
|
757
|
+
headers['X-Client-Secret'] = this.config.apiKey;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
506
760
|
if (this.config.debug) {
|
|
507
|
-
debugLog('Gateway
|
|
508
|
-
contextId,
|
|
509
|
-
provider,
|
|
510
|
-
model,
|
|
511
|
-
tokens: tokenUsage.totalTokens
|
|
761
|
+
debugLog('Gateway Mode: Audit', {
|
|
762
|
+
contextId: options.contextId,
|
|
763
|
+
provider: options.provider,
|
|
764
|
+
model: options.model,
|
|
512
765
|
});
|
|
513
766
|
}
|
|
514
|
-
const startTime = Date.now();
|
|
515
767
|
const response = await fetch(url, {
|
|
516
768
|
method: 'POST',
|
|
517
|
-
headers
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
'X-License-Key': this.config.apiKey
|
|
521
|
-
},
|
|
522
|
-
body: JSON.stringify(body),
|
|
523
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
769
|
+
headers,
|
|
770
|
+
body: JSON.stringify(requestBody),
|
|
771
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
524
772
|
});
|
|
525
|
-
const duration = Date.now() - startTime;
|
|
526
773
|
if (!response.ok) {
|
|
527
774
|
const errorText = await response.text();
|
|
528
|
-
|
|
775
|
+
if (response.status === 401 || response.status === 403) {
|
|
776
|
+
throw new AuthenticationError(`Audit logging authentication failed: ${errorText}`);
|
|
777
|
+
}
|
|
778
|
+
throw new APIError(response.status, response.statusText, errorText);
|
|
529
779
|
}
|
|
530
780
|
const data = await response.json();
|
|
531
|
-
|
|
532
|
-
debugLog('Gateway audit complete', {
|
|
533
|
-
auditId: data.audit_id,
|
|
534
|
-
duration
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
return {
|
|
781
|
+
const result = {
|
|
538
782
|
success: data.success,
|
|
539
|
-
auditId: data.audit_id
|
|
783
|
+
auditId: data.audit_id,
|
|
540
784
|
};
|
|
785
|
+
if (this.config.debug) {
|
|
786
|
+
debugLog('Gateway Mode: Audit logged', { auditId: result.auditId });
|
|
787
|
+
}
|
|
788
|
+
return result;
|
|
541
789
|
}
|
|
542
790
|
}
|
|
543
791
|
//# sourceMappingURL=client.js.map
|