@silmaril-security/sdk 0.7.7 → 0.7.9
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/CHANGELOG.md +15 -1
- package/README.md +57 -3
- package/dist/adapters/deepagents.cjs +28 -1
- package/dist/adapters/deepagents.cjs.map +1 -1
- package/dist/adapters/deepagents.d.cts +1 -1
- package/dist/adapters/deepagents.d.ts +1 -1
- package/dist/adapters/deepagents.js +28 -1
- package/dist/adapters/deepagents.js.map +1 -1
- package/dist/adapters/langchain.cjs +28 -1
- package/dist/adapters/langchain.cjs.map +1 -1
- package/dist/adapters/langchain.d.cts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/langchain.js +28 -1
- package/dist/adapters/langchain.js.map +1 -1
- package/dist/adapters/vercel.cjs +9 -1
- package/dist/adapters/vercel.cjs.map +1 -1
- package/dist/adapters/vercel.d.cts +1 -1
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/adapters/vercel.js +9 -1
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/{firewall-CueYday8.d.cts → firewall-DqjD6aXD.d.cts} +11 -1
- package/dist/{firewall-CueYday8.d.ts → firewall-DqjD6aXD.d.ts} +11 -1
- package/dist/index.cjs +102 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +101 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -14,6 +14,19 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/exceptions.ts
|
|
17
|
+
function isReviewCompatibilityError(error) {
|
|
18
|
+
if (typeof error !== "object" && typeof error !== "function" || error === null) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return Object.getOwnPropertyDescriptor(
|
|
23
|
+
error,
|
|
24
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND
|
|
25
|
+
)?.value === true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
17
30
|
function parseErrorBody(body) {
|
|
18
31
|
try {
|
|
19
32
|
const parsed = JSON.parse(body);
|
|
@@ -30,7 +43,7 @@ function parseErrorBody(body) {
|
|
|
30
43
|
return { details: void 0, error: void 0, apiMessage: void 0 };
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
|
-
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, SilmarilApiError;
|
|
46
|
+
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, REVIEW_COMPATIBILITY_ERROR_BRAND, ReviewCompatibilityError, SilmarilApiError;
|
|
34
47
|
var init_exceptions = __esm({
|
|
35
48
|
"src/exceptions.ts"() {
|
|
36
49
|
"use strict";
|
|
@@ -66,6 +79,27 @@ var init_exceptions = __esm({
|
|
|
66
79
|
}
|
|
67
80
|
};
|
|
68
81
|
PromptBlockedException = FirewallBlockedException;
|
|
82
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND = /* @__PURE__ */ Symbol.for(
|
|
83
|
+
"@silmaril-security/sdk/ReviewCompatibilityError"
|
|
84
|
+
);
|
|
85
|
+
ReviewCompatibilityError = class _ReviewCompatibilityError extends Error {
|
|
86
|
+
requestedReview;
|
|
87
|
+
acknowledgedReview;
|
|
88
|
+
constructor(requestedReview, acknowledgedReview) {
|
|
89
|
+
const detail = acknowledgedReview === void 0 ? "the response omitted its acknowledgement" : "the response acknowledgement did not match";
|
|
90
|
+
super(`Silmaril review compatibility error: ${detail} for requested ${requestedReview} review`);
|
|
91
|
+
this.name = "ReviewCompatibilityError";
|
|
92
|
+
this.requestedReview = requestedReview;
|
|
93
|
+
this.acknowledgedReview = acknowledgedReview;
|
|
94
|
+
Object.defineProperty(this, REVIEW_COMPATIBILITY_ERROR_BRAND, {
|
|
95
|
+
value: true,
|
|
96
|
+
enumerable: false,
|
|
97
|
+
configurable: false,
|
|
98
|
+
writable: false
|
|
99
|
+
});
|
|
100
|
+
Object.setPrototypeOf(this, _ReviewCompatibilityError.prototype);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
69
103
|
SilmarilApiError = class _SilmarilApiError extends Error {
|
|
70
104
|
status;
|
|
71
105
|
statusText;
|
|
@@ -174,6 +208,19 @@ var init_hooks = __esm({
|
|
|
174
208
|
}
|
|
175
209
|
});
|
|
176
210
|
|
|
211
|
+
// src/modes.ts
|
|
212
|
+
function validateMode(value) {
|
|
213
|
+
if (value === void 0 || value === "shadow" || value === "warn" || value === "block") {
|
|
214
|
+
return value;
|
|
215
|
+
}
|
|
216
|
+
throw new Error("Firewall: mode must be shadow, warn, or block");
|
|
217
|
+
}
|
|
218
|
+
var init_modes = __esm({
|
|
219
|
+
"src/modes.ts"() {
|
|
220
|
+
"use strict";
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
177
224
|
// src/utils/extract.ts
|
|
178
225
|
function extractTextFromPrompts(prompts) {
|
|
179
226
|
return prompts.map((p) => p.trim()).filter((p) => p.length > 0).join("\n");
|
|
@@ -257,7 +304,7 @@ async function createLangChainHandler(firewall, options = {}) {
|
|
|
257
304
|
const logger = options.logger ?? ((message, error) => {
|
|
258
305
|
console.warn(`silmaril.firewall: ${message}`, error);
|
|
259
306
|
});
|
|
260
|
-
const requestedMode = options.mode ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
|
|
307
|
+
const requestedMode = validateMode(options.mode) ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
|
|
261
308
|
const onClassify = options.onClassify;
|
|
262
309
|
const fireOnClassify = (event) => {
|
|
263
310
|
if (!onClassify) {
|
|
@@ -282,6 +329,9 @@ async function createLangChainHandler(firewall, options = {}) {
|
|
|
282
329
|
...toolName !== void 0 ? { toolName } : {}
|
|
283
330
|
});
|
|
284
331
|
} catch (err) {
|
|
332
|
+
if (isReviewCompatibilityError(err)) {
|
|
333
|
+
throw err;
|
|
334
|
+
}
|
|
285
335
|
if (!failOpen) {
|
|
286
336
|
throw err;
|
|
287
337
|
}
|
|
@@ -413,6 +463,7 @@ var init_langchain = __esm({
|
|
|
413
463
|
"use strict";
|
|
414
464
|
init_exceptions();
|
|
415
465
|
init_hooks();
|
|
466
|
+
init_modes();
|
|
416
467
|
init_extract();
|
|
417
468
|
USER_ROLES = /* @__PURE__ */ new Set(["human", "user"]);
|
|
418
469
|
}
|
|
@@ -424,6 +475,7 @@ import { randomUUID } from "crypto";
|
|
|
424
475
|
// src/adapters/vercel.ts
|
|
425
476
|
init_exceptions();
|
|
426
477
|
init_hooks();
|
|
478
|
+
init_modes();
|
|
427
479
|
function stringifyToolValue(value) {
|
|
428
480
|
if (value === null || value === void 0) {
|
|
429
481
|
return "";
|
|
@@ -499,7 +551,7 @@ function findLastUserMessage(messages) {
|
|
|
499
551
|
function createMiddleware(firewall, options = {}) {
|
|
500
552
|
const scanInput = options.scanInput ?? true;
|
|
501
553
|
const scanOutput = options.scanOutput ?? false;
|
|
502
|
-
const requestedMode = options.mode ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
|
|
554
|
+
const requestedMode = validateMode(options.mode) ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
|
|
503
555
|
const classifyOrBlock = async (text, hook, context = { toolName: void 0, toolCallId: void 0 }) => {
|
|
504
556
|
if (!text.trim()) {
|
|
505
557
|
return;
|
|
@@ -644,6 +696,7 @@ function createMiddleware(firewall, options = {}) {
|
|
|
644
696
|
|
|
645
697
|
// src/firewall.ts
|
|
646
698
|
init_exceptions();
|
|
699
|
+
init_modes();
|
|
647
700
|
|
|
648
701
|
// src/outcomes.ts
|
|
649
702
|
var Outcome = {
|
|
@@ -766,12 +819,32 @@ function sanitizeText(text) {
|
|
|
766
819
|
}
|
|
767
820
|
|
|
768
821
|
// src/firewall.ts
|
|
769
|
-
var SDK_VERSION = "0.7.
|
|
822
|
+
var SDK_VERSION = "0.7.9";
|
|
770
823
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
771
824
|
var DEFAULT_MAX_RETRIES = 5;
|
|
772
825
|
var MAX_BACKOFF_SECONDS = 30;
|
|
773
826
|
var MAX_ERROR_BODY_BYTES = 1 << 16;
|
|
774
827
|
var MAX_TIMEOUT_MS = 2147483647;
|
|
828
|
+
function validateReview(value, name) {
|
|
829
|
+
if (value === void 0) {
|
|
830
|
+
return void 0;
|
|
831
|
+
}
|
|
832
|
+
if (value !== "standard" && value !== "deep") {
|
|
833
|
+
throw new Error(`Firewall: ${name} must be standard or deep`);
|
|
834
|
+
}
|
|
835
|
+
return value;
|
|
836
|
+
}
|
|
837
|
+
function resolveReview(perCallReview, clientReview) {
|
|
838
|
+
return perCallReview === void 0 ? clientReview : validateReview(perCallReview, "review");
|
|
839
|
+
}
|
|
840
|
+
function verifyReviewAcknowledgement(acknowledgedReview, requestedReview) {
|
|
841
|
+
if (requestedReview !== void 0 && acknowledgedReview !== requestedReview) {
|
|
842
|
+
throw new ReviewCompatibilityError(requestedReview, acknowledgedReview);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function reviewAcknowledgementFromResponse(response) {
|
|
846
|
+
return isRecord2(response) ? response.review : void 0;
|
|
847
|
+
}
|
|
775
848
|
function resolveMode(value, requestedMode) {
|
|
776
849
|
let responseMode;
|
|
777
850
|
if (value === "shadow" || value === "warn" || value === "block") {
|
|
@@ -784,7 +857,7 @@ function resolveMode(value, requestedMode) {
|
|
|
784
857
|
function legacyMode(shadowMode) {
|
|
785
858
|
return shadowMode === void 0 ? void 0 : shadowMode ? "shadow" : "block";
|
|
786
859
|
}
|
|
787
|
-
function blockResultFromResponse(data, requestedMode) {
|
|
860
|
+
function blockResultFromResponse(data, requestedMode, requestedReview) {
|
|
788
861
|
if (data.prediction !== "BENIGN" && data.prediction !== "MALICIOUS") {
|
|
789
862
|
throw new Error("Firewall: response prediction must be BENIGN or MALICIOUS");
|
|
790
863
|
}
|
|
@@ -793,6 +866,9 @@ function blockResultFromResponse(data, requestedMode) {
|
|
|
793
866
|
score: Number(data.score),
|
|
794
867
|
threshold: Number(data.threshold)
|
|
795
868
|
};
|
|
869
|
+
if (requestedReview !== void 0) {
|
|
870
|
+
result.review = requestedReview;
|
|
871
|
+
}
|
|
796
872
|
const mode = resolveMode(data.mode, requestedMode);
|
|
797
873
|
if (mode !== void 0) {
|
|
798
874
|
result.mode = mode;
|
|
@@ -1067,6 +1143,7 @@ var Firewall = class {
|
|
|
1067
1143
|
timeoutMs;
|
|
1068
1144
|
shadowMode;
|
|
1069
1145
|
mode;
|
|
1146
|
+
review;
|
|
1070
1147
|
headers;
|
|
1071
1148
|
constructor(options) {
|
|
1072
1149
|
if (!options.apiKey) {
|
|
@@ -1086,7 +1163,8 @@ var Firewall = class {
|
|
|
1086
1163
|
`Firewall: timeoutMs must be at most ${MAX_TIMEOUT_MS} ms, got ${this.timeoutMs}`
|
|
1087
1164
|
);
|
|
1088
1165
|
}
|
|
1089
|
-
this.mode = options.mode ?? legacyMode(options.shadowMode);
|
|
1166
|
+
this.mode = validateMode(options.mode) ?? legacyMode(options.shadowMode);
|
|
1167
|
+
this.review = validateReview(options.review, "review");
|
|
1090
1168
|
this.shadowMode = this.mode === "shadow";
|
|
1091
1169
|
this.headers = Object.freeze({
|
|
1092
1170
|
"x-api-key": this.apiKey,
|
|
@@ -1125,10 +1203,14 @@ var Firewall = class {
|
|
|
1125
1203
|
const payload = {
|
|
1126
1204
|
texts: texts.map((text) => sanitizeText(text))
|
|
1127
1205
|
};
|
|
1128
|
-
const requestedMode = options.mode ?? this.mode;
|
|
1206
|
+
const requestedMode = validateMode(options.mode) ?? this.mode;
|
|
1207
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1129
1208
|
if (requestedMode !== void 0) {
|
|
1130
1209
|
payload.mode = requestedMode;
|
|
1131
1210
|
}
|
|
1211
|
+
if (requestedReview !== void 0) {
|
|
1212
|
+
payload.review = requestedReview;
|
|
1213
|
+
}
|
|
1132
1214
|
if (options.hooks && options.hooks.length > 0) {
|
|
1133
1215
|
payload.hooks = options.hooks.map((h) => String(h));
|
|
1134
1216
|
}
|
|
@@ -1148,6 +1230,7 @@ var Firewall = class {
|
|
|
1148
1230
|
);
|
|
1149
1231
|
}
|
|
1150
1232
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1233
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1151
1234
|
if (!Array.isArray(data.predictions)) {
|
|
1152
1235
|
throw new Error("Firewall: response predictions must be an array");
|
|
1153
1236
|
}
|
|
@@ -1156,7 +1239,9 @@ var Firewall = class {
|
|
|
1156
1239
|
`Firewall: response predictions length ${data.predictions.length} does not match submitted texts length ${payload.texts.length}`
|
|
1157
1240
|
);
|
|
1158
1241
|
}
|
|
1159
|
-
return data.predictions.map(
|
|
1242
|
+
return data.predictions.map(
|
|
1243
|
+
(p) => blockResultFromResponse(p, requestedMode, requestedReview)
|
|
1244
|
+
);
|
|
1160
1245
|
}
|
|
1161
1246
|
asLangChainHandler(options = {}) {
|
|
1162
1247
|
return Promise.resolve().then(() => (init_langchain(), langchain_exports)).then(
|
|
@@ -1205,10 +1290,14 @@ var Firewall = class {
|
|
|
1205
1290
|
}
|
|
1206
1291
|
async classifySingle(text, options, metadataInfo) {
|
|
1207
1292
|
const payload = { text };
|
|
1208
|
-
const requestedMode = options.mode ?? this.mode;
|
|
1293
|
+
const requestedMode = validateMode(options.mode) ?? this.mode;
|
|
1294
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1209
1295
|
if (requestedMode !== void 0) {
|
|
1210
1296
|
payload.mode = requestedMode;
|
|
1211
1297
|
}
|
|
1298
|
+
if (requestedReview !== void 0) {
|
|
1299
|
+
payload.review = requestedReview;
|
|
1300
|
+
}
|
|
1212
1301
|
if (options.hook !== void 0) {
|
|
1213
1302
|
payload.hook = options.hook;
|
|
1214
1303
|
}
|
|
@@ -1223,7 +1312,8 @@ var Firewall = class {
|
|
|
1223
1312
|
...options.governance === void 0 ? {} : { governance: options.governance }
|
|
1224
1313
|
});
|
|
1225
1314
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1226
|
-
|
|
1315
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1316
|
+
return blockResultFromResponse(data, requestedMode, requestedReview);
|
|
1227
1317
|
}
|
|
1228
1318
|
};
|
|
1229
1319
|
|
|
@@ -1246,6 +1336,7 @@ export {
|
|
|
1246
1336
|
Outcome,
|
|
1247
1337
|
PRIMARY_OUTCOMES,
|
|
1248
1338
|
PromptBlockedException,
|
|
1339
|
+
ReviewCompatibilityError,
|
|
1249
1340
|
SilmarilApiError,
|
|
1250
1341
|
isHarmfulOutcome,
|
|
1251
1342
|
isPrimaryOutcome,
|