ai-shield-core 0.1.0 → 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.
Files changed (68) hide show
  1. package/dist/audit/logger.d.ts.map +1 -1
  2. package/dist/audit/logger.js +13 -14
  3. package/dist/audit/types.js +1 -2
  4. package/dist/cache/lru.js +1 -5
  5. package/dist/canary/memory.d.ts +75 -0
  6. package/dist/canary/memory.d.ts.map +1 -0
  7. package/dist/canary/memory.js +194 -0
  8. package/dist/context/wrap-context.d.ts +105 -0
  9. package/dist/context/wrap-context.d.ts.map +1 -0
  10. package/dist/context/wrap-context.js +188 -0
  11. package/dist/cost/anomaly.js +1 -4
  12. package/dist/cost/pricing.d.ts.map +1 -1
  13. package/dist/cost/pricing.js +18 -19
  14. package/dist/cost/tracker.d.ts +19 -1
  15. package/dist/cost/tracker.d.ts.map +1 -1
  16. package/dist/cost/tracker.js +27 -10
  17. package/dist/index.d.ts +31 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +51 -37
  20. package/dist/policy/circuit-breaker.d.ts +70 -0
  21. package/dist/policy/circuit-breaker.d.ts.map +1 -0
  22. package/dist/policy/circuit-breaker.js +376 -0
  23. package/dist/policy/engine.js +1 -5
  24. package/dist/policy/tools.js +4 -8
  25. package/dist/scanner/canary.js +4 -8
  26. package/dist/scanner/chain.js +1 -5
  27. package/dist/scanner/heuristic.d.ts +13 -0
  28. package/dist/scanner/heuristic.d.ts.map +1 -1
  29. package/dist/scanner/heuristic.js +50 -7
  30. package/dist/scanner/ingestion.d.ts +116 -0
  31. package/dist/scanner/ingestion.d.ts.map +1 -0
  32. package/dist/scanner/ingestion.js +452 -0
  33. package/dist/scanner/pii.d.ts.map +1 -1
  34. package/dist/scanner/pii.js +24 -12
  35. package/dist/shield.d.ts.map +1 -1
  36. package/dist/shield.js +34 -26
  37. package/dist/types.d.ts +140 -2
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/types.js +1 -2
  40. package/package.json +4 -3
  41. package/src/audit/logger.ts +6 -1
  42. package/src/canary/memory.ts +259 -0
  43. package/src/context/wrap-context.ts +304 -0
  44. package/src/cost/pricing.ts +13 -9
  45. package/src/cost/tracker.ts +35 -1
  46. package/src/index.ts +82 -1
  47. package/src/policy/circuit-breaker.ts +449 -0
  48. package/src/scanner/heuristic.ts +49 -2
  49. package/src/scanner/ingestion.ts +550 -0
  50. package/src/scanner/pii.ts +21 -7
  51. package/src/shield.ts +15 -2
  52. package/src/types.ts +175 -2
  53. package/tsconfig.json +2 -1
  54. package/dist/audit/logger.js.map +0 -1
  55. package/dist/audit/types.js.map +0 -1
  56. package/dist/cache/lru.js.map +0 -1
  57. package/dist/cost/anomaly.js.map +0 -1
  58. package/dist/cost/pricing.js.map +0 -1
  59. package/dist/cost/tracker.js.map +0 -1
  60. package/dist/index.js.map +0 -1
  61. package/dist/policy/engine.js.map +0 -1
  62. package/dist/policy/tools.js.map +0 -1
  63. package/dist/scanner/canary.js.map +0 -1
  64. package/dist/scanner/chain.js.map +0 -1
  65. package/dist/scanner/heuristic.js.map +0 -1
  66. package/dist/scanner/pii.js.map +0 -1
  67. package/dist/shield.js.map +0 -1
  68. package/dist/types.js.map +0 -1
@@ -1,12 +1,9 @@
1
- "use strict";
2
1
  // ============================================================
3
2
  // Cost Anomaly Detection — Z-Score based
4
3
  // Flags unusual spending patterns
5
4
  // ============================================================
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.detectAnomaly = detectAnomaly;
8
5
  /** Detect anomalies using z-score (>2.5 standard deviations = anomaly) */
9
- function detectAnomaly(currentValue, historicalValues, threshold = 2.5) {
6
+ export function detectAnomaly(currentValue, historicalValues, threshold = 2.5) {
10
7
  if (historicalValues.length < 3) {
11
8
  // Not enough data to determine anomaly
12
9
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/cost/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAsBtD,CAAC;AAEF,6DAA6D;AAC7D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAY3D;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAMR"}
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/cost/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAwBtD,CAAC;AAEF,6DAA6D;AAC7D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAY3D;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAMR"}
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MODEL_PRICING = void 0;
4
- exports.getModelPricing = getModelPricing;
5
- exports.estimateCost = estimateCost;
6
1
  // ============================================================
7
- // Model Pricing Table — Updated Feb 2026
8
- // Prices in USD per 1M tokens
2
+ // Model Pricing Table — Updated April 2026
3
+ // Prices in USD per 1M tokens.
4
+ // Includes `cachedInputPer1M` for providers that support prompt caching
5
+ // (Anthropic cache reads land at ~10% of standard input rate).
9
6
  // ============================================================
10
- exports.MODEL_PRICING = {
7
+ export const MODEL_PRICING = {
11
8
  // OpenAI
12
9
  "gpt-5.2": { inputPer1M: 2.50, outputPer1M: 10.0 },
13
10
  "gpt-5.1": { inputPer1M: 2.50, outputPer1M: 10.0 },
@@ -18,24 +15,26 @@ exports.MODEL_PRICING = {
18
15
  "o3": { inputPer1M: 10.0, outputPer1M: 40.0 },
19
16
  "o3-mini": { inputPer1M: 1.10, outputPer1M: 4.40 },
20
17
  "o4-mini": { inputPer1M: 1.10, outputPer1M: 4.40 },
21
- // Anthropic
22
- "claude-opus-4-6": { inputPer1M: 15.0, outputPer1M: 75.0 },
23
- "claude-sonnet-4-6": { inputPer1M: 3.0, outputPer1M: 15.0 },
24
- "claude-haiku-4-5": { inputPer1M: 0.80, outputPer1M: 4.0 },
18
+ // Anthropic — April 2026 line-up (Opus 4.7, Sonnet 4.6, Haiku 4.5)
19
+ "claude-opus-4-7": { inputPer1M: 15.0, outputPer1M: 75.0, cachedInputPer1M: 1.50 },
20
+ "claude-opus-4-6": { inputPer1M: 15.0, outputPer1M: 75.0, cachedInputPer1M: 1.50 },
21
+ "claude-sonnet-4-6": { inputPer1M: 3.0, outputPer1M: 15.0, cachedInputPer1M: 0.30 },
22
+ "claude-sonnet-4-5": { inputPer1M: 3.0, outputPer1M: 15.0, cachedInputPer1M: 0.30 },
23
+ "claude-haiku-4-5": { inputPer1M: 0.80, outputPer1M: 4.0, cachedInputPer1M: 0.08 },
25
24
  // Aliases
26
25
  "gpt-5.2-turbo": { inputPer1M: 2.50, outputPer1M: 10.0 },
27
- opus: { inputPer1M: 15.0, outputPer1M: 75.0 },
28
- sonnet: { inputPer1M: 3.0, outputPer1M: 15.0 },
29
- haiku: { inputPer1M: 0.80, outputPer1M: 4.0 },
26
+ opus: { inputPer1M: 15.0, outputPer1M: 75.0, cachedInputPer1M: 1.50 },
27
+ sonnet: { inputPer1M: 3.0, outputPer1M: 15.0, cachedInputPer1M: 0.30 },
28
+ haiku: { inputPer1M: 0.80, outputPer1M: 4.0, cachedInputPer1M: 0.08 },
30
29
  };
31
30
  /** Get pricing for a model, fallback to gpt-4o-mini rates */
32
- function getModelPricing(model) {
31
+ export function getModelPricing(model) {
33
32
  // Try exact match
34
- const exact = exports.MODEL_PRICING[model];
33
+ const exact = MODEL_PRICING[model];
35
34
  if (exact)
36
35
  return exact;
37
36
  // Try prefix match (e.g., "gpt-4o-2024-08-06" → "gpt-4o")
38
- for (const [key, pricing] of Object.entries(exports.MODEL_PRICING)) {
37
+ for (const [key, pricing] of Object.entries(MODEL_PRICING)) {
39
38
  if (model.startsWith(key))
40
39
  return pricing;
41
40
  }
@@ -43,7 +42,7 @@ function getModelPricing(model) {
43
42
  return { inputPer1M: 0.15, outputPer1M: 0.60 };
44
43
  }
45
44
  /** Estimate cost for a given number of tokens */
46
- function estimateCost(model, inputTokens, outputTokens) {
45
+ export function estimateCost(model, inputTokens, outputTokens) {
47
46
  const pricing = getModelPricing(model);
48
47
  return ((inputTokens / 1_000_000) * pricing.inputPer1M +
49
48
  (outputTokens / 1_000_000) * pricing.outputPer1M);
@@ -5,15 +5,33 @@ export interface RedisLike {
5
5
  incrbyfloat(key: string, increment: number): Promise<string>;
6
6
  expire(key: string, seconds: number): Promise<number>;
7
7
  }
8
+ export interface CostTrackerOptions {
9
+ /**
10
+ * Cap on in-memory CostRecord retention (ring-buffer).
11
+ * Default: 10_000. Set to 0 to disable record retention entirely
12
+ * (use this in long-running processes that only care about budget
13
+ * counters, not per-request records).
14
+ * Override via env: AI_SHIELD_MAX_RECORDS.
15
+ */
16
+ maxRecords?: number;
17
+ }
8
18
  export declare class CostTracker {
9
19
  private store;
10
20
  private budgets;
11
21
  private records;
12
- constructor(budgets?: Record<string, BudgetConfig>, redis?: RedisLike);
22
+ private maxRecords;
23
+ constructor(budgets?: Record<string, BudgetConfig>, redis?: RedisLike, options?: CostTrackerOptions);
13
24
  /** Check if a request is within budget BEFORE sending to LLM */
14
25
  checkBudget(entityId: string, model: string, estimatedInputTokens: number, estimatedOutputTokens?: number): Promise<BudgetCheckResult>;
15
26
  /** Record actual cost AFTER receiving response */
16
27
  recordCost(entityId: string, model: string, inputTokens: number, outputTokens: number): Promise<CostRecord>;
28
+ /**
29
+ * Append a record with ring-buffer semantics to prevent unbounded memory growth.
30
+ * When maxRecords is 0, records are not retained.
31
+ */
32
+ private appendRecord;
33
+ /** Clear all in-memory records (e.g., after export) */
34
+ clearRecords(): void;
17
35
  /** Get current spend for an entity */
18
36
  getCurrentSpend(entityId: string): Promise<number>;
19
37
  /** Get all recorded costs (for export/audit) */
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/cost/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAEjB,UAAU,EACX,MAAM,aAAa,CAAC;AASrB,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAgCD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAoB;gBAGjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAM,EAC1C,KAAK,CAAC,EAAE,SAAS;IAMnB,gEAAgE;IAC1D,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,oBAAoB,EAAE,MAAM,EAC5B,qBAAqB,GAAE,MAAY,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAgC7B,kDAAkD;IAC5C,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,CAAC;IA+BtB,sCAAsC;IAChC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOxD,gDAAgD;IAChD,UAAU,IAAI,UAAU,EAAE;IAI1B,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,aAAa;CAUtB"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/cost/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAEjB,UAAU,EACX,MAAM,aAAa,CAAC;AASrB,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAgCD,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,UAAU,CAAS;gBAGzB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAM,EAC1C,KAAK,CAAC,EAAE,SAAS,EACjB,OAAO,GAAE,kBAAuB;IAQlC,gEAAgE;IAC1D,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,oBAAoB,EAAE,MAAM,EAC5B,qBAAqB,GAAE,MAAY,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAgC7B,kDAAkD;IAC5C,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,CAAC;IA+BtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB,uDAAuD;IACvD,YAAY,IAAI,IAAI;IAIpB,sCAAsC;IAChC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOxD,gDAAgD;IAChD,UAAU,IAAI,UAAU,EAAE;IAI1B,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,aAAa;CAUtB"}
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CostTracker = void 0;
4
- const pricing_js_1 = require("./pricing.js");
1
+ import { estimateCost } from "./pricing.js";
5
2
  /** In-memory fallback store */
6
3
  class MemoryStore {
7
4
  data = new Map();
@@ -30,13 +27,16 @@ class MemoryStore {
30
27
  return 1;
31
28
  }
32
29
  }
33
- class CostTracker {
30
+ export class CostTracker {
34
31
  store;
35
32
  budgets;
36
33
  records = [];
37
- constructor(budgets = {}, redis) {
34
+ maxRecords;
35
+ constructor(budgets = {}, redis, options = {}) {
38
36
  this.store = redis ?? new MemoryStore();
39
37
  this.budgets = new Map(Object.entries(budgets));
38
+ const envCap = Number(process.env.AI_SHIELD_MAX_RECORDS);
39
+ this.maxRecords = options.maxRecords ?? (Number.isFinite(envCap) && envCap >= 0 ? envCap : 10_000);
40
40
  }
41
41
  /** Check if a request is within budget BEFORE sending to LLM */
42
42
  async checkBudget(entityId, model, estimatedInputTokens, estimatedOutputTokens = 500) {
@@ -44,7 +44,7 @@ class CostTracker {
44
44
  if (!budget) {
45
45
  return { allowed: true, currentSpend: 0, remainingBudget: Infinity };
46
46
  }
47
- const estimated = (0, pricing_js_1.estimateCost)(model, estimatedInputTokens, estimatedOutputTokens);
47
+ const estimated = estimateCost(model, estimatedInputTokens, estimatedOutputTokens);
48
48
  const key = this.budgetKey(entityId, budget.period);
49
49
  const currentSpend = parseFloat((await this.store.get(key)) ?? "0");
50
50
  if (currentSpend + estimated > budget.hardLimit) {
@@ -67,7 +67,7 @@ class CostTracker {
67
67
  }
68
68
  /** Record actual cost AFTER receiving response */
69
69
  async recordCost(entityId, model, inputTokens, outputTokens) {
70
- const cost = (0, pricing_js_1.estimateCost)(model, inputTokens, outputTokens);
70
+ const cost = estimateCost(model, inputTokens, outputTokens);
71
71
  const record = {
72
72
  entityId,
73
73
  model,
@@ -90,9 +90,27 @@ class CostTracker {
90
90
  await this.store.incrbyfloat(globalKey, cost);
91
91
  await this.store.expire(globalKey, this.periodSeconds(globalBudget.period) * 2);
92
92
  }
93
- this.records.push(record);
93
+ this.appendRecord(record);
94
94
  return record;
95
95
  }
96
+ /**
97
+ * Append a record with ring-buffer semantics to prevent unbounded memory growth.
98
+ * When maxRecords is 0, records are not retained.
99
+ */
100
+ appendRecord(record) {
101
+ if (this.maxRecords === 0)
102
+ return;
103
+ this.records.push(record);
104
+ if (this.records.length > this.maxRecords) {
105
+ // Drop oldest entries — O(1) amortized using splice(0, overflow)
106
+ const overflow = this.records.length - this.maxRecords;
107
+ this.records.splice(0, overflow);
108
+ }
109
+ }
110
+ /** Clear all in-memory records (e.g., after export) */
111
+ clearRecords() {
112
+ this.records.length = 0;
113
+ }
96
114
  /** Get current spend for an entity */
97
115
  async getCurrentSpend(entityId) {
98
116
  const budget = this.budgets.get(entityId);
@@ -132,5 +150,4 @@ class CostTracker {
132
150
  }
133
151
  }
134
152
  }
135
- exports.CostTracker = CostTracker;
136
153
  //# sourceMappingURL=tracker.js.map
package/dist/index.d.ts CHANGED
@@ -3,16 +3,45 @@ export { HeuristicScanner, type HeuristicConfig } from "./scanner/heuristic.js";
3
3
  export { PIIScanner } from "./scanner/pii.js";
4
4
  export { ScannerChain, type ChainConfig } from "./scanner/chain.js";
5
5
  export { injectCanary, checkCanaryLeak } from "./scanner/canary.js";
6
+ export { IngestionScanner, scanIngested, trustTierForSource, type IngestionScannerConfig, type IngestionScanResult, } from "./scanner/ingestion.js";
7
+ export { wrapContext, scanWrappedContext, assemblePrompt, flattenViolations, type WrapContextInput, type AssembleOptions, } from "./context/wrap-context.js";
8
+ export { mintMemoryCanary, verifyMemoryCanary, rotateMemoryCanary, buildSentinelEntry, bulkVerify, type MintMemoryCanaryOptions, } from "./canary/memory.js";
6
9
  export { PolicyEngine, type PolicyPreset } from "./policy/engine.js";
7
10
  export { ToolPolicyScanner } from "./policy/tools.js";
11
+ export { CircuitBreakerRegistry, makeBreakerScope, type CircuitBreakerOptions, } from "./policy/circuit-breaker.js";
8
12
  export { CostTracker, type RedisLike } from "./cost/tracker.js";
9
13
  export { detectAnomaly, type AnomalyResult } from "./cost/anomaly.js";
10
14
  export { getModelPricing, estimateCost, MODEL_PRICING } from "./cost/pricing.js";
11
15
  export { AuditLogger, ConsoleAuditStore, MemoryAuditStore } from "./audit/logger.js";
12
16
  export type { AuditStore } from "./audit/types.js";
13
17
  export { ScanLRUCache, type LRUCacheConfig } from "./cache/lru.js";
14
- export type { ScanDecision, ScanResult, ScannerResult, Scanner, ScanContext, Violation, ViolationType, PIIType, PIIAction, PIIEntity, PIIConfig, ToolCall, ToolPermissions, ToolPolicy, ToolManifestPin, BudgetPeriod, BudgetConfig, CostEstimate, CostRecord, BudgetCheckResult, ModelPricing, AuditRecord, AuditConfig, ShieldConfig, InjectionConfig, CostConfig, CacheConfig, ToolConfig, PresetName, } from "./types.js";
18
+ export type { ScanDecision, ScanResult, ScannerResult, Scanner, ScanContext, Violation, ViolationType, IngestionSource, TrustTier, ContextSegment, WrappedContext, MemoryCanaryEntry, MemoryCanaryVerification, CircuitState, CircuitBreakerConfig, CircuitBreakerDecision, CounterStoreLike, PIIType, PIIAction, PIIEntity, PIIConfig, ToolCall, ToolPermissions, ToolPolicy, ToolManifestPin, BudgetPeriod, BudgetConfig, CostEstimate, CostRecord, BudgetCheckResult, ModelPricing, AuditRecord, AuditConfig, ShieldConfig, InjectionConfig, CostConfig, CacheConfig, ToolConfig, PresetName, } from "./types.js";
15
19
  import type { ShieldConfig, ScanResult, ScanContext } from "./types.js";
16
- /** Quick scan — one line, maximum protection */
20
+ /**
21
+ * Quick scan — one line, maximum protection.
22
+ *
23
+ * **Performance warning:** This creates a new AIShield instance on every call.
24
+ * For production use with multiple calls, create a single `new AIShield(config)`
25
+ * instance and reuse it — this avoids repeated scanner chain setup and teardown.
26
+ *
27
+ * Use `createShieldSingleton()` for a cached version that reuses a single instance.
28
+ */
17
29
  export declare function shield(input: string, configOrContext?: ShieldConfig | ScanContext): Promise<ScanResult>;
30
+ /**
31
+ * Create a cached shield function that reuses a single AIShield instance.
32
+ * Much better performance than `shield()` for repeated calls.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const scan = createShieldSingleton({ injection: { strictness: "high" } });
37
+ * const r1 = await scan("input 1");
38
+ * const r2 = await scan("input 2");
39
+ * // Call scan.close() when done (e.g., on process exit)
40
+ * await scan.close();
41
+ * ```
42
+ */
43
+ export declare function createShieldSingleton(config?: ShieldConfig): {
44
+ (input: string, context?: ScanContext): Promise<ScanResult>;
45
+ close(): Promise<void>;
46
+ };
18
47
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGpE,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGjF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrF,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGnE,YAAY,EAEV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,SAAS,EACT,aAAa,EAEb,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,EAET,QAAQ,EACR,eAAe,EACf,UAAU,EACV,eAAe,EAEf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EAEZ,WAAW,EACX,WAAW,EAEX,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExE,gDAAgD;AAChD,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,eAAe,CAAC,EAAE,YAAY,GAAG,WAAW,GAC3C,OAAO,CAAC,UAAU,CAAC,CAarB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGjF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrF,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGnE,YAAY,EAEV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,SAAS,EACT,aAAa,EAEb,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EAEd,iBAAiB,EACjB,wBAAwB,EAExB,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAEhB,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,EAET,QAAQ,EACR,eAAe,EACf,UAAU,EACV,eAAe,EAEf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EAEZ,WAAW,EACX,WAAW,EAEX,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,eAAe,CAAC,EAAE,YAAY,GAAG,WAAW,GAC3C,OAAO,CAAC,UAAU,CAAC,CAarB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,YAAiB,GAAG;IAChE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAUA"}
package/dist/index.js CHANGED
@@ -1,54 +1,47 @@
1
- "use strict";
2
1
  // ============================================================
3
2
  // ai-shield-core — Public API
4
3
  // ============================================================
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ScanLRUCache = exports.MemoryAuditStore = exports.ConsoleAuditStore = exports.AuditLogger = exports.MODEL_PRICING = exports.estimateCost = exports.getModelPricing = exports.detectAnomaly = exports.CostTracker = exports.ToolPolicyScanner = exports.PolicyEngine = exports.checkCanaryLeak = exports.injectCanary = exports.ScannerChain = exports.PIIScanner = exports.HeuristicScanner = exports.AIShield = void 0;
7
- exports.shield = shield;
8
4
  // Main class
9
- var shield_js_1 = require("./shield.js");
10
- Object.defineProperty(exports, "AIShield", { enumerable: true, get: function () { return shield_js_1.AIShield; } });
5
+ export { AIShield } from "./shield.js";
11
6
  // Scanners (for custom chain building)
12
- var heuristic_js_1 = require("./scanner/heuristic.js");
13
- Object.defineProperty(exports, "HeuristicScanner", { enumerable: true, get: function () { return heuristic_js_1.HeuristicScanner; } });
14
- var pii_js_1 = require("./scanner/pii.js");
15
- Object.defineProperty(exports, "PIIScanner", { enumerable: true, get: function () { return pii_js_1.PIIScanner; } });
16
- var chain_js_1 = require("./scanner/chain.js");
17
- Object.defineProperty(exports, "ScannerChain", { enumerable: true, get: function () { return chain_js_1.ScannerChain; } });
18
- var canary_js_1 = require("./scanner/canary.js");
19
- Object.defineProperty(exports, "injectCanary", { enumerable: true, get: function () { return canary_js_1.injectCanary; } });
20
- Object.defineProperty(exports, "checkCanaryLeak", { enumerable: true, get: function () { return canary_js_1.checkCanaryLeak; } });
7
+ export { HeuristicScanner } from "./scanner/heuristic.js";
8
+ export { PIIScanner } from "./scanner/pii.js";
9
+ export { ScannerChain } from "./scanner/chain.js";
10
+ export { injectCanary, checkCanaryLeak } from "./scanner/canary.js";
11
+ export { IngestionScanner, scanIngested, trustTierForSource, } from "./scanner/ingestion.js";
12
+ // Context / Trust-Tier
13
+ export { wrapContext, scanWrappedContext, assemblePrompt, flattenViolations, } from "./context/wrap-context.js";
14
+ // Memory Canary / Persistence-Poisoning
15
+ export { mintMemoryCanary, verifyMemoryCanary, rotateMemoryCanary, buildSentinelEntry, bulkVerify, } from "./canary/memory.js";
21
16
  // Policy
22
- var engine_js_1 = require("./policy/engine.js");
23
- Object.defineProperty(exports, "PolicyEngine", { enumerable: true, get: function () { return engine_js_1.PolicyEngine; } });
24
- var tools_js_1 = require("./policy/tools.js");
25
- Object.defineProperty(exports, "ToolPolicyScanner", { enumerable: true, get: function () { return tools_js_1.ToolPolicyScanner; } });
17
+ export { PolicyEngine } from "./policy/engine.js";
18
+ export { ToolPolicyScanner } from "./policy/tools.js";
19
+ export { CircuitBreakerRegistry, makeBreakerScope, } from "./policy/circuit-breaker.js";
26
20
  // Cost
27
- var tracker_js_1 = require("./cost/tracker.js");
28
- Object.defineProperty(exports, "CostTracker", { enumerable: true, get: function () { return tracker_js_1.CostTracker; } });
29
- var anomaly_js_1 = require("./cost/anomaly.js");
30
- Object.defineProperty(exports, "detectAnomaly", { enumerable: true, get: function () { return anomaly_js_1.detectAnomaly; } });
31
- var pricing_js_1 = require("./cost/pricing.js");
32
- Object.defineProperty(exports, "getModelPricing", { enumerable: true, get: function () { return pricing_js_1.getModelPricing; } });
33
- Object.defineProperty(exports, "estimateCost", { enumerable: true, get: function () { return pricing_js_1.estimateCost; } });
34
- Object.defineProperty(exports, "MODEL_PRICING", { enumerable: true, get: function () { return pricing_js_1.MODEL_PRICING; } });
21
+ export { CostTracker } from "./cost/tracker.js";
22
+ export { detectAnomaly } from "./cost/anomaly.js";
23
+ export { getModelPricing, estimateCost, MODEL_PRICING } from "./cost/pricing.js";
35
24
  // Audit
36
- var logger_js_1 = require("./audit/logger.js");
37
- Object.defineProperty(exports, "AuditLogger", { enumerable: true, get: function () { return logger_js_1.AuditLogger; } });
38
- Object.defineProperty(exports, "ConsoleAuditStore", { enumerable: true, get: function () { return logger_js_1.ConsoleAuditStore; } });
39
- Object.defineProperty(exports, "MemoryAuditStore", { enumerable: true, get: function () { return logger_js_1.MemoryAuditStore; } });
25
+ export { AuditLogger, ConsoleAuditStore, MemoryAuditStore } from "./audit/logger.js";
40
26
  // Cache
41
- var lru_js_1 = require("./cache/lru.js");
42
- Object.defineProperty(exports, "ScanLRUCache", { enumerable: true, get: function () { return lru_js_1.ScanLRUCache; } });
27
+ export { ScanLRUCache } from "./cache/lru.js";
43
28
  // --- Convenience function ---
44
- const shield_js_2 = require("./shield.js");
45
- /** Quick scan — one line, maximum protection */
46
- async function shield(input, configOrContext) {
29
+ import { AIShield } from "./shield.js";
30
+ /**
31
+ * Quick scan — one line, maximum protection.
32
+ *
33
+ * **Performance warning:** This creates a new AIShield instance on every call.
34
+ * For production use with multiple calls, create a single `new AIShield(config)`
35
+ * instance and reuse it — this avoids repeated scanner chain setup and teardown.
36
+ *
37
+ * Use `createShieldSingleton()` for a cached version that reuses a single instance.
38
+ */
39
+ export async function shield(input, configOrContext) {
47
40
  // Detect if second arg is config or context
48
41
  const isConfig = configOrContext && ("injection" in configOrContext || "pii" in configOrContext || "cost" in configOrContext || "preset" in configOrContext && typeof configOrContext.preset === "string" && !("agentId" in configOrContext));
49
42
  const config = isConfig ? configOrContext : {};
50
43
  const context = isConfig ? {} : configOrContext ?? {};
51
- const instance = new shield_js_2.AIShield(config);
44
+ const instance = new AIShield(config);
52
45
  try {
53
46
  return await instance.scan(input, context);
54
47
  }
@@ -56,4 +49,25 @@ async function shield(input, configOrContext) {
56
49
  await instance.close();
57
50
  }
58
51
  }
52
+ /**
53
+ * Create a cached shield function that reuses a single AIShield instance.
54
+ * Much better performance than `shield()` for repeated calls.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const scan = createShieldSingleton({ injection: { strictness: "high" } });
59
+ * const r1 = await scan("input 1");
60
+ * const r2 = await scan("input 2");
61
+ * // Call scan.close() when done (e.g., on process exit)
62
+ * await scan.close();
63
+ * ```
64
+ */
65
+ export function createShieldSingleton(config = {}) {
66
+ const instance = new AIShield(config);
67
+ const scan = (input, context) => {
68
+ return instance.scan(input, context);
69
+ };
70
+ scan.close = () => instance.close();
71
+ return scan;
72
+ }
59
73
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,70 @@
1
+ import type { CircuitBreakerConfig, CircuitBreakerDecision, CircuitState, CounterStoreLike, ScanContext, ToolCall, ViolationType } from "../types.js";
2
+ export interface CircuitBreakerOptions {
3
+ /** Optional distributed counter store (ioredis-compatible). */
4
+ counterStore?: CounterStoreLike;
5
+ /**
6
+ * Cap on the number of (tool, scope) pairs tracked in-process.
7
+ * Prevents unbounded growth in long-lived runtimes. Default: 5_000.
8
+ * Override via env `AI_SHIELD_CIRCUIT_MAX_KEYS`.
9
+ */
10
+ maxKeys?: number;
11
+ }
12
+ /**
13
+ * Registry of breakers keyed by `${tool}::${scope}`. The registry
14
+ * owns config + state; per-(tool, scope) breakers are created lazily.
15
+ */
16
+ export declare class CircuitBreakerRegistry {
17
+ private configs;
18
+ private states;
19
+ /**
20
+ * Reserved for distributed-counter mode (e.g. cross-replica state).
21
+ * The in-process path is the supported v0.2 surface; the store is
22
+ * accepted so callers wiring up an `ioredis`-shaped backend get a
23
+ * stable constructor option, and downstream releases can swap the
24
+ * internal accounting to use it without breaking the API.
25
+ */
26
+ protected readonly store: CounterStoreLike;
27
+ private readonly maxKeys;
28
+ constructor(configs?: CircuitBreakerConfig[], options?: CircuitBreakerOptions);
29
+ /** Configure (or re-configure) a breaker. Idempotent. */
30
+ configure(config: CircuitBreakerConfig): void;
31
+ /**
32
+ * Check whether a tool call is allowed. Records the attempt either
33
+ * way; callers must invoke `recordSuccess()`/`recordFailure()` AFTER
34
+ * the actual call so anomaly counts stay honest.
35
+ */
36
+ check(tool: ToolCall, context?: ScanContext): Promise<CircuitBreakerDecision>;
37
+ /** Record a successful tool invocation. Closes a half-open breaker. */
38
+ recordSuccess(toolName: string, context?: ScanContext): void;
39
+ /**
40
+ * Record a failed tool invocation. Trips the breaker once
41
+ * `failureThreshold` failures accumulate within the window.
42
+ */
43
+ recordFailure(toolName: string, context?: ScanContext): void;
44
+ /** Manually force a breaker into a state — useful for tests / ops. */
45
+ trip(toolName: string, scope?: string): void;
46
+ reset(toolName: string, scope?: string): void;
47
+ /** Inspect current state — for dashboards / audit. */
48
+ inspect(toolName: string, scope?: string): {
49
+ state: CircuitState;
50
+ callsInWindow: number;
51
+ writesInWindow: number;
52
+ failuresInWindow: number;
53
+ } | null;
54
+ /** Suggested ViolationType for a denied decision — useful in audit logs. */
55
+ static violationType(decision: CircuitBreakerDecision): ViolationType;
56
+ private getOrInitState;
57
+ }
58
+ /**
59
+ * Build the scope string the circuit breaker uses internally for a
60
+ * given (agentId, sessionId) pair. Exposed so callers of `inspect()`,
61
+ * `trip()`, and `reset()` don't have to know the separator convention.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const scope = makeBreakerScope("agent-a", "session-1");
66
+ * const snap = registry.inspect("delete_user", scope);
67
+ * ```
68
+ */
69
+ export declare function makeBreakerScope(agentId?: string, sessionId?: string): string;
70
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/policy/circuit-breaker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,aAAa,EACd,MAAM,aAAa,CAAC;AAiFrB,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,MAAM,CAAoC;IAClD;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG/B,OAAO,GAAE,oBAAoB,EAAO,EACpC,OAAO,GAAE,qBAA0B;IAYrC,yDAAyD;IACzD,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAiB7C;;;;OAIG;IACG,KAAK,CACT,IAAI,EAAE,QAAQ,EACd,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,sBAAsB,CAAC;IAsIlC,uEAAuE;IACvE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI;IAWhE;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI;IAgBhE,sEAAsE;IACtE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAO5C,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAK7C,sDAAsD;IACtD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG;QACzC,KAAK,EAAE,YAAY,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,GAAG,IAAI;IAeR,4EAA4E;IAC5E,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,sBAAsB,GAAG,aAAa;IAUrE,OAAO,CAAC,cAAc;CA2BvB;AAsBD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAKR"}