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.
- package/dist/audit/logger.d.ts.map +1 -1
- package/dist/audit/logger.js +13 -14
- package/dist/audit/types.js +1 -2
- package/dist/cache/lru.js +1 -5
- package/dist/canary/memory.d.ts +75 -0
- package/dist/canary/memory.d.ts.map +1 -0
- package/dist/canary/memory.js +194 -0
- package/dist/context/wrap-context.d.ts +105 -0
- package/dist/context/wrap-context.d.ts.map +1 -0
- package/dist/context/wrap-context.js +188 -0
- package/dist/cost/anomaly.js +1 -4
- package/dist/cost/pricing.d.ts.map +1 -1
- package/dist/cost/pricing.js +18 -19
- package/dist/cost/tracker.d.ts +19 -1
- package/dist/cost/tracker.d.ts.map +1 -1
- package/dist/cost/tracker.js +27 -10
- package/dist/index.d.ts +31 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -37
- package/dist/policy/circuit-breaker.d.ts +70 -0
- package/dist/policy/circuit-breaker.d.ts.map +1 -0
- package/dist/policy/circuit-breaker.js +376 -0
- package/dist/policy/engine.js +1 -5
- package/dist/policy/tools.js +4 -8
- package/dist/scanner/canary.js +4 -8
- package/dist/scanner/chain.js +1 -5
- package/dist/scanner/heuristic.d.ts +13 -0
- package/dist/scanner/heuristic.d.ts.map +1 -1
- package/dist/scanner/heuristic.js +50 -7
- package/dist/scanner/ingestion.d.ts +116 -0
- package/dist/scanner/ingestion.d.ts.map +1 -0
- package/dist/scanner/ingestion.js +452 -0
- package/dist/scanner/pii.d.ts.map +1 -1
- package/dist/scanner/pii.js +24 -12
- package/dist/shield.d.ts.map +1 -1
- package/dist/shield.js +34 -26
- package/dist/types.d.ts +140 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/package.json +4 -3
- package/src/audit/logger.ts +6 -1
- package/src/canary/memory.ts +259 -0
- package/src/context/wrap-context.ts +304 -0
- package/src/cost/pricing.ts +13 -9
- package/src/cost/tracker.ts +35 -1
- package/src/index.ts +82 -1
- package/src/policy/circuit-breaker.ts +449 -0
- package/src/scanner/heuristic.ts +49 -2
- package/src/scanner/ingestion.ts +550 -0
- package/src/scanner/pii.ts +21 -7
- package/src/shield.ts +15 -2
- package/src/types.ts +175 -2
- package/tsconfig.json +2 -1
- package/dist/audit/logger.js.map +0 -1
- package/dist/audit/types.js.map +0 -1
- package/dist/cache/lru.js.map +0 -1
- package/dist/cost/anomaly.js.map +0 -1
- package/dist/cost/pricing.js.map +0 -1
- package/dist/cost/tracker.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/policy/engine.js.map +0 -1
- package/dist/policy/tools.js.map +0 -1
- package/dist/scanner/canary.js.map +0 -1
- package/dist/scanner/chain.js.map +0 -1
- package/dist/scanner/heuristic.js.map +0 -1
- package/dist/scanner/pii.js.map +0 -1
- package/dist/shield.js.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/cost/anomaly.js
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/cost/pricing.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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-
|
|
23
|
-
"claude-
|
|
24
|
-
"claude-
|
|
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 =
|
|
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(
|
|
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);
|
package/dist/cost/tracker.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
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"}
|
package/dist/cost/tracker.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
-
/**
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
/**
|
|
46
|
-
|
|
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
|
|
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"}
|