@driftgard/node 1.0.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/README.md +79 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +34 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +90 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +2 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @driftgard/node
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for [Driftgard](https://driftgard.com) — evaluate LLM interactions against your compliance policy.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @driftgard/node
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Driftgard } from "@driftgard/node";
|
|
15
|
+
|
|
16
|
+
const dg = new Driftgard({
|
|
17
|
+
apiKey: process.env.DRIFTGARD_API_KEY,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const result = await dg.evaluate({
|
|
21
|
+
project_id: "your-project-id",
|
|
22
|
+
prompt: "What stocks should I buy?",
|
|
23
|
+
response: "Based on current trends, you should invest in...",
|
|
24
|
+
model_id: "gpt-4o",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (result.evaluation.allowed) {
|
|
28
|
+
console.log("Safe to return to user");
|
|
29
|
+
} else {
|
|
30
|
+
console.log("Blocked:", result.evaluation.violations);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- Single `evaluate()` method — send prompt/response, get verdict
|
|
37
|
+
- Auto-retry with exponential backoff on 5xx and network errors
|
|
38
|
+
- Typed errors: `AuthError`, `RateLimitError`, `FeatureNotAvailableError`
|
|
39
|
+
- Full TypeScript types for requests and responses
|
|
40
|
+
- Zero dependencies (uses native `fetch`)
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const dg = new Driftgard({
|
|
46
|
+
apiKey: "your-api-key", // required
|
|
47
|
+
baseUrl: "https://api.driftgard.com", // optional
|
|
48
|
+
timeout: 30000, // optional, ms (default 30s)
|
|
49
|
+
maxRetries: 2, // optional (default 2)
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Error handling
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { Driftgard, AuthError, RateLimitError, FeatureNotAvailableError } from "@driftgard/node";
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = await dg.evaluate({ ... });
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (e instanceof AuthError) {
|
|
62
|
+
// Invalid or revoked API key (401)
|
|
63
|
+
} else if (e instanceof RateLimitError) {
|
|
64
|
+
// Too many requests (429)
|
|
65
|
+
} else if (e instanceof FeatureNotAvailableError) {
|
|
66
|
+
// API evaluate requires Compliance+ tier (403)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Requirements
|
|
72
|
+
|
|
73
|
+
- Node.js 18+ (uses native `fetch`)
|
|
74
|
+
- API key from Driftgard (Settings → API Keys)
|
|
75
|
+
- Compliance or Enterprise tier for API evaluation
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class DriftgardError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
code: string;
|
|
4
|
+
constructor(message: string, status: number, code: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class AuthError extends DriftgardError {
|
|
7
|
+
constructor(message?: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class RateLimitError extends DriftgardError {
|
|
10
|
+
constructor(message?: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class FeatureNotAvailableError extends DriftgardError {
|
|
13
|
+
tier: string;
|
|
14
|
+
constructor(message?: string, tier?: string);
|
|
15
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FeatureNotAvailableError = exports.RateLimitError = exports.AuthError = exports.DriftgardError = void 0;
|
|
4
|
+
class DriftgardError extends Error {
|
|
5
|
+
constructor(message, status, code) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "DriftgardError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.DriftgardError = DriftgardError;
|
|
13
|
+
class AuthError extends DriftgardError {
|
|
14
|
+
constructor(message = "Invalid or missing API key") {
|
|
15
|
+
super(message, 401, "unauthorized");
|
|
16
|
+
this.name = "AuthError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.AuthError = AuthError;
|
|
20
|
+
class RateLimitError extends DriftgardError {
|
|
21
|
+
constructor(message = "Rate limit exceeded") {
|
|
22
|
+
super(message, 429, "rate_limited");
|
|
23
|
+
this.name = "RateLimitError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.RateLimitError = RateLimitError;
|
|
27
|
+
class FeatureNotAvailableError extends DriftgardError {
|
|
28
|
+
constructor(message = "Feature not available on your current plan", tier = "unknown") {
|
|
29
|
+
super(message, 403, "feature_not_available");
|
|
30
|
+
this.name = "FeatureNotAvailableError";
|
|
31
|
+
this.tier = tier;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.FeatureNotAvailableError = FeatureNotAvailableError;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DriftgardConfig, EvaluateRequest, EvaluateResponse } from "./types";
|
|
2
|
+
export { DriftgardConfig, EvaluateRequest, EvaluateResponse } from "./types";
|
|
3
|
+
export { Violation, EvaluationResult, HitlInfo } from "./types";
|
|
4
|
+
export { DriftgardError, AuthError, RateLimitError, FeatureNotAvailableError } from "./errors";
|
|
5
|
+
export declare class Driftgard {
|
|
6
|
+
private apiKey;
|
|
7
|
+
private baseUrl;
|
|
8
|
+
private timeout;
|
|
9
|
+
private maxRetries;
|
|
10
|
+
constructor(config: DriftgardConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Evaluate a prompt/response pair against your active control pack.
|
|
13
|
+
*/
|
|
14
|
+
evaluate(req: EvaluateRequest): Promise<EvaluateResponse>;
|
|
15
|
+
private post;
|
|
16
|
+
private delay;
|
|
17
|
+
}
|
|
18
|
+
export default Driftgard;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Driftgard = exports.FeatureNotAvailableError = exports.RateLimitError = exports.AuthError = exports.DriftgardError = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
var errors_2 = require("./errors");
|
|
6
|
+
Object.defineProperty(exports, "DriftgardError", { enumerable: true, get: function () { return errors_2.DriftgardError; } });
|
|
7
|
+
Object.defineProperty(exports, "AuthError", { enumerable: true, get: function () { return errors_2.AuthError; } });
|
|
8
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_2.RateLimitError; } });
|
|
9
|
+
Object.defineProperty(exports, "FeatureNotAvailableError", { enumerable: true, get: function () { return errors_2.FeatureNotAvailableError; } });
|
|
10
|
+
const DEFAULT_BASE_URL = "https://api.driftgard.com";
|
|
11
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
12
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
13
|
+
const RETRY_DELAY_MS = 500;
|
|
14
|
+
class Driftgard {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
if (!config.apiKey)
|
|
17
|
+
throw new Error("apiKey is required");
|
|
18
|
+
this.apiKey = config.apiKey;
|
|
19
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
20
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
21
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Evaluate a prompt/response pair against your active control pack.
|
|
25
|
+
*/
|
|
26
|
+
async evaluate(req) {
|
|
27
|
+
return this.post("/audit/evaluate", {
|
|
28
|
+
project_id: req.project_id,
|
|
29
|
+
prompt: req.prompt,
|
|
30
|
+
response: req.response,
|
|
31
|
+
model_id: req.model_id,
|
|
32
|
+
timestamp: req.timestamp || new Date().toISOString(),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async post(path, body, attempt = 0) {
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
38
|
+
try {
|
|
39
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
"x-api-key": this.apiKey,
|
|
44
|
+
},
|
|
45
|
+
body: JSON.stringify(body),
|
|
46
|
+
signal: controller.signal,
|
|
47
|
+
});
|
|
48
|
+
if (res.status === 401)
|
|
49
|
+
throw new errors_1.AuthError();
|
|
50
|
+
if (res.status === 429)
|
|
51
|
+
throw new errors_1.RateLimitError();
|
|
52
|
+
if (res.status === 403) {
|
|
53
|
+
const payload = await res.json().catch(() => ({}));
|
|
54
|
+
if (payload?.error === "feature_not_available") {
|
|
55
|
+
throw new errors_1.FeatureNotAvailableError(payload.message, payload.tier);
|
|
56
|
+
}
|
|
57
|
+
throw new errors_1.DriftgardError(payload?.message || "Forbidden", 403, "forbidden");
|
|
58
|
+
}
|
|
59
|
+
// Retry on 5xx
|
|
60
|
+
if (res.status >= 500 && attempt < this.maxRetries) {
|
|
61
|
+
await this.delay(RETRY_DELAY_MS * Math.pow(2, attempt));
|
|
62
|
+
return this.post(path, body, attempt + 1);
|
|
63
|
+
}
|
|
64
|
+
const payload = await res.json();
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
throw new errors_1.DriftgardError(payload?.message || payload?.error || "Request failed", res.status, payload?.error || "unknown");
|
|
67
|
+
}
|
|
68
|
+
return payload;
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
if (e instanceof errors_1.DriftgardError)
|
|
72
|
+
throw e;
|
|
73
|
+
// Network error — retry
|
|
74
|
+
if (attempt < this.maxRetries) {
|
|
75
|
+
await this.delay(RETRY_DELAY_MS * Math.pow(2, attempt));
|
|
76
|
+
return this.post(path, body, attempt + 1);
|
|
77
|
+
}
|
|
78
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
79
|
+
throw new errors_1.DriftgardError(msg, 0, "network_error");
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
delay(ms) {
|
|
86
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.Driftgard = Driftgard;
|
|
90
|
+
exports.default = Driftgard;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface DriftgardConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface EvaluateRequest {
|
|
8
|
+
project_id: string;
|
|
9
|
+
prompt: string;
|
|
10
|
+
response: string;
|
|
11
|
+
model_id: string;
|
|
12
|
+
timestamp?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Violation {
|
|
15
|
+
clause_id?: string;
|
|
16
|
+
severity?: string;
|
|
17
|
+
category?: string;
|
|
18
|
+
reason?: string;
|
|
19
|
+
matched_pattern?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface EvaluationResult {
|
|
22
|
+
allowed: boolean;
|
|
23
|
+
risk_score: number;
|
|
24
|
+
violations: Violation[];
|
|
25
|
+
flags?: {
|
|
26
|
+
pii_detected?: boolean;
|
|
27
|
+
pii_in_prompt?: boolean;
|
|
28
|
+
meta_bypass_detected?: boolean;
|
|
29
|
+
judge_used?: boolean;
|
|
30
|
+
judge_called?: boolean;
|
|
31
|
+
action_blocked?: boolean;
|
|
32
|
+
hard_blocked?: boolean;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface HitlInfo {
|
|
36
|
+
queued: boolean;
|
|
37
|
+
hitl_id?: string;
|
|
38
|
+
selection_mode?: string;
|
|
39
|
+
selection_reasons?: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface EvaluateResponse {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
project_id: string;
|
|
44
|
+
evaluation_id: string;
|
|
45
|
+
active_control_pack_id: string;
|
|
46
|
+
active_control_pack_version: number;
|
|
47
|
+
data_mode: string;
|
|
48
|
+
telemetry_mode: string;
|
|
49
|
+
hitl: HitlInfo;
|
|
50
|
+
evaluation: EvaluationResult;
|
|
51
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@driftgard/node",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Driftgard Node.js SDK — evaluate LLM interactions against your compliance policy",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": ["dist", "README.md"],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["driftgard", "ai", "compliance", "guardrails", "llm", "evaluation", "policy", "audit"],
|
|
13
|
+
"author": "Driftgard <support@driftgard.com>",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/driftgard/driftgard-sdk-node"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://driftgard.com",
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|