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