@vpdeva/blackwall-llm-shield-js 0.1.5 → 0.1.6
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/README.md +13 -6
- package/index.d.ts +92 -0
- package/integrations.d.ts +18 -0
- package/package.json +22 -5
- package/providers.d.ts +6 -0
- package/semantic.d.ts +4 -0
- package/src/index.js +26 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ npm install @xenova/transformers
|
|
|
32
32
|
## Fast Start
|
|
33
33
|
|
|
34
34
|
```js
|
|
35
|
-
const { BlackwallShield } = require('blackwall-llm-shield-js');
|
|
35
|
+
const { BlackwallShield } = require('@vpdeva/blackwall-llm-shield-js');
|
|
36
36
|
|
|
37
37
|
const shield = new BlackwallShield({
|
|
38
38
|
blockOnPromptInjection: true,
|
|
@@ -95,9 +95,9 @@ Use `createExpressMiddleware()`, `createLangChainCallbacks()`, or `createLlamaIn
|
|
|
95
95
|
|
|
96
96
|
### Subpath modules
|
|
97
97
|
|
|
98
|
-
Use `require('blackwall-llm-shield-js/integrations')` for callback wrappers and `require('blackwall-llm-shield-js/semantic')` for optional local semantic scoring adapters.
|
|
98
|
+
Use `require('@vpdeva/blackwall-llm-shield-js/integrations')` for callback wrappers and `require('@vpdeva/blackwall-llm-shield-js/semantic')` for optional local semantic scoring adapters.
|
|
99
99
|
|
|
100
|
-
Use `require('blackwall-llm-shield-js/providers')` for provider adapter factories.
|
|
100
|
+
Use `require('@vpdeva/blackwall-llm-shield-js/providers')` for provider adapter factories.
|
|
101
101
|
|
|
102
102
|
## Core Building Blocks
|
|
103
103
|
|
|
@@ -151,7 +151,7 @@ if (!guarded.allowed) {
|
|
|
151
151
|
### Wrap a provider call end to end
|
|
152
152
|
|
|
153
153
|
```js
|
|
154
|
-
const { BlackwallShield, createOpenAIAdapter } = require('blackwall-llm-shield-js');
|
|
154
|
+
const { BlackwallShield, createOpenAIAdapter } = require('@vpdeva/blackwall-llm-shield-js');
|
|
155
155
|
|
|
156
156
|
const shield = new BlackwallShield({
|
|
157
157
|
preset: 'shadowFirst',
|
|
@@ -234,15 +234,20 @@ const toolFirewall = new ToolPermissionFirewall({
|
|
|
234
234
|
### Operational telemetry summaries
|
|
235
235
|
|
|
236
236
|
```js
|
|
237
|
+
const { summarizeOperationalTelemetry } = require('@vpdeva/blackwall-llm-shield-js');
|
|
237
238
|
const summary = summarizeOperationalTelemetry(events);
|
|
238
239
|
console.log(summary.byRoute);
|
|
239
240
|
console.log(summary.highestSeverity);
|
|
240
241
|
```
|
|
241
242
|
|
|
243
|
+
### TypeScript
|
|
244
|
+
|
|
245
|
+
The package now ships first-class declaration files for the main entry point plus `integrations`, `providers`, and `semantic` subpaths, so local declaration shims should no longer be necessary in TypeScript apps.
|
|
246
|
+
|
|
242
247
|
### Inspect model output
|
|
243
248
|
|
|
244
249
|
```js
|
|
245
|
-
const { OutputFirewall } = require('blackwall-llm-shield-js');
|
|
250
|
+
const { OutputFirewall } = require('@vpdeva/blackwall-llm-shield-js');
|
|
246
251
|
|
|
247
252
|
const firewall = new OutputFirewall({
|
|
248
253
|
riskThreshold: 'high',
|
|
@@ -259,7 +264,7 @@ console.log(review.allowed);
|
|
|
259
264
|
### Gate tool execution
|
|
260
265
|
|
|
261
266
|
```js
|
|
262
|
-
const { ToolPermissionFirewall } = require('blackwall-llm-shield-js');
|
|
267
|
+
const { ToolPermissionFirewall } = require('@vpdeva/blackwall-llm-shield-js');
|
|
263
268
|
|
|
264
269
|
const tools = new ToolPermissionFirewall({
|
|
265
270
|
allowedTools: ['search', 'lookupCustomer'],
|
|
@@ -274,6 +279,8 @@ console.log(tools.inspectCall({ tool: 'lookupCustomer', args: { id: 'cus_123' }
|
|
|
274
279
|
- [`examples/nextjs-app-router/app/api/chat/route.js`](/Users/vishnu/Documents/blackwall-llm-shield/blackwall-llm-shield-js/examples/nextjs-app-router/app/api/chat/route.js) shows guarded request handling in a Next.js route
|
|
275
280
|
- [`examples/admin-dashboard/index.html`](/Users/vishnu/Documents/blackwall-llm-shield/blackwall-llm-shield-js/examples/admin-dashboard/index.html) shows a polished security command center demo
|
|
276
281
|
|
|
282
|
+
For Next.js, the most production-real patterns are App Router route handlers, server actions for trusted internal mutations, and streaming endpoints that apply output review to assembled or final chunks instead of raw intermediate tokens.
|
|
283
|
+
|
|
277
284
|
## Release Commands
|
|
278
285
|
|
|
279
286
|
- `npm run release:check` runs the JS test suite before release
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
|
|
2
|
+
|
|
3
|
+
export interface MessagePart {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
image_url?: string;
|
|
7
|
+
file_id?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ShieldMessage {
|
|
12
|
+
role: 'system' | 'user' | 'assistant';
|
|
13
|
+
content: string | MessagePart[] | Record<string, unknown>;
|
|
14
|
+
trusted?: boolean;
|
|
15
|
+
contentParts?: MessagePart[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface GuardResult {
|
|
19
|
+
allowed: boolean;
|
|
20
|
+
blocked: boolean;
|
|
21
|
+
reason: string | null;
|
|
22
|
+
messages: Array<ShieldMessage & { content: string; contentParts?: MessagePart[] }>;
|
|
23
|
+
report: Record<string, unknown>;
|
|
24
|
+
vault: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ReviewResult {
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
severity: RiskLevel;
|
|
30
|
+
findings: Array<Record<string, unknown>>;
|
|
31
|
+
report: Record<string, unknown>;
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ProviderAdapter {
|
|
36
|
+
provider: string;
|
|
37
|
+
invoke(payload: { messages: ShieldMessage[]; metadata?: Record<string, unknown>; guard?: GuardResult }): Promise<unknown> | unknown;
|
|
38
|
+
extractOutput?(response: unknown, request?: GuardResult): unknown;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ShieldOptions {
|
|
42
|
+
preset?: string | null;
|
|
43
|
+
policyPack?: string | null;
|
|
44
|
+
shadowMode?: boolean;
|
|
45
|
+
routePolicies?: Array<{ route: string | RegExp | ((route: string, metadata: Record<string, unknown>) => boolean); options: Record<string, unknown> }>;
|
|
46
|
+
customPromptDetectors?: Array<(payload: Record<string, unknown>) => Record<string, unknown> | Array<Record<string, unknown>> | null>;
|
|
47
|
+
onTelemetry?: (event: Record<string, unknown>) => void | Promise<void>;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class BlackwallShield {
|
|
52
|
+
constructor(options?: ShieldOptions);
|
|
53
|
+
inspectText(text: unknown): Record<string, unknown>;
|
|
54
|
+
guardModelRequest(input?: { messages?: ShieldMessage[]; metadata?: Record<string, unknown>; allowSystemMessages?: boolean; comparePolicyPacks?: string[] }): Promise<GuardResult>;
|
|
55
|
+
reviewModelResponse(input?: { output: unknown; metadata?: Record<string, unknown>; outputFirewall?: OutputFirewall | null; firewallOptions?: Record<string, unknown> }): Promise<ReviewResult>;
|
|
56
|
+
protectModelCall(input: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
57
|
+
protectWithAdapter(input: { adapter: ProviderAdapter; messages?: ShieldMessage[]; metadata?: Record<string, unknown>; allowSystemMessages?: boolean; comparePolicyPacks?: string[]; outputFirewall?: OutputFirewall | null; firewallOptions?: Record<string, unknown> }): Promise<Record<string, unknown>>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class OutputFirewall {
|
|
61
|
+
constructor(options?: Record<string, unknown>);
|
|
62
|
+
inspect(output: unknown, options?: Record<string, unknown>): ReviewResult;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class ToolPermissionFirewall {
|
|
66
|
+
constructor(options?: Record<string, unknown>);
|
|
67
|
+
inspectCall(input: Record<string, unknown>): Record<string, unknown>;
|
|
68
|
+
inspectCallAsync?(input: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class RetrievalSanitizer {
|
|
72
|
+
constructor(options?: Record<string, unknown>);
|
|
73
|
+
sanitizeDocuments(documents: Array<Record<string, unknown>>): Array<Record<string, unknown>>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class AuditTrail {
|
|
77
|
+
constructor(options?: Record<string, unknown>);
|
|
78
|
+
record(event?: Record<string, unknown>): Record<string, unknown>;
|
|
79
|
+
summarize(): Record<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const SHIELD_PRESETS: Record<string, Record<string, unknown>>;
|
|
83
|
+
export const CORE_INTERFACES: Record<string, string>;
|
|
84
|
+
export const POLICY_PACKS: Record<string, Record<string, unknown>>;
|
|
85
|
+
|
|
86
|
+
export function buildShieldOptions(options?: Record<string, unknown>): Record<string, unknown>;
|
|
87
|
+
export function summarizeOperationalTelemetry(events?: Array<Record<string, unknown>>): Record<string, unknown>;
|
|
88
|
+
|
|
89
|
+
export function createOpenAIAdapter(input: Record<string, unknown>): ProviderAdapter;
|
|
90
|
+
export function createAnthropicAdapter(input: Record<string, unknown>): ProviderAdapter;
|
|
91
|
+
export function createGeminiAdapter(input: Record<string, unknown>): ProviderAdapter;
|
|
92
|
+
export function createOpenRouterAdapter(input: Record<string, unknown>): ProviderAdapter;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { BlackwallShield, OutputFirewall, type ProviderAdapter } from './index';
|
|
2
|
+
|
|
3
|
+
export class BlackwallLangChainCallback {
|
|
4
|
+
constructor(options?: Record<string, unknown>);
|
|
5
|
+
handleLLMStart(llm: unknown, prompts?: string[]): Promise<unknown>;
|
|
6
|
+
guardMessages(messages: unknown, metadata?: Record<string, unknown>): Promise<unknown>;
|
|
7
|
+
handleLLMEnd(output: unknown): Promise<unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BlackwallLlamaIndexCallback {
|
|
11
|
+
constructor(options?: Record<string, unknown>);
|
|
12
|
+
onEventStart(event: unknown): Promise<unknown>;
|
|
13
|
+
onEventEnd(event: unknown): Promise<unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createExpressMiddleware(options?: Record<string, unknown>): (req: unknown, res: unknown, next: () => void) => Promise<void>;
|
|
17
|
+
export function createLangChainCallbacks(options?: Record<string, unknown>): Record<string, unknown>;
|
|
18
|
+
export function createLlamaIndexCallback(options?: Record<string, unknown>): Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vpdeva/blackwall-llm-shield-js",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Open-source JavaScript enterprise LLM protection toolkit for Node.js and Next.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Vish <hello@vish.au> (https://vish.au)",
|
|
7
7
|
"type": "commonjs",
|
|
8
8
|
"main": "src/index.js",
|
|
9
|
+
"types": "./index.d.ts",
|
|
9
10
|
"exports": {
|
|
10
|
-
".":
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"default": "./src/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./integrations": {
|
|
16
|
+
"types": "./integrations.d.ts",
|
|
17
|
+
"default": "./src/integrations.js"
|
|
18
|
+
},
|
|
19
|
+
"./providers": {
|
|
20
|
+
"types": "./providers.d.ts",
|
|
21
|
+
"default": "./src/providers.js"
|
|
22
|
+
},
|
|
23
|
+
"./semantic": {
|
|
24
|
+
"types": "./semantic.d.ts",
|
|
25
|
+
"default": "./src/semantic.js"
|
|
26
|
+
}
|
|
14
27
|
},
|
|
15
28
|
"bin": {
|
|
16
29
|
"blackwall-scorecard": "src/scorecard.js"
|
|
@@ -26,6 +39,10 @@
|
|
|
26
39
|
},
|
|
27
40
|
"files": [
|
|
28
41
|
"src",
|
|
42
|
+
"index.d.ts",
|
|
43
|
+
"integrations.d.ts",
|
|
44
|
+
"providers.d.ts",
|
|
45
|
+
"semantic.d.ts",
|
|
29
46
|
"README.md",
|
|
30
47
|
"LICENSE",
|
|
31
48
|
"NOTICE"
|
package/providers.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ProviderAdapter } from './index';
|
|
2
|
+
|
|
3
|
+
export function createOpenAIAdapter(input: Record<string, unknown>): import('./index').ProviderAdapter;
|
|
4
|
+
export function createAnthropicAdapter(input: Record<string, unknown>): import('./index').ProviderAdapter;
|
|
5
|
+
export function createGeminiAdapter(input: Record<string, unknown>): import('./index').ProviderAdapter;
|
|
6
|
+
export function createOpenRouterAdapter(input: Record<string, unknown>): import('./index').ProviderAdapter;
|
package/semantic.d.ts
ADDED
package/src/index.js
CHANGED
|
@@ -350,21 +350,46 @@ function summarizeOperationalTelemetry(events = []) {
|
|
|
350
350
|
shadowModeEvents: 0,
|
|
351
351
|
byType: {},
|
|
352
352
|
byRoute: {},
|
|
353
|
+
byTenant: {},
|
|
354
|
+
byModel: {},
|
|
355
|
+
byPolicyOutcome: {
|
|
356
|
+
blocked: 0,
|
|
357
|
+
shadowBlocked: 0,
|
|
358
|
+
allowed: 0,
|
|
359
|
+
},
|
|
360
|
+
topRules: {},
|
|
353
361
|
highestSeverity: 'low',
|
|
354
362
|
};
|
|
355
363
|
for (const event of Array.isArray(events) ? events : []) {
|
|
356
364
|
const type = event && event.type ? event.type : 'unknown';
|
|
357
|
-
const
|
|
365
|
+
const metadata = event && event.metadata ? event.metadata : {};
|
|
366
|
+
const route = metadata.route || metadata.path || 'unknown';
|
|
367
|
+
const tenant = metadata.tenantId || metadata.tenant_id || 'unknown';
|
|
368
|
+
const model = metadata.model || metadata.modelName || 'unknown';
|
|
358
369
|
const severity = event && event.report && event.report.outputReview
|
|
359
370
|
? event.report.outputReview.severity
|
|
360
371
|
: (event && event.report && event.report.promptInjection ? event.report.promptInjection.level : 'low');
|
|
361
372
|
summary.totalEvents += 1;
|
|
362
373
|
summary.byType[type] = (summary.byType[type] || 0) + 1;
|
|
363
374
|
summary.byRoute[route] = (summary.byRoute[route] || 0) + 1;
|
|
375
|
+
summary.byTenant[tenant] = (summary.byTenant[tenant] || 0) + 1;
|
|
376
|
+
summary.byModel[model] = (summary.byModel[model] || 0) + 1;
|
|
364
377
|
if (event && event.blocked) summary.blockedEvents += 1;
|
|
365
378
|
if (event && event.shadowMode) summary.shadowModeEvents += 1;
|
|
379
|
+
if (event && event.blocked) summary.byPolicyOutcome.blocked += 1;
|
|
380
|
+
else if (event && event.shadowMode) summary.byPolicyOutcome.shadowBlocked += 1;
|
|
381
|
+
else summary.byPolicyOutcome.allowed += 1;
|
|
382
|
+
const rules = event && event.report && event.report.promptInjection && Array.isArray(event.report.promptInjection.matches)
|
|
383
|
+
? event.report.promptInjection.matches.map((item) => item.id).filter(Boolean)
|
|
384
|
+
: [];
|
|
385
|
+
rules.forEach((rule) => {
|
|
386
|
+
summary.topRules[rule] = (summary.topRules[rule] || 0) + 1;
|
|
387
|
+
});
|
|
366
388
|
if (severityWeight(severity) > severityWeight(summary.highestSeverity)) summary.highestSeverity = severity;
|
|
367
389
|
}
|
|
390
|
+
summary.topRules = Object.fromEntries(
|
|
391
|
+
Object.entries(summary.topRules).sort((a, b) => b[1] - a[1]).slice(0, 10)
|
|
392
|
+
);
|
|
368
393
|
return summary;
|
|
369
394
|
}
|
|
370
395
|
|