@vaikora/sdk 0.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/dist/index.mjs ADDED
@@ -0,0 +1,1693 @@
1
+ // src/index.ts
2
+ import axios, { AxiosError } from "axios";
3
+ import axiosRetry from "axios-retry";
4
+
5
+ // src/errors.ts
6
+ var VaikoraError = class extends Error {
7
+ statusCode;
8
+ responseData;
9
+ constructor(message, statusCode, responseData) {
10
+ super(message);
11
+ this.name = "VaikoraError";
12
+ this.statusCode = statusCode;
13
+ this.responseData = responseData;
14
+ }
15
+ };
16
+ var AuthenticationError = class extends VaikoraError {
17
+ constructor(message, statusCode, responseData) {
18
+ super(message, statusCode, responseData);
19
+ this.name = "AuthenticationError";
20
+ }
21
+ };
22
+ var AuthorizationError = class extends VaikoraError {
23
+ constructor(message, statusCode, responseData) {
24
+ super(message, statusCode, responseData);
25
+ this.name = "AuthorizationError";
26
+ }
27
+ };
28
+ var RateLimitError = class extends VaikoraError {
29
+ retryAfter;
30
+ constructor(message, retryAfter, statusCode, responseData) {
31
+ super(message, statusCode, responseData);
32
+ this.name = "RateLimitError";
33
+ this.retryAfter = retryAfter;
34
+ }
35
+ };
36
+ var PolicyViolationError = class extends VaikoraError {
37
+ policyId;
38
+ policyName;
39
+ constructor(message, policyId, policyName, statusCode, responseData) {
40
+ super(message, statusCode, responseData);
41
+ this.name = "PolicyViolationError";
42
+ this.policyId = policyId;
43
+ this.policyName = policyName;
44
+ }
45
+ };
46
+ var NetworkError = class extends VaikoraError {
47
+ constructor(message) {
48
+ super(message);
49
+ this.name = "NetworkError";
50
+ }
51
+ };
52
+ var TimeoutError = class extends NetworkError {
53
+ constructor(message) {
54
+ super(message);
55
+ this.name = "TimeoutError";
56
+ }
57
+ };
58
+ var ValidationError = class extends VaikoraError {
59
+ errors;
60
+ constructor(message, errors, statusCode, responseData) {
61
+ super(message, statusCode, responseData);
62
+ this.name = "ValidationError";
63
+ this.errors = errors;
64
+ }
65
+ };
66
+ var NotFoundError = class extends VaikoraError {
67
+ constructor(message, statusCode, responseData) {
68
+ super(message, statusCode, responseData);
69
+ this.name = "NotFoundError";
70
+ }
71
+ };
72
+ var ConflictError = class extends VaikoraError {
73
+ constructor(message, statusCode, responseData) {
74
+ super(message, statusCode, responseData);
75
+ this.name = "ConflictError";
76
+ }
77
+ };
78
+ var ServerError = class extends VaikoraError {
79
+ constructor(message, statusCode, responseData) {
80
+ super(message, statusCode, responseData);
81
+ this.name = "ServerError";
82
+ }
83
+ };
84
+ function raiseForStatus(statusCode, responseData) {
85
+ const message = responseData.detail || responseData.message || "Unknown error";
86
+ if (statusCode === 401) {
87
+ throw new AuthenticationError(message, statusCode, responseData);
88
+ } else if (statusCode === 403) {
89
+ throw new AuthorizationError(message, statusCode, responseData);
90
+ } else if (statusCode === 404) {
91
+ throw new NotFoundError(message, statusCode, responseData);
92
+ } else if (statusCode === 409) {
93
+ throw new ConflictError(message, statusCode, responseData);
94
+ } else if (statusCode === 422) {
95
+ const errors = responseData.errors || responseData.detail;
96
+ const errorList = Array.isArray(errors) ? errors : typeof errors === "string" ? [{ msg: errors }] : [];
97
+ throw new ValidationError(message, errorList, statusCode, responseData);
98
+ } else if (statusCode === 429) {
99
+ const retryAfter = responseData.retry_after;
100
+ throw new RateLimitError(message, retryAfter, statusCode, responseData);
101
+ } else if (statusCode >= 400 && statusCode < 500) {
102
+ if (message.toLowerCase().includes("policy") || responseData.policy_id) {
103
+ throw new PolicyViolationError(
104
+ message,
105
+ responseData.policy_id,
106
+ responseData.policy_name,
107
+ statusCode,
108
+ responseData
109
+ );
110
+ }
111
+ throw new VaikoraError(message, statusCode, responseData);
112
+ } else if (statusCode >= 500) {
113
+ throw new ServerError(message, statusCode, responseData);
114
+ }
115
+ throw new VaikoraError(message, statusCode, responseData);
116
+ }
117
+
118
+ // src/utils.ts
119
+ function toCamelCase(str) {
120
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
121
+ }
122
+ function toSnakeCase(str) {
123
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
124
+ }
125
+ function transformKeysToCamel(obj) {
126
+ if (Array.isArray(obj)) {
127
+ return obj.map((item) => transformKeysToCamel(item));
128
+ }
129
+ if (obj !== null && typeof obj === "object") {
130
+ return Object.entries(obj).reduce(
131
+ (acc, [key, value]) => ({
132
+ ...acc,
133
+ [toCamelCase(key)]: transformKeysToCamel(value)
134
+ }),
135
+ {}
136
+ );
137
+ }
138
+ return obj;
139
+ }
140
+ function transformKeysToSnake(obj) {
141
+ if (Array.isArray(obj)) {
142
+ return obj.map((item) => transformKeysToSnake(item));
143
+ }
144
+ if (obj !== null && typeof obj === "object") {
145
+ return Object.entries(obj).reduce(
146
+ (acc, [key, value]) => ({
147
+ ...acc,
148
+ [toSnakeCase(key)]: transformKeysToSnake(value)
149
+ }),
150
+ {}
151
+ );
152
+ }
153
+ return obj;
154
+ }
155
+ function removeUndefined(obj) {
156
+ return Object.fromEntries(
157
+ Object.entries(obj).filter(([, value]) => value !== void 0)
158
+ );
159
+ }
160
+ function formatDate(date) {
161
+ if (!date) return void 0;
162
+ if (typeof date === "string") return date;
163
+ return date.toISOString();
164
+ }
165
+
166
+ // src/emergency.ts
167
+ var FreezeReason = /* @__PURE__ */ ((FreezeReason2) => {
168
+ FreezeReason2["MANUAL"] = "manual";
169
+ FreezeReason2["POLICY_VIOLATION"] = "policy_violation";
170
+ FreezeReason2["ANOMALY_DETECTED"] = "anomaly_detected";
171
+ FreezeReason2["RATE_LIMIT"] = "rate_limit";
172
+ FreezeReason2["SECURITY_THREAT"] = "security_threat";
173
+ FreezeReason2["SYSTEM_OVERLOAD"] = "system_overload";
174
+ FreezeReason2["CIRCUIT_BREAKER"] = "circuit_breaker";
175
+ FreezeReason2["MAINTENANCE"] = "maintenance";
176
+ return FreezeReason2;
177
+ })(FreezeReason || {});
178
+ var FreezeScope = /* @__PURE__ */ ((FreezeScope2) => {
179
+ FreezeScope2["ALL_ACTIONS"] = "all_actions";
180
+ FreezeScope2["WRITE_ACTIONS"] = "write_actions";
181
+ FreezeScope2["SPECIFIC_RESOURCE"] = "specific_resource";
182
+ FreezeScope2["SPECIFIC_ACTION_TYPE"] = "specific_action_type";
183
+ return FreezeScope2;
184
+ })(FreezeScope || {});
185
+ var CircuitState = /* @__PURE__ */ ((CircuitState2) => {
186
+ CircuitState2["CLOSED"] = "closed";
187
+ CircuitState2["OPEN"] = "open";
188
+ CircuitState2["HALF_OPEN"] = "half_open";
189
+ return CircuitState2;
190
+ })(CircuitState || {});
191
+ var CircuitBreaker = class {
192
+ name;
193
+ config;
194
+ state = "closed" /* CLOSED */;
195
+ failureCount = 0;
196
+ successCount = 0;
197
+ lastFailureTime;
198
+ halfOpenCalls = 0;
199
+ constructor(name, config) {
200
+ this.name = name;
201
+ this.config = {
202
+ failureThreshold: config?.failureThreshold ?? 5,
203
+ successThreshold: config?.successThreshold ?? 3,
204
+ timeoutSeconds: config?.timeoutSeconds ?? 60,
205
+ halfOpenMaxCalls: config?.halfOpenMaxCalls ?? 3
206
+ };
207
+ }
208
+ /**
209
+ * Check if circuit is open (blocking).
210
+ */
211
+ isOpen() {
212
+ if (this.state === "open" /* OPEN */) {
213
+ if (this.lastFailureTime) {
214
+ const elapsed = (Date.now() - this.lastFailureTime) / 1e3;
215
+ if (elapsed >= this.config.timeoutSeconds) {
216
+ this.state = "half_open" /* HALF_OPEN */;
217
+ this.halfOpenCalls = 0;
218
+ return false;
219
+ }
220
+ }
221
+ return true;
222
+ }
223
+ return false;
224
+ }
225
+ /**
226
+ * Record a successful call.
227
+ */
228
+ recordSuccess() {
229
+ if (this.state === "half_open" /* HALF_OPEN */) {
230
+ this.successCount++;
231
+ if (this.successCount >= this.config.successThreshold) {
232
+ this.state = "closed" /* CLOSED */;
233
+ this.failureCount = 0;
234
+ this.successCount = 0;
235
+ }
236
+ } else if (this.state === "closed" /* CLOSED */) {
237
+ this.failureCount = Math.max(0, this.failureCount - 1);
238
+ }
239
+ }
240
+ /**
241
+ * Record a failed call.
242
+ */
243
+ recordFailure() {
244
+ this.failureCount++;
245
+ this.lastFailureTime = Date.now();
246
+ if (this.state === "half_open" /* HALF_OPEN */) {
247
+ this.state = "open" /* OPEN */;
248
+ this.successCount = 0;
249
+ } else if (this.failureCount >= this.config.failureThreshold) {
250
+ this.state = "open" /* OPEN */;
251
+ this.successCount = 0;
252
+ }
253
+ }
254
+ /**
255
+ * Check if request should be allowed.
256
+ */
257
+ allowRequest() {
258
+ if (this.isOpen()) {
259
+ return false;
260
+ }
261
+ if (this.state === "half_open" /* HALF_OPEN */) {
262
+ if (this.halfOpenCalls >= this.config.halfOpenMaxCalls) {
263
+ return false;
264
+ }
265
+ this.halfOpenCalls++;
266
+ }
267
+ return true;
268
+ }
269
+ /**
270
+ * Wrap a function with circuit breaker protection.
271
+ */
272
+ wrap(fn) {
273
+ if (!this.allowRequest()) {
274
+ return Promise.reject(new CircuitBreakerOpenError(`Circuit breaker '${this.name}' is open`));
275
+ }
276
+ return fn().then((result) => {
277
+ this.recordSuccess();
278
+ return result;
279
+ }).catch((error) => {
280
+ this.recordFailure();
281
+ throw error;
282
+ });
283
+ }
284
+ };
285
+ var CircuitBreakerOpenError = class extends Error {
286
+ constructor(message) {
287
+ super(message);
288
+ this.name = "CircuitBreakerOpenError";
289
+ }
290
+ };
291
+ var AgentFrozenError = class extends Error {
292
+ freezeState;
293
+ constructor(message, freezeState) {
294
+ super(message);
295
+ this.name = "AgentFrozenError";
296
+ this.freezeState = freezeState;
297
+ }
298
+ };
299
+ var EmergencyController = class {
300
+ agentId;
301
+ freezeState;
302
+ circuitBreakers = /* @__PURE__ */ new Map();
303
+ freezeCallbacks = [];
304
+ resumeCallbacks = [];
305
+ rateLimits = /* @__PURE__ */ new Map();
306
+ constructor(agentId) {
307
+ this.agentId = agentId;
308
+ this.freezeState = {
309
+ isFrozen: false,
310
+ scope: "all_actions" /* ALL_ACTIONS */,
311
+ affectedResources: [],
312
+ affectedActionTypes: [],
313
+ metadata: {}
314
+ };
315
+ }
316
+ /**
317
+ * Check if agent is currently frozen.
318
+ */
319
+ get isFrozen() {
320
+ if (this.isExpired()) {
321
+ this.autoUnfreeze();
322
+ }
323
+ return this.freezeState.isFrozen;
324
+ }
325
+ /**
326
+ * Get current freeze state.
327
+ */
328
+ getFreezeState() {
329
+ return { ...this.freezeState };
330
+ }
331
+ /**
332
+ * Check if freeze has expired.
333
+ */
334
+ isExpired() {
335
+ if (!this.freezeState.freezeUntil) return false;
336
+ return /* @__PURE__ */ new Date() > this.freezeState.freezeUntil;
337
+ }
338
+ /**
339
+ * Freeze the agent immediately.
340
+ */
341
+ freeze(options) {
342
+ const now = /* @__PURE__ */ new Date();
343
+ let freezeUntil;
344
+ if (options.durationSeconds) {
345
+ freezeUntil = new Date(now.getTime() + options.durationSeconds * 1e3);
346
+ }
347
+ this.freezeState = {
348
+ isFrozen: true,
349
+ reason: options.reason,
350
+ scope: options.scope ?? "all_actions" /* ALL_ACTIONS */,
351
+ frozenAt: now,
352
+ frozenBy: options.frozenBy ?? "system",
353
+ freezeUntil,
354
+ affectedResources: options.affectedResources ?? [],
355
+ affectedActionTypes: options.affectedActionTypes ?? [],
356
+ message: options.message,
357
+ metadata: options.metadata ?? {}
358
+ };
359
+ console.warn(
360
+ `Agent ${this.agentId} FROZEN: reason=${options.reason}, scope=${options.scope ?? "all_actions"}, by=${options.frozenBy ?? "system"}`
361
+ );
362
+ for (const callback of this.freezeCallbacks) {
363
+ try {
364
+ callback(this.freezeState);
365
+ } catch (e) {
366
+ console.error("Freeze callback failed:", e);
367
+ }
368
+ }
369
+ return this.getFreezeState();
370
+ }
371
+ /**
372
+ * Resume agent operations.
373
+ */
374
+ resume(options = {}) {
375
+ if (!this.freezeState.isFrozen) {
376
+ return this.getFreezeState();
377
+ }
378
+ if (options.verificationPassed === false) {
379
+ console.warn(`Resume denied for agent ${this.agentId}: verification failed`);
380
+ return this.getFreezeState();
381
+ }
382
+ const oldState = { ...this.freezeState };
383
+ this.freezeState = {
384
+ isFrozen: false,
385
+ scope: "all_actions" /* ALL_ACTIONS */,
386
+ affectedResources: [],
387
+ affectedActionTypes: [],
388
+ metadata: {}
389
+ };
390
+ console.info(
391
+ `Agent ${this.agentId} RESUMED: by=${options.resumedBy ?? "system"}, was_frozen_for=${oldState.reason ?? "unknown"}`
392
+ );
393
+ for (const callback of this.resumeCallbacks) {
394
+ try {
395
+ callback(oldState, options.notes);
396
+ } catch (e) {
397
+ console.error("Resume callback failed:", e);
398
+ }
399
+ }
400
+ return this.getFreezeState();
401
+ }
402
+ /**
403
+ * Auto-unfreeze when time expires.
404
+ */
405
+ autoUnfreeze() {
406
+ console.info(`Agent ${this.agentId} auto-unfreezing (time expired)`);
407
+ this.freezeState = {
408
+ isFrozen: false,
409
+ scope: "all_actions" /* ALL_ACTIONS */,
410
+ affectedResources: [],
411
+ affectedActionTypes: [],
412
+ metadata: {}
413
+ };
414
+ }
415
+ /**
416
+ * Check if a specific action is blocked.
417
+ */
418
+ isActionBlocked(actionType, resource) {
419
+ if (!this.isFrozen) {
420
+ return { blocked: false };
421
+ }
422
+ const state = this.freezeState;
423
+ if (state.scope === "all_actions" /* ALL_ACTIONS */) {
424
+ return { blocked: true, message: state.message || `Agent frozen: ${state.reason}` };
425
+ }
426
+ if (state.scope === "write_actions" /* WRITE_ACTIONS */) {
427
+ const writeActions = ["create", "update", "delete", "write", "modify", "insert"];
428
+ if (writeActions.some((w) => actionType.toLowerCase().includes(w))) {
429
+ return { blocked: true, message: state.message || "Write actions frozen" };
430
+ }
431
+ }
432
+ if (state.scope === "specific_resource" /* SPECIFIC_RESOURCE */) {
433
+ if (resource && state.affectedResources.includes(resource)) {
434
+ return { blocked: true, message: state.message || `Resource ${resource} is frozen` };
435
+ }
436
+ }
437
+ if (state.scope === "specific_action_type" /* SPECIFIC_ACTION_TYPE */) {
438
+ if (state.affectedActionTypes.includes(actionType)) {
439
+ return { blocked: true, message: state.message || `Action type ${actionType} is frozen` };
440
+ }
441
+ }
442
+ return { blocked: false };
443
+ }
444
+ /**
445
+ * Register a callback for freeze events.
446
+ */
447
+ onFreeze(callback) {
448
+ this.freezeCallbacks.push(callback);
449
+ }
450
+ /**
451
+ * Register a callback for resume events.
452
+ */
453
+ onResume(callback) {
454
+ this.resumeCallbacks.push(callback);
455
+ }
456
+ /**
457
+ * Get or create a circuit breaker.
458
+ */
459
+ getCircuitBreaker(name, config) {
460
+ if (!this.circuitBreakers.has(name)) {
461
+ this.circuitBreakers.set(name, new CircuitBreaker(name, config));
462
+ }
463
+ return this.circuitBreakers.get(name);
464
+ }
465
+ /**
466
+ * Check if rate limit is exceeded.
467
+ */
468
+ checkRateLimit(key, maxRequests, windowSeconds) {
469
+ const now = Date.now();
470
+ const cutoff = now - windowSeconds * 1e3;
471
+ if (!this.rateLimits.has(key)) {
472
+ this.rateLimits.set(key, []);
473
+ }
474
+ const timestamps = this.rateLimits.get(key).filter((t) => t > cutoff);
475
+ this.rateLimits.set(key, timestamps);
476
+ if (timestamps.length >= maxRequests) {
477
+ return { allowed: false, remaining: 0 };
478
+ }
479
+ timestamps.push(now);
480
+ return { allowed: true, remaining: maxRequests - timestamps.length };
481
+ }
482
+ /**
483
+ * Get agent ID.
484
+ */
485
+ getAgentId() {
486
+ return this.agentId;
487
+ }
488
+ };
489
+ function assertNotFrozen(controller, actionType, resource) {
490
+ const { blocked, message } = controller.isActionBlocked(actionType, resource);
491
+ if (blocked) {
492
+ throw new AgentFrozenError(message || "Agent is frozen", controller.getFreezeState());
493
+ }
494
+ }
495
+ function frozenGuard(controller, actionType, resource) {
496
+ return function(fn) {
497
+ return async function(...args) {
498
+ assertNotFrozen(controller, actionType, resource);
499
+ return fn.apply(this, args);
500
+ };
501
+ };
502
+ }
503
+
504
+ // src/types.ts
505
+ var ApprovalStatus = /* @__PURE__ */ ((ApprovalStatus2) => {
506
+ ApprovalStatus2["PENDING"] = "pending";
507
+ ApprovalStatus2["APPROVED"] = "approved";
508
+ ApprovalStatus2["DENIED"] = "denied";
509
+ ApprovalStatus2["EXPIRED"] = "expired";
510
+ return ApprovalStatus2;
511
+ })(ApprovalStatus || {});
512
+
513
+ // src/identity.ts
514
+ import crypto from "crypto";
515
+ var AgentIdentity = class _AgentIdentity {
516
+ static NONCE_LENGTH = 16;
517
+ static MAX_TIMESTAMP_DRIFT_SECONDS = 300;
518
+ // 5 minutes
519
+ agentId;
520
+ apiKey;
521
+ secretKey;
522
+ environment;
523
+ requestCounter = 0;
524
+ usedNonces = /* @__PURE__ */ new Set();
525
+ nonceExpiry = /* @__PURE__ */ new Map();
526
+ constructor(agentId, apiKey, secretKey, environment = "production") {
527
+ this.agentId = agentId;
528
+ this.apiKey = apiKey;
529
+ this.secretKey = secretKey || this.generateSecretKey();
530
+ this.environment = environment;
531
+ }
532
+ /**
533
+ * Generate a cryptographically secure secret key.
534
+ */
535
+ generateSecretKey() {
536
+ return crypto.randomBytes(32).toString("base64url");
537
+ }
538
+ /**
539
+ * Generate a unique nonce for request signing.
540
+ */
541
+ generateNonce() {
542
+ return crypto.randomBytes(_AgentIdentity.NONCE_LENGTH).toString("base64url");
543
+ }
544
+ /**
545
+ * Get current timestamp in ISO format.
546
+ */
547
+ getTimestamp() {
548
+ return (/* @__PURE__ */ new Date()).toISOString();
549
+ }
550
+ /**
551
+ * Create SHA-256 hash of payload.
552
+ */
553
+ hashPayload(payload) {
554
+ let payloadStr;
555
+ if (payload === null || payload === void 0) {
556
+ payloadStr = "";
557
+ } else if (typeof payload === "string") {
558
+ payloadStr = payload;
559
+ } else {
560
+ payloadStr = JSON.stringify(payload);
561
+ }
562
+ return crypto.createHash("sha256").update(payloadStr).digest("hex");
563
+ }
564
+ /**
565
+ * Sign an API request.
566
+ */
567
+ signRequest(method, path, payload, additionalHeaders) {
568
+ const timestamp = this.getTimestamp();
569
+ const nonce = this.generateNonce();
570
+ const payloadHash = this.hashPayload(payload);
571
+ this.requestCounter++;
572
+ const requestId = `${this.agentId}-${Date.now()}-${String(this.requestCounter).padStart(6, "0")}`;
573
+ const canonicalString = [
574
+ method.toUpperCase(),
575
+ path,
576
+ timestamp,
577
+ nonce,
578
+ payloadHash,
579
+ this.agentId
580
+ ].join("\n");
581
+ const signature = crypto.createHmac("sha256", this.secretKey).update(canonicalString).digest("hex");
582
+ const signedHeaders = {
583
+ "X-Vaikora-Agent-ID": this.agentId,
584
+ "X-Vaikora-Request-ID": requestId,
585
+ "X-Vaikora-Timestamp": timestamp,
586
+ "X-Vaikora-Nonce": nonce,
587
+ "X-Vaikora-Signature": signature,
588
+ "X-Vaikora-Payload-Hash": payloadHash,
589
+ ...additionalHeaders
590
+ };
591
+ const signatureDetails = {
592
+ requestId,
593
+ agentId: this.agentId,
594
+ timestamp,
595
+ signature,
596
+ payloadHash,
597
+ nonce
598
+ };
599
+ this.usedNonces.add(nonce);
600
+ this.nonceExpiry.set(nonce, Date.now() + _AgentIdentity.MAX_TIMESTAMP_DRIFT_SECONDS * 1e3);
601
+ this.cleanupNonces();
602
+ return { headers: signedHeaders, signature: signatureDetails };
603
+ }
604
+ /**
605
+ * Verify a signed request.
606
+ */
607
+ verifySignature(method, path, timestamp, nonce, payloadHash, providedSignature, agentId) {
608
+ if (agentId !== this.agentId) {
609
+ return { isValid: false, errorMessage: "Agent ID mismatch" };
610
+ }
611
+ try {
612
+ const requestTime = new Date(timestamp);
613
+ const now = /* @__PURE__ */ new Date();
614
+ const driftSeconds = Math.abs((now.getTime() - requestTime.getTime()) / 1e3);
615
+ if (driftSeconds > _AgentIdentity.MAX_TIMESTAMP_DRIFT_SECONDS) {
616
+ return { isValid: false, errorMessage: `Timestamp too old: ${driftSeconds}s drift` };
617
+ }
618
+ } catch (e) {
619
+ return { isValid: false, errorMessage: `Invalid timestamp format: ${e}` };
620
+ }
621
+ if (this.usedNonces.has(nonce)) {
622
+ return { isValid: false, errorMessage: "Nonce already used (possible replay attack)" };
623
+ }
624
+ const canonicalString = [
625
+ method.toUpperCase(),
626
+ path,
627
+ timestamp,
628
+ nonce,
629
+ payloadHash,
630
+ agentId
631
+ ].join("\n");
632
+ const expectedSignature = crypto.createHmac("sha256", this.secretKey).update(canonicalString).digest("hex");
633
+ if (!crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(providedSignature))) {
634
+ return { isValid: false, errorMessage: "Signature mismatch" };
635
+ }
636
+ this.usedNonces.add(nonce);
637
+ this.nonceExpiry.set(nonce, Date.now() + _AgentIdentity.MAX_TIMESTAMP_DRIFT_SECONDS * 1e3);
638
+ return { isValid: true };
639
+ }
640
+ /**
641
+ * Clean up expired nonces.
642
+ */
643
+ cleanupNonces() {
644
+ const now = Date.now();
645
+ for (const [nonce, expiry] of this.nonceExpiry.entries()) {
646
+ if (expiry < now) {
647
+ this.usedNonces.delete(nonce);
648
+ this.nonceExpiry.delete(nonce);
649
+ }
650
+ }
651
+ }
652
+ /**
653
+ * Create a signed attestation of claims.
654
+ */
655
+ createAttestation(claims) {
656
+ const attestation = {
657
+ agentId: this.agentId,
658
+ claims,
659
+ issuedAt: this.getTimestamp(),
660
+ environment: this.environment
661
+ };
662
+ const payload = JSON.stringify(attestation);
663
+ const signature = crypto.createHmac("sha256", this.secretKey).update(payload).digest("hex");
664
+ attestation.signature = signature;
665
+ return Buffer.from(JSON.stringify(attestation)).toString("base64url");
666
+ }
667
+ /**
668
+ * Verify a signed attestation.
669
+ */
670
+ verifyAttestation(encodedAttestation) {
671
+ try {
672
+ const decoded = JSON.parse(Buffer.from(encodedAttestation, "base64url").toString());
673
+ const providedSignature = decoded.signature;
674
+ if (!providedSignature) {
675
+ return { isValid: false };
676
+ }
677
+ delete decoded.signature;
678
+ const payload = JSON.stringify(decoded);
679
+ const expectedSignature = crypto.createHmac("sha256", this.secretKey).update(payload).digest("hex");
680
+ if (!crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(providedSignature))) {
681
+ return { isValid: false };
682
+ }
683
+ return { isValid: true, attestation: decoded };
684
+ } catch (e) {
685
+ return { isValid: false };
686
+ }
687
+ }
688
+ /**
689
+ * Rotate the secret key.
690
+ */
691
+ rotateSecret() {
692
+ this.secretKey = this.generateSecretKey();
693
+ this.usedNonces.clear();
694
+ this.nonceExpiry.clear();
695
+ return this.secretKey;
696
+ }
697
+ /**
698
+ * Get identity information (without secrets).
699
+ */
700
+ getIdentityInfo() {
701
+ return {
702
+ agentId: this.agentId,
703
+ apiKey: this.apiKey,
704
+ environment: this.environment,
705
+ requestCount: this.requestCounter
706
+ };
707
+ }
708
+ /**
709
+ * Get the agent ID.
710
+ */
711
+ getAgentId() {
712
+ return this.agentId;
713
+ }
714
+ };
715
+
716
+ // src/context.ts
717
+ import { randomUUID } from "crypto";
718
+ var uuidv4 = () => randomUUID();
719
+ var ExecutionMode = /* @__PURE__ */ ((ExecutionMode2) => {
720
+ ExecutionMode2["ENFORCE"] = "enforce";
721
+ ExecutionMode2["MONITOR"] = "monitor";
722
+ ExecutionMode2["SIMULATE"] = "simulate";
723
+ return ExecutionMode2;
724
+ })(ExecutionMode || {});
725
+ var ContextLevel = /* @__PURE__ */ ((ContextLevel2) => {
726
+ ContextLevel2["ROOT"] = "root";
727
+ ContextLevel2["CHILD"] = "child";
728
+ ContextLevel2["NESTED"] = "nested";
729
+ return ContextLevel2;
730
+ })(ContextLevel || {});
731
+ var ExecutionContext = class _ExecutionContext {
732
+ // Identity
733
+ agentId;
734
+ sessionId;
735
+ // Execution settings
736
+ mode;
737
+ environment;
738
+ // Tracing
739
+ traceId;
740
+ spanId;
741
+ parentSpanId;
742
+ // Context level
743
+ level;
744
+ depth;
745
+ // Metadata
746
+ userId;
747
+ tenantId;
748
+ correlationId;
749
+ // Timing
750
+ createdAt;
751
+ timeoutSeconds;
752
+ deadline;
753
+ // Custom context
754
+ attributes;
755
+ baggage;
756
+ // Internal state
757
+ traces = [];
758
+ activeTrace;
759
+ constructor(options) {
760
+ this.agentId = options.agentId;
761
+ this.sessionId = options.sessionId || uuidv4();
762
+ this.mode = options.mode || "enforce" /* ENFORCE */;
763
+ this.environment = options.environment || "production";
764
+ this.traceId = options.traceId || uuidv4();
765
+ this.spanId = options.spanId || uuidv4().substring(0, 16);
766
+ this.parentSpanId = options.parentSpanId;
767
+ this.level = options.level || "root" /* ROOT */;
768
+ this.depth = options.depth || 0;
769
+ this.userId = options.userId;
770
+ this.tenantId = options.tenantId;
771
+ this.correlationId = options.correlationId;
772
+ this.createdAt = /* @__PURE__ */ new Date();
773
+ this.timeoutSeconds = options.timeoutSeconds;
774
+ this.attributes = options.attributes || {};
775
+ this.baggage = options.baggage || {};
776
+ if (options.timeoutSeconds) {
777
+ this.deadline = new Date(Date.now() + options.timeoutSeconds * 1e3);
778
+ }
779
+ }
780
+ /**
781
+ * Check if this is a dry-run (simulate mode).
782
+ */
783
+ isDryRun() {
784
+ return this.mode === "simulate" /* SIMULATE */;
785
+ }
786
+ /**
787
+ * Check if policy enforcement is active.
788
+ */
789
+ shouldEnforce() {
790
+ return this.mode === "enforce" /* ENFORCE */;
791
+ }
792
+ /**
793
+ * Check if violations should block execution.
794
+ */
795
+ shouldBlockViolations() {
796
+ return this.mode === "enforce" /* ENFORCE */;
797
+ }
798
+ /**
799
+ * Check if context deadline has passed.
800
+ */
801
+ isExpired() {
802
+ if (!this.deadline) return false;
803
+ return /* @__PURE__ */ new Date() > this.deadline;
804
+ }
805
+ /**
806
+ * Get remaining time before deadline.
807
+ */
808
+ remainingTimeSeconds() {
809
+ if (!this.deadline) return void 0;
810
+ const remaining = (this.deadline.getTime() - Date.now()) / 1e3;
811
+ return Math.max(0, remaining);
812
+ }
813
+ /**
814
+ * Start a new trace span.
815
+ */
816
+ startSpan(operationName, tags) {
817
+ const trace = {
818
+ traceId: this.traceId,
819
+ spanId: uuidv4().substring(0, 16),
820
+ parentSpanId: this.activeTrace?.spanId || this.spanId,
821
+ operationName,
822
+ startTime: Date.now(),
823
+ status: "pending",
824
+ tags: tags || {},
825
+ logs: []
826
+ };
827
+ this.traces.push(trace);
828
+ this.activeTrace = trace;
829
+ return trace;
830
+ }
831
+ /**
832
+ * End the current trace span.
833
+ */
834
+ endSpan(status = "ok") {
835
+ if (this.activeTrace) {
836
+ this.activeTrace.endTime = Date.now();
837
+ this.activeTrace.durationMs = this.activeTrace.endTime - this.activeTrace.startTime;
838
+ this.activeTrace.status = status;
839
+ this.activeTrace = void 0;
840
+ }
841
+ }
842
+ /**
843
+ * Add a log entry to the current trace.
844
+ */
845
+ addLog(message, level = "info") {
846
+ if (this.activeTrace) {
847
+ this.activeTrace.logs.push({
848
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
849
+ level,
850
+ message
851
+ });
852
+ }
853
+ }
854
+ /**
855
+ * Create a child context for nested operations.
856
+ */
857
+ childContext(_operation) {
858
+ return new _ExecutionContext({
859
+ agentId: this.agentId,
860
+ sessionId: this.sessionId,
861
+ mode: this.mode,
862
+ environment: this.environment,
863
+ traceId: this.traceId,
864
+ spanId: uuidv4().substring(0, 16),
865
+ parentSpanId: this.spanId,
866
+ level: this.level === "root" /* ROOT */ ? "child" /* CHILD */ : "nested" /* NESTED */,
867
+ depth: this.depth + 1,
868
+ userId: this.userId,
869
+ tenantId: this.tenantId,
870
+ correlationId: this.correlationId,
871
+ timeoutSeconds: this.remainingTimeSeconds(),
872
+ attributes: { ...this.attributes },
873
+ baggage: { ...this.baggage }
874
+ });
875
+ }
876
+ /**
877
+ * Create a new context with different execution mode.
878
+ */
879
+ withMode(mode) {
880
+ const ctx = this.childContext();
881
+ ctx.mode = mode;
882
+ return ctx;
883
+ }
884
+ /**
885
+ * Set a context attribute.
886
+ */
887
+ setAttribute(key, value) {
888
+ this.attributes[key] = value;
889
+ }
890
+ /**
891
+ * Get a context attribute.
892
+ */
893
+ getAttribute(key, defaultValue) {
894
+ return this.attributes[key] || defaultValue;
895
+ }
896
+ /**
897
+ * Set baggage (propagated across service boundaries).
898
+ */
899
+ setBaggage(key, value) {
900
+ this.baggage[key] = value;
901
+ }
902
+ /**
903
+ * Get baggage value.
904
+ */
905
+ getBaggage(key, defaultValue = "") {
906
+ return this.baggage[key] || defaultValue;
907
+ }
908
+ /**
909
+ * Export context to HTTP headers for propagation.
910
+ */
911
+ toHeaders() {
912
+ const headers = {
913
+ "X-Vaikora-Trace-ID": this.traceId,
914
+ "X-Vaikora-Span-ID": this.spanId,
915
+ "X-Vaikora-Agent-ID": this.agentId,
916
+ "X-Vaikora-Session-ID": this.sessionId,
917
+ "X-Vaikora-Mode": this.mode
918
+ };
919
+ if (this.parentSpanId) {
920
+ headers["X-Vaikora-Parent-Span-ID"] = this.parentSpanId;
921
+ }
922
+ if (this.correlationId) {
923
+ headers["X-Vaikora-Correlation-ID"] = this.correlationId;
924
+ }
925
+ if (this.tenantId) {
926
+ headers["X-Vaikora-Tenant-ID"] = this.tenantId;
927
+ }
928
+ for (const [key, value] of Object.entries(this.baggage)) {
929
+ headers[`X-Vaikora-Baggage-${key}`] = value;
930
+ }
931
+ return headers;
932
+ }
933
+ /**
934
+ * Create context from HTTP headers.
935
+ */
936
+ static fromHeaders(headers, agentId) {
937
+ const modeStr = headers["X-Vaikora-Mode"] || headers["x-vaikora-mode"] || "enforce";
938
+ let mode;
939
+ try {
940
+ mode = modeStr;
941
+ } catch {
942
+ mode = "enforce" /* ENFORCE */;
943
+ }
944
+ const baggage = {};
945
+ for (const [key, value] of Object.entries(headers)) {
946
+ const lowerKey = key.toLowerCase();
947
+ if (lowerKey.startsWith("x-vaikora-baggage-")) {
948
+ const baggageKey = key.substring(18);
949
+ baggage[baggageKey] = value;
950
+ }
951
+ }
952
+ return new _ExecutionContext({
953
+ agentId,
954
+ sessionId: headers["X-Vaikora-Session-ID"] || headers["x-vaikora-session-id"],
955
+ mode,
956
+ traceId: headers["X-Vaikora-Trace-ID"] || headers["x-vaikora-trace-id"],
957
+ parentSpanId: headers["X-Vaikora-Span-ID"] || headers["x-vaikora-span-id"],
958
+ correlationId: headers["X-Vaikora-Correlation-ID"] || headers["x-vaikora-correlation-id"],
959
+ tenantId: headers["X-Vaikora-Tenant-ID"] || headers["x-vaikora-tenant-id"],
960
+ level: "child" /* CHILD */,
961
+ baggage
962
+ });
963
+ }
964
+ /**
965
+ * Export context to dictionary.
966
+ */
967
+ toDict() {
968
+ return {
969
+ agentId: this.agentId,
970
+ sessionId: this.sessionId,
971
+ mode: this.mode,
972
+ environment: this.environment,
973
+ traceId: this.traceId,
974
+ spanId: this.spanId,
975
+ parentSpanId: this.parentSpanId,
976
+ level: this.level,
977
+ depth: this.depth,
978
+ userId: this.userId,
979
+ tenantId: this.tenantId,
980
+ correlationId: this.correlationId,
981
+ createdAt: this.createdAt.toISOString(),
982
+ attributes: this.attributes,
983
+ baggage: this.baggage,
984
+ traceCount: this.traces.length
985
+ };
986
+ }
987
+ /**
988
+ * Get all traces.
989
+ */
990
+ getTraces() {
991
+ return [...this.traces];
992
+ }
993
+ };
994
+ var currentContext;
995
+ function getCurrentContext() {
996
+ return currentContext;
997
+ }
998
+ function setCurrentContext(ctx) {
999
+ currentContext = ctx;
1000
+ }
1001
+ function clearContext() {
1002
+ currentContext = void 0;
1003
+ }
1004
+ async function withContextScope(ctx, fn) {
1005
+ const previousContext = currentContext;
1006
+ currentContext = ctx;
1007
+ try {
1008
+ return await fn();
1009
+ } finally {
1010
+ currentContext = previousContext;
1011
+ }
1012
+ }
1013
+ function withContext(mode = "enforce" /* ENFORCE */, timeoutSeconds) {
1014
+ return function(target, context) {
1015
+ return async function(...args) {
1016
+ const existing = getCurrentContext();
1017
+ let ctx;
1018
+ if (existing) {
1019
+ ctx = existing.childContext();
1020
+ } else {
1021
+ ctx = new ExecutionContext({ agentId: "unknown" });
1022
+ }
1023
+ ctx.mode = mode;
1024
+ if (timeoutSeconds) {
1025
+ ctx.setAttribute("_requestedTimeout", timeoutSeconds);
1026
+ }
1027
+ ctx.startSpan(context?.name || "anonymous");
1028
+ return withContextScope(ctx, async () => {
1029
+ try {
1030
+ const result = await target.apply(this, args);
1031
+ ctx.endSpan("ok");
1032
+ return result;
1033
+ } catch (error) {
1034
+ ctx.endSpan("error");
1035
+ ctx.addLog(String(error), "error");
1036
+ throw error;
1037
+ }
1038
+ });
1039
+ };
1040
+ };
1041
+ }
1042
+
1043
+ // src/interceptor.ts
1044
+ var InterceptorAction = /* @__PURE__ */ ((InterceptorAction2) => {
1045
+ InterceptorAction2["BLOCK"] = "block";
1046
+ InterceptorAction2["WARN"] = "warn";
1047
+ InterceptorAction2["QUEUE"] = "queue";
1048
+ InterceptorAction2["FALLBACK"] = "fallback";
1049
+ return InterceptorAction2;
1050
+ })(InterceptorAction || {});
1051
+ var PolicyDeniedException = class extends Error {
1052
+ constructor(message, policyId, actionId) {
1053
+ super(message);
1054
+ this.policyId = policyId;
1055
+ this.actionId = actionId;
1056
+ this.name = "PolicyDeniedException";
1057
+ }
1058
+ };
1059
+ var ValidationException = class extends Error {
1060
+ constructor(message, issues) {
1061
+ super(message);
1062
+ this.issues = issues;
1063
+ this.name = "ValidationException";
1064
+ }
1065
+ };
1066
+ var ApprovalRequiredException = class extends Error {
1067
+ constructor(message, approvalId, actionId) {
1068
+ super(message);
1069
+ this.approvalId = approvalId;
1070
+ this.actionId = actionId;
1071
+ this.name = "ApprovalRequiredException";
1072
+ }
1073
+ };
1074
+ var ApprovalDeniedException = class extends Error {
1075
+ constructor(message, approvalId, reason) {
1076
+ super(message);
1077
+ this.approvalId = approvalId;
1078
+ this.reason = reason;
1079
+ this.name = "ApprovalDeniedException";
1080
+ }
1081
+ };
1082
+ var VaikoraInterceptor = class {
1083
+ client;
1084
+ config;
1085
+ constructor(client, config) {
1086
+ this.client = client;
1087
+ this.config = {
1088
+ actionType: config.actionType,
1089
+ resource: config.resource || "",
1090
+ agentId: config.agentId || client.getDefaultAgentId() || "",
1091
+ validateInputs: config.validateInputs ?? true,
1092
+ validateOutputs: config.validateOutputs ?? false,
1093
+ validationStrict: config.validationStrict ?? false,
1094
+ checkPii: config.checkPii ?? true,
1095
+ checkAnomalies: config.checkAnomalies ?? true,
1096
+ checkToxicity: config.checkToxicity ?? true,
1097
+ autoClean: config.autoClean ?? false,
1098
+ evaluatePolicy: config.evaluatePolicy ?? true,
1099
+ onPolicyDeny: config.onPolicyDeny ?? "block" /* BLOCK */,
1100
+ requireApproval: config.requireApproval ?? false,
1101
+ approvalTimeoutSeconds: config.approvalTimeoutSeconds ?? 3600,
1102
+ approvalNotifyChannels: config.approvalNotifyChannels ?? ["email"],
1103
+ approvalMessage: config.approvalMessage || "",
1104
+ fallbackFunction: config.fallbackFunction,
1105
+ metadata: config.metadata ?? {},
1106
+ tags: config.tags ?? []
1107
+ };
1108
+ }
1109
+ /**
1110
+ * Wrap a function with Vaikora security
1111
+ */
1112
+ wrap(fn) {
1113
+ return async (...args) => {
1114
+ const startTime = Date.now();
1115
+ const result = {
1116
+ success: false,
1117
+ validationIssues: [],
1118
+ approvalRequired: false,
1119
+ executionTimeMs: 0
1120
+ };
1121
+ try {
1122
+ if (this.config.validateInputs) {
1123
+ const validationResult = await this.validateData(args);
1124
+ if (!validationResult.isValid && this.config.validationStrict) {
1125
+ throw new ValidationException(
1126
+ "Input validation failed",
1127
+ validationResult.issues || []
1128
+ );
1129
+ }
1130
+ result.validationIssues.push(...validationResult.issues || []);
1131
+ }
1132
+ if (this.config.evaluatePolicy) {
1133
+ const actionResult = await this.client.actions.submit({
1134
+ agentId: this.config.agentId,
1135
+ actionType: this.config.actionType,
1136
+ resource: this.config.resource,
1137
+ payload: { args },
1138
+ metadata: {
1139
+ ...this.config.metadata,
1140
+ function: fn.name || "anonymous",
1141
+ tags: this.config.tags
1142
+ }
1143
+ });
1144
+ result.actionId = actionResult.actionId;
1145
+ if (!actionResult.approved) {
1146
+ result.policyViolation = actionResult.denialReason || "Policy denied";
1147
+ if (this.config.onPolicyDeny === "block" /* BLOCK */) {
1148
+ throw new PolicyDeniedException(
1149
+ result.policyViolation,
1150
+ actionResult.policyId ?? void 0,
1151
+ actionResult.actionId
1152
+ );
1153
+ }
1154
+ if (this.config.onPolicyDeny === "fallback" /* FALLBACK */ && this.config.fallbackFunction) {
1155
+ result.result = await this.config.fallbackFunction(...args);
1156
+ result.success = true;
1157
+ result.executionTimeMs = Date.now() - startTime;
1158
+ return result;
1159
+ }
1160
+ if (this.config.onPolicyDeny === "warn" /* WARN */) {
1161
+ console.warn(`[Vaikora] Policy warning: ${result.policyViolation}`);
1162
+ }
1163
+ }
1164
+ const extResult = actionResult;
1165
+ if (this.config.requireApproval && extResult.requiresApproval) {
1166
+ result.approvalRequired = true;
1167
+ result.approvalId = extResult.approvalId;
1168
+ const approved = await this.waitForApproval(extResult.approvalId);
1169
+ if (!approved) {
1170
+ throw new ApprovalDeniedException(
1171
+ "Approval denied",
1172
+ extResult.approvalId
1173
+ );
1174
+ }
1175
+ }
1176
+ }
1177
+ result.result = await fn(...args);
1178
+ if (this.config.validateOutputs && result.result !== void 0) {
1179
+ const outputValidation = await this.validateData([result.result]);
1180
+ if (!outputValidation.isValid && this.config.validationStrict) {
1181
+ throw new ValidationException(
1182
+ "Output validation failed",
1183
+ outputValidation.issues || []
1184
+ );
1185
+ }
1186
+ result.validationIssues.push(...outputValidation.issues || []);
1187
+ }
1188
+ if (result.actionId) {
1189
+ await this.client.actions.complete(result.actionId, {
1190
+ status: "executed",
1191
+ executionTimeMs: Date.now() - startTime
1192
+ });
1193
+ }
1194
+ result.success = true;
1195
+ } catch (error) {
1196
+ result.error = error instanceof Error ? error.message : String(error);
1197
+ if (result.actionId) {
1198
+ await this.client.actions.complete(result.actionId, {
1199
+ status: "failed",
1200
+ executionTimeMs: Date.now() - startTime,
1201
+ errorMessage: result.error
1202
+ });
1203
+ }
1204
+ throw error;
1205
+ } finally {
1206
+ result.executionTimeMs = Date.now() - startTime;
1207
+ }
1208
+ return result;
1209
+ };
1210
+ }
1211
+ /**
1212
+ * Validate data using Vaikora API
1213
+ */
1214
+ async validateData(data) {
1215
+ try {
1216
+ const response = await this.client.request(
1217
+ "POST",
1218
+ "/validate",
1219
+ {
1220
+ data: data.length === 1 ? data[0] : data,
1221
+ check_pii: this.config.checkPii,
1222
+ check_anomalies: this.config.checkAnomalies,
1223
+ check_toxicity: this.config.checkToxicity,
1224
+ auto_clean: this.config.autoClean
1225
+ }
1226
+ );
1227
+ const issues = [];
1228
+ if (response.piiDetected) {
1229
+ issues.push(`PII detected: ${response.piiDetections?.length || 0} items`);
1230
+ }
1231
+ if (response.anomalyDetected) {
1232
+ issues.push(`Anomalies detected: ${response.anomalyDetections?.length || 0} items`);
1233
+ }
1234
+ if (response.toxicityDetected) {
1235
+ issues.push(`Toxicity detected: ${response.toxicityDetections?.length || 0} items`);
1236
+ }
1237
+ return {
1238
+ isValid: issues.length === 0,
1239
+ issues
1240
+ };
1241
+ } catch (error) {
1242
+ console.warn("[Vaikora] Validation failed:", error);
1243
+ return { isValid: true, issues: [] };
1244
+ }
1245
+ }
1246
+ /**
1247
+ * Wait for approval to be granted or denied
1248
+ */
1249
+ async waitForApproval(approvalId) {
1250
+ const timeout = this.config.approvalTimeoutSeconds * 1e3;
1251
+ const pollInterval = 5e3;
1252
+ const startTime = Date.now();
1253
+ while (Date.now() - startTime < timeout) {
1254
+ try {
1255
+ const response = await this.client.request(
1256
+ "GET",
1257
+ `/approvals/${approvalId}/status`
1258
+ );
1259
+ if (response.status === "approved" /* APPROVED */) {
1260
+ return true;
1261
+ }
1262
+ if (response.status === "denied" /* DENIED */) {
1263
+ return false;
1264
+ }
1265
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1266
+ } catch (error) {
1267
+ console.warn("[Vaikora] Error checking approval status:", error);
1268
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1269
+ }
1270
+ }
1271
+ throw new ApprovalRequiredException(
1272
+ "Approval request timed out",
1273
+ approvalId
1274
+ );
1275
+ }
1276
+ };
1277
+ function createInterceptor(client, config) {
1278
+ const interceptor2 = new VaikoraInterceptor(client, config);
1279
+ return (fn) => interceptor2.wrap(fn);
1280
+ }
1281
+ function interceptor(client, config) {
1282
+ return function(_target, _propertyKey, descriptor) {
1283
+ const originalMethod = descriptor.value;
1284
+ const interceptorInstance = new VaikoraInterceptor(client, config);
1285
+ descriptor.value = async function(...args) {
1286
+ const result = await interceptorInstance.wrap(originalMethod.bind(this))(...args);
1287
+ return result.result;
1288
+ };
1289
+ return descriptor;
1290
+ };
1291
+ }
1292
+
1293
+ // src/index.ts
1294
+ var DEFAULT_BASE_URL = "https://api.vaikora.com";
1295
+ var DEFAULT_TIMEOUT = 3e4;
1296
+ var DEFAULT_RETRY_COUNT = 3;
1297
+ var AgentsAPI = class {
1298
+ constructor(client) {
1299
+ this.client = client;
1300
+ }
1301
+ async register(data) {
1302
+ const response = await this.client.request("POST", "/agents", transformKeysToSnake(data));
1303
+ return response;
1304
+ }
1305
+ async get(agentId) {
1306
+ return this.client.request("GET", `/agents/${agentId}`);
1307
+ }
1308
+ async list(params = {}) {
1309
+ const queryParams = removeUndefined({
1310
+ page: params.page,
1311
+ page_size: params.pageSize,
1312
+ status: params.status,
1313
+ agent_type: params.agentType
1314
+ });
1315
+ return this.client.request("GET", "/agents", void 0, queryParams);
1316
+ }
1317
+ async update(agentId, data) {
1318
+ const updateData = removeUndefined(transformKeysToSnake(data));
1319
+ return this.client.request("PATCH", `/agents/${agentId}`, updateData);
1320
+ }
1321
+ async deactivate(agentId) {
1322
+ return this.update(agentId, { status: "inactive" });
1323
+ }
1324
+ async delete(agentId) {
1325
+ await this.client.request("DELETE", `/agents/${agentId}`);
1326
+ }
1327
+ };
1328
+ var ActionsAPI = class {
1329
+ constructor(client) {
1330
+ this.client = client;
1331
+ }
1332
+ async submit(data) {
1333
+ const requestData = removeUndefined({
1334
+ agent_id: data.agentId,
1335
+ action_type: data.actionType,
1336
+ resource: data.resource,
1337
+ payload: data.payload || {},
1338
+ metadata: data.metadata || {}
1339
+ });
1340
+ return this.client.request("POST", "/actions/evaluate", requestData);
1341
+ }
1342
+ async submitSandbox(data) {
1343
+ const requestData = removeUndefined({
1344
+ agent_id: data.agentId,
1345
+ action_type: data.actionType,
1346
+ resource: data.resource,
1347
+ payload: data.payload || {},
1348
+ metadata: data.metadata || {}
1349
+ });
1350
+ return this.client.request("POST", "/actions/sandbox", requestData);
1351
+ }
1352
+ async get(actionId) {
1353
+ return this.client.request("GET", `/actions/${actionId}`);
1354
+ }
1355
+ async list(params = {}) {
1356
+ const queryParams = removeUndefined({
1357
+ page: params.page,
1358
+ page_size: params.pageSize,
1359
+ agent_id: params.agentId,
1360
+ action_type: params.actionType,
1361
+ status: params.status,
1362
+ is_anomaly: params.isAnomaly,
1363
+ start_date: formatDate(params.startDate),
1364
+ end_date: formatDate(params.endDate)
1365
+ });
1366
+ return this.client.request("GET", "/actions", void 0, queryParams);
1367
+ }
1368
+ async complete(actionId, data) {
1369
+ const requestData = removeUndefined({
1370
+ status: data.status,
1371
+ execution_time_ms: data.executionTimeMs,
1372
+ error_message: data.errorMessage,
1373
+ result_metadata: data.resultMetadata || {}
1374
+ });
1375
+ return this.client.request("POST", `/actions/${actionId}/complete`, requestData);
1376
+ }
1377
+ };
1378
+ var PoliciesAPI = class {
1379
+ constructor(client) {
1380
+ this.client = client;
1381
+ }
1382
+ async list(params = {}) {
1383
+ const queryParams = removeUndefined({
1384
+ page: params.page,
1385
+ page_size: params.pageSize,
1386
+ enabled: params.enabled,
1387
+ policy_type: params.policyType
1388
+ });
1389
+ return this.client.request("GET", "/policies", void 0, queryParams);
1390
+ }
1391
+ async get(policyId) {
1392
+ return this.client.request("GET", `/policies/${policyId}`);
1393
+ }
1394
+ };
1395
+ var AlertsAPI = class {
1396
+ constructor(client) {
1397
+ this.client = client;
1398
+ }
1399
+ async list(params = {}) {
1400
+ const queryParams = removeUndefined({
1401
+ page: params.page,
1402
+ page_size: params.pageSize,
1403
+ status: params.status,
1404
+ severity: params.severity,
1405
+ agent_id: params.agentId
1406
+ });
1407
+ return this.client.request("GET", "/alerts", void 0, queryParams);
1408
+ }
1409
+ async get(alertId) {
1410
+ return this.client.request("GET", `/alerts/${alertId}`);
1411
+ }
1412
+ async acknowledge(alertId) {
1413
+ return this.client.request("POST", `/alerts/${alertId}/acknowledge`);
1414
+ }
1415
+ async resolve(alertId, options) {
1416
+ const data = options?.notes ? { resolution_notes: options.notes } : {};
1417
+ return this.client.request("POST", `/alerts/${alertId}/resolve`, data);
1418
+ }
1419
+ async ignore(alertId) {
1420
+ return this.client.request("POST", `/alerts/${alertId}/ignore`);
1421
+ }
1422
+ };
1423
+ var VaikoraClient = class {
1424
+ httpClient;
1425
+ defaultAgentId;
1426
+ agents;
1427
+ actions;
1428
+ policies;
1429
+ alerts;
1430
+ constructor(config) {
1431
+ const baseURL = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "") + "/api/v1";
1432
+ const timeout = config.timeout || DEFAULT_TIMEOUT;
1433
+ const retryCount = config.retryCount || DEFAULT_RETRY_COUNT;
1434
+ this.defaultAgentId = config.agentId;
1435
+ this.httpClient = axios.create({
1436
+ baseURL,
1437
+ timeout,
1438
+ headers: {
1439
+ "Authorization": `Bearer ${config.apiKey}`,
1440
+ "X-API-Key": config.apiKey,
1441
+ "Content-Type": "application/json",
1442
+ "User-Agent": "@vaikora/sdk/0.1.0"
1443
+ }
1444
+ });
1445
+ axiosRetry(this.httpClient, {
1446
+ retries: retryCount,
1447
+ retryDelay: axiosRetry.exponentialDelay,
1448
+ retryCondition: (error) => {
1449
+ return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 429 || error.response?.status !== void 0 && error.response.status >= 500;
1450
+ }
1451
+ });
1452
+ this.agents = new AgentsAPI(this);
1453
+ this.actions = new ActionsAPI(this);
1454
+ this.policies = new PoliciesAPI(this);
1455
+ this.alerts = new AlertsAPI(this);
1456
+ }
1457
+ /**
1458
+ * Make an HTTP request
1459
+ */
1460
+ async request(method, path, data, params) {
1461
+ try {
1462
+ const response = await this.httpClient.request({
1463
+ method,
1464
+ url: path,
1465
+ data,
1466
+ params
1467
+ });
1468
+ if (response.status === 204) {
1469
+ return {};
1470
+ }
1471
+ return transformKeysToCamel(response.data);
1472
+ } catch (error) {
1473
+ if (error instanceof AxiosError) {
1474
+ if (error.code === "ECONNABORTED") {
1475
+ throw new TimeoutError(`Request timed out: ${error.message}`);
1476
+ }
1477
+ if (!error.response) {
1478
+ throw new NetworkError(`Network error: ${error.message}`);
1479
+ }
1480
+ const responseData = error.response.data || {};
1481
+ raiseForStatus(error.response.status, responseData);
1482
+ }
1483
+ throw error;
1484
+ }
1485
+ }
1486
+ /**
1487
+ * Get the default agent ID
1488
+ */
1489
+ getDefaultAgentId() {
1490
+ return this.defaultAgentId;
1491
+ }
1492
+ };
1493
+ function secureAction(client, options) {
1494
+ return (fn) => {
1495
+ return async (...args) => {
1496
+ const agentId = options.agentId || client.getDefaultAgentId();
1497
+ if (!agentId) {
1498
+ throw new Error("agentId must be provided either to secureAction or client");
1499
+ }
1500
+ const startTime = Date.now();
1501
+ const result = await client.actions.submit({
1502
+ agentId,
1503
+ actionType: options.actionType,
1504
+ resource: options.resource,
1505
+ payload: { args },
1506
+ metadata: { function: fn.name || "anonymous" }
1507
+ });
1508
+ if (!result.approved) {
1509
+ throw new PolicyViolationError(
1510
+ result.denialReason || "Action denied by policy",
1511
+ result.policyId || void 0,
1512
+ void 0
1513
+ );
1514
+ }
1515
+ try {
1516
+ const output = await fn(...args);
1517
+ const executionTimeMs = Date.now() - startTime;
1518
+ await client.actions.complete(result.actionId, {
1519
+ status: "executed",
1520
+ executionTimeMs
1521
+ });
1522
+ return output;
1523
+ } catch (err) {
1524
+ const executionTimeMs = Date.now() - startTime;
1525
+ await client.actions.complete(result.actionId, {
1526
+ status: "failed",
1527
+ executionTimeMs,
1528
+ errorMessage: err instanceof Error ? err.message : String(err)
1529
+ });
1530
+ throw err;
1531
+ }
1532
+ };
1533
+ };
1534
+ }
1535
+ var globalClient = null;
1536
+ var globalAgentId = null;
1537
+ function configure(apiKey, options = {}) {
1538
+ globalClient = new VaikoraClient({
1539
+ apiKey,
1540
+ baseUrl: options.baseUrl,
1541
+ timeout: options.timeout,
1542
+ retryCount: options.retryCount
1543
+ });
1544
+ return globalClient;
1545
+ }
1546
+ function getClient() {
1547
+ if (!globalClient) {
1548
+ throw new Error(
1549
+ "Vaikora client not configured. Call configure(apiKey) first."
1550
+ );
1551
+ }
1552
+ return globalClient;
1553
+ }
1554
+ async function register(options) {
1555
+ const client = getClient();
1556
+ const agent = await client.agents.register({
1557
+ name: options.name,
1558
+ agentType: options.agentType || "autonomous",
1559
+ capabilities: options.capabilities || [],
1560
+ metadata: options.metadata || {}
1561
+ });
1562
+ globalAgentId = agent.id;
1563
+ return agent;
1564
+ }
1565
+ function getAgentId() {
1566
+ return globalAgentId;
1567
+ }
1568
+ function setAgentId(agentId) {
1569
+ globalAgentId = agentId;
1570
+ }
1571
+ async function validateData(data, options = {}) {
1572
+ const client = getClient();
1573
+ return client.request("POST", "/validate", {
1574
+ data,
1575
+ check_pii: options.checkPii ?? true,
1576
+ check_anomalies: options.checkAnomalies ?? true,
1577
+ check_toxicity: options.checkToxicity ?? true,
1578
+ auto_clean: options.autoClean ?? false
1579
+ });
1580
+ }
1581
+ async function submitAction(options) {
1582
+ const client = getClient();
1583
+ const agentId = options.agentId || globalAgentId;
1584
+ if (!agentId) {
1585
+ throw new Error(
1586
+ "No agent ID available. Call register() first or provide agentId in options."
1587
+ );
1588
+ }
1589
+ return client.actions.submit({
1590
+ agentId,
1591
+ actionType: options.actionType,
1592
+ resource: options.resource,
1593
+ payload: options.payload || {},
1594
+ metadata: options.metadata || {}
1595
+ });
1596
+ }
1597
+ function wrapAction(options, fn) {
1598
+ const client = getClient();
1599
+ const effectiveOptions = {
1600
+ ...options,
1601
+ agentId: options.agentId || globalAgentId || void 0
1602
+ };
1603
+ return secureAction(client, effectiveOptions)(fn);
1604
+ }
1605
+ var globalEmergencyController = null;
1606
+ function getEmergencyController() {
1607
+ if (!globalEmergencyController) {
1608
+ if (!globalAgentId) {
1609
+ throw new Error("Agent not registered. Call register() first.");
1610
+ }
1611
+ globalEmergencyController = new EmergencyController(globalAgentId);
1612
+ }
1613
+ return globalEmergencyController;
1614
+ }
1615
+ function freezeAgent(options) {
1616
+ const controller = getEmergencyController();
1617
+ return controller.freeze(options);
1618
+ }
1619
+ function resumeAgent(options = {}) {
1620
+ const controller = getEmergencyController();
1621
+ return controller.resume(options);
1622
+ }
1623
+ function isAgentFrozen() {
1624
+ try {
1625
+ const controller = getEmergencyController();
1626
+ return controller.isFrozen;
1627
+ } catch {
1628
+ return false;
1629
+ }
1630
+ }
1631
+ function getFreezeState() {
1632
+ try {
1633
+ const controller = getEmergencyController();
1634
+ return controller.getFreezeState();
1635
+ } catch {
1636
+ return null;
1637
+ }
1638
+ }
1639
+ export {
1640
+ AgentFrozenError,
1641
+ AgentIdentity,
1642
+ ApprovalDeniedException,
1643
+ ApprovalRequiredException,
1644
+ ApprovalStatus,
1645
+ AuthenticationError,
1646
+ AuthorizationError,
1647
+ CircuitBreaker,
1648
+ CircuitBreakerOpenError,
1649
+ CircuitState,
1650
+ ConflictError,
1651
+ ContextLevel,
1652
+ EmergencyController,
1653
+ ExecutionContext,
1654
+ ExecutionMode,
1655
+ FreezeReason,
1656
+ FreezeScope,
1657
+ InterceptorAction,
1658
+ NetworkError,
1659
+ NotFoundError,
1660
+ PolicyDeniedException,
1661
+ PolicyViolationError,
1662
+ RateLimitError,
1663
+ ServerError,
1664
+ TimeoutError,
1665
+ VaikoraClient,
1666
+ VaikoraError,
1667
+ VaikoraInterceptor,
1668
+ ValidationError,
1669
+ ValidationException,
1670
+ assertNotFrozen,
1671
+ clearContext,
1672
+ configure,
1673
+ createInterceptor,
1674
+ freezeAgent,
1675
+ frozenGuard,
1676
+ getAgentId,
1677
+ getClient,
1678
+ getCurrentContext,
1679
+ getFreezeState,
1680
+ interceptor,
1681
+ isAgentFrozen,
1682
+ raiseForStatus,
1683
+ register,
1684
+ resumeAgent,
1685
+ secureAction,
1686
+ setAgentId,
1687
+ setCurrentContext,
1688
+ submitAction,
1689
+ validateData,
1690
+ withContext,
1691
+ withContextScope,
1692
+ wrapAction
1693
+ };