@silmaril-security/sdk 0.5.0 → 0.6.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/index.js CHANGED
@@ -251,7 +251,7 @@ async function createLangChainHandler(firewall, options = {}) {
251
251
  const logger = options.logger ?? ((message, error) => {
252
252
  console.warn(`silmaril.firewall: ${message}`, error);
253
253
  });
254
- const shadowMode = options.shadowMode ?? firewall.shadowMode;
254
+ const requestedMode = options.mode ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
255
255
  const onClassify = options.onClassify;
256
256
  const fireOnClassify = (event) => {
257
257
  if (!onClassify) {
@@ -268,6 +268,7 @@ async function createLangChainHandler(firewall, options = {}) {
268
268
  try {
269
269
  result = await firewall.classify(text, {
270
270
  hook: hookLabel,
271
+ ...requestedMode !== void 0 ? { mode: requestedMode } : {},
271
272
  ...toolName !== void 0 ? { toolName } : {}
272
273
  });
273
274
  } catch (err) {
@@ -279,6 +280,7 @@ async function createLangChainHandler(firewall, options = {}) {
279
280
  }
280
281
  const threshold = result.threshold;
281
282
  const blocked = result.prediction === "MALICIOUS";
283
+ const effectiveMode = requestedMode ?? result.mode ?? "block";
282
284
  const commonEventFields = {
283
285
  hook: hookLabel,
284
286
  ...toolName !== void 0 ? { toolName } : {},
@@ -289,9 +291,10 @@ async function createLangChainHandler(firewall, options = {}) {
289
291
  fireOnClassify({
290
292
  ...commonEventFields,
291
293
  blocked,
292
- shadowMode
294
+ mode: effectiveMode,
295
+ shadowMode: effectiveMode === "shadow"
293
296
  });
294
- if (!blocked || shadowMode) {
297
+ if (!blocked || effectiveMode !== "block") {
295
298
  return;
296
299
  }
297
300
  throw new FirewallBlockedException({
@@ -486,7 +489,7 @@ function findLastUserMessage(messages) {
486
489
  function createMiddleware(firewall, options = {}) {
487
490
  const scanInput = options.scanInput ?? true;
488
491
  const scanOutput = options.scanOutput ?? false;
489
- const shadowMode = options.shadowMode ?? firewall.shadowMode;
492
+ const requestedMode = options.mode ?? (options.shadowMode === void 0 ? firewall.mode : options.shadowMode ? "shadow" : "block");
490
493
  const classifyOrBlock = async (text, hook, context = { toolName: void 0, toolCallId: void 0 }) => {
491
494
  if (!text.trim()) {
492
495
  return;
@@ -494,10 +497,15 @@ function createMiddleware(firewall, options = {}) {
494
497
  const { toolName, toolCallId } = context;
495
498
  const result = await firewall.classify(
496
499
  text,
497
- toolName !== void 0 ? { hook, toolName } : { hook }
500
+ {
501
+ hook,
502
+ ...toolName !== void 0 ? { toolName } : {},
503
+ ...requestedMode !== void 0 ? { mode: requestedMode } : {}
504
+ }
498
505
  );
499
506
  const threshold = result.threshold;
500
507
  const blocked = result.prediction === "MALICIOUS";
508
+ const effectiveMode = requestedMode ?? result.mode ?? "block";
501
509
  const commonEventFields = {
502
510
  hook,
503
511
  ...toolName !== void 0 ? { toolName } : {},
@@ -508,9 +516,10 @@ function createMiddleware(firewall, options = {}) {
508
516
  options.onClassify?.({
509
517
  ...commonEventFields,
510
518
  blocked,
511
- shadowMode
519
+ mode: effectiveMode,
520
+ shadowMode: effectiveMode === "shadow"
512
521
  });
513
- if (!blocked || shadowMode) {
522
+ if (!blocked || effectiveMode !== "block") {
514
523
  return;
515
524
  }
516
525
  const err = new FirewallBlockedException({
@@ -633,7 +642,13 @@ var Outcome = {
633
642
  SecretExposure: "secret_exposure",
634
643
  ControlAbuse: "control_abuse",
635
644
  SystemCompromise: "system_compromise",
636
- ServiceDisruption: "service_disruption"
645
+ ServiceDisruption: "service_disruption",
646
+ CodeGeneration: "code_generation",
647
+ StoryScriptGeneration: "story_script_generation",
648
+ GameGeneration: "game_generation",
649
+ WebsiteGeneration: "website_generation",
650
+ ClickUpTermsViolation: "clickup_terms_violation",
651
+ TraditionalAiAbuse: "traditional_ai_abuse"
637
652
  };
638
653
  var PRIMARY_OUTCOMES = [
639
654
  Outcome.Benign,
@@ -641,14 +656,26 @@ var PRIMARY_OUTCOMES = [
641
656
  Outcome.SecretExposure,
642
657
  Outcome.ControlAbuse,
643
658
  Outcome.SystemCompromise,
644
- Outcome.ServiceDisruption
659
+ Outcome.ServiceDisruption,
660
+ Outcome.CodeGeneration,
661
+ Outcome.StoryScriptGeneration,
662
+ Outcome.GameGeneration,
663
+ Outcome.WebsiteGeneration,
664
+ Outcome.ClickUpTermsViolation,
665
+ Outcome.TraditionalAiAbuse
645
666
  ];
646
667
  var HARMFUL_OUTCOMES = [
647
668
  Outcome.InformationDisclosure,
648
669
  Outcome.SecretExposure,
649
670
  Outcome.ControlAbuse,
650
671
  Outcome.SystemCompromise,
651
- Outcome.ServiceDisruption
672
+ Outcome.ServiceDisruption,
673
+ Outcome.CodeGeneration,
674
+ Outcome.StoryScriptGeneration,
675
+ Outcome.GameGeneration,
676
+ Outcome.WebsiteGeneration,
677
+ Outcome.ClickUpTermsViolation,
678
+ Outcome.TraditionalAiAbuse
652
679
  ];
653
680
  var OUTCOME_DESCRIPTIONS = {
654
681
  [Outcome.Benign]: "No harmful firewall outcome detected.",
@@ -656,7 +683,13 @@ var OUTCOME_DESCRIPTIONS = {
656
683
  [Outcome.SecretExposure]: "Exposes credentials, tokens, API keys, cookies, passwords, signing keys, OAuth secrets, session material, or webhook secrets.",
657
684
  [Outcome.ControlAbuse]: "Misuses authorized tools or user privileges to send, change, approve, delete, operate, or bypass policy/RBAC without a stronger outcome.",
658
685
  [Outcome.SystemCompromise]: "Enables privilege escalation, account takeover, hostile integration or plugin takeover, persistence, lateral movement, attacker webhook registration, or code/plugin execution.",
659
- [Outcome.ServiceDisruption]: "Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence."
686
+ [Outcome.ServiceDisruption]: "Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence.",
687
+ [Outcome.CodeGeneration]: "Requests generation or material modification of executable code, scripts, workflows, or configuration.",
688
+ [Outcome.StoryScriptGeneration]: "Requests generation of narrative prose, dialogue, scripts, or story artifacts.",
689
+ [Outcome.GameGeneration]: "Requests generation of a game, quest, level, mechanic, or playable experience.",
690
+ [Outcome.WebsiteGeneration]: "Requests generation of a website, landing page, storefront, or web experience.",
691
+ [Outcome.ClickUpTermsViolation]: "Requests content or actions that violate the configured ClickUp tenant policy.",
692
+ [Outcome.TraditionalAiAbuse]: "Requests unsafe AI assistance outside the concrete security outcome classes."
660
693
  };
661
694
  var PRIMARY_OUTCOME_SET = new Set(PRIMARY_OUTCOMES);
662
695
  var HARMFUL_OUTCOME_SET = new Set(HARMFUL_OUTCOMES);
@@ -723,12 +756,24 @@ function sanitizeText(text) {
723
756
  }
724
757
 
725
758
  // src/firewall.ts
726
- var SDK_VERSION = "0.5.0";
759
+ var SDK_VERSION = "0.6.0";
727
760
  var DEFAULT_TIMEOUT_MS = 1e4;
728
761
  var DEFAULT_MAX_RETRIES = 5;
729
762
  var MAX_BACKOFF_SECONDS = 30;
730
763
  var MAX_ERROR_BODY_BYTES = 1 << 16;
731
- function blockResultFromResponse(data) {
764
+ function resolveMode(value, requestedMode) {
765
+ let responseMode;
766
+ if (value === "shadow" || value === "warn" || value === "block") {
767
+ responseMode = value;
768
+ } else if (value !== void 0) {
769
+ throw new Error("Firewall: response mode must be shadow, warn, or block");
770
+ }
771
+ return requestedMode ?? responseMode;
772
+ }
773
+ function legacyMode(shadowMode) {
774
+ return shadowMode === void 0 ? void 0 : shadowMode ? "shadow" : "block";
775
+ }
776
+ function blockResultFromResponse(data, requestedMode) {
732
777
  if (data.prediction !== "BENIGN" && data.prediction !== "MALICIOUS") {
733
778
  throw new Error("Firewall: response prediction must be BENIGN or MALICIOUS");
734
779
  }
@@ -737,6 +782,10 @@ function blockResultFromResponse(data) {
737
782
  score: Number(data.score),
738
783
  threshold: Number(data.threshold)
739
784
  };
785
+ const mode = resolveMode(data.mode, requestedMode);
786
+ if (mode !== void 0) {
787
+ result.mode = mode;
788
+ }
740
789
  if (data.primary_outcome !== void 0) {
741
790
  result.primaryOutcome = normalizePrimaryOutcome(data.primary_outcome);
742
791
  }
@@ -820,6 +869,7 @@ var Firewall = class {
820
869
  apiUrl;
821
870
  timeoutMs;
822
871
  shadowMode;
872
+ mode;
823
873
  headers;
824
874
  constructor(options) {
825
875
  if (!options.apiKey) {
@@ -834,7 +884,8 @@ var Firewall = class {
834
884
  if (typeof this.timeoutMs !== "number" || !Number.isFinite(this.timeoutMs) || this.timeoutMs < 0) {
835
885
  throw new Error(`Firewall: timeoutMs must be a finite non-negative number, got ${this.timeoutMs}`);
836
886
  }
837
- this.shadowMode = options.shadowMode ?? false;
887
+ this.mode = options.mode ?? legacyMode(options.shadowMode);
888
+ this.shadowMode = this.mode === "shadow";
838
889
  this.headers = Object.freeze({
839
890
  "x-api-key": this.apiKey,
840
891
  "content-type": "application/json"
@@ -867,6 +918,10 @@ var Firewall = class {
867
918
  const payload = {
868
919
  texts: texts.map((text) => sanitizeText(text))
869
920
  };
921
+ const requestedMode = options.mode ?? this.mode;
922
+ if (requestedMode !== void 0) {
923
+ payload.mode = requestedMode;
924
+ }
870
925
  if (options.hooks && options.hooks.length > 0) {
871
926
  payload.hooks = options.hooks.map((h) => String(h));
872
927
  }
@@ -880,7 +935,7 @@ var Firewall = class {
880
935
  })
881
936
  );
882
937
  const data = await this.postWithRetry(payload);
883
- return data.predictions.map((p) => blockResultFromResponse(p));
938
+ return data.predictions.map((p) => blockResultFromResponse(p, requestedMode));
884
939
  }
885
940
  asLangChainHandler(options = {}) {
886
941
  return Promise.resolve().then(() => (init_langchain(), langchain_exports)).then(
@@ -917,6 +972,10 @@ var Firewall = class {
917
972
  }
918
973
  async classifySingle(text, options, metadataInfo) {
919
974
  const payload = { text };
975
+ const requestedMode = options.mode ?? this.mode;
976
+ if (requestedMode !== void 0) {
977
+ payload.mode = requestedMode;
978
+ }
920
979
  if (options.hook !== void 0) {
921
980
  payload.hook = options.hook;
922
981
  }
@@ -925,7 +984,7 @@ var Firewall = class {
925
984
  }
926
985
  payload.metadata = withSdkMetadata(options.metadata, metadataInfo);
927
986
  const data = await this.postWithRetry(payload);
928
- return blockResultFromResponse(data);
987
+ return blockResultFromResponse(data, requestedMode);
929
988
  }
930
989
  };
931
990
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/exceptions.ts","../src/hooks.ts","../src/utils/extract.ts","../src/adapters/langchain.ts","../src/firewall.ts","../src/adapters/vercel.ts","../src/outcomes.ts","../src/sanitization.ts","../src/index.ts"],"sourcesContent":["// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { HookLabel } from \"./hooks.js\";\nimport type { BlockResult } from \"./types.js\";\n\nconst MAX_PROMPT_DISPLAY_LEN = 100;\n\nexport interface MalformedInputDetails {\n field?: string;\n inputIndex?: number;\n charOffset?: number;\n malformedToken?: string;\n codePoint?: string;\n reason?: string;\n}\n\nexport class FirewallBlockedException extends Error {\n readonly score: number;\n readonly threshold: number;\n readonly promptText: string;\n readonly runId: string | undefined;\n readonly hook: HookLabel | undefined;\n readonly toolName: string | undefined;\n readonly toolCallId: string | undefined;\n readonly result: BlockResult | undefined;\n\n constructor(params: {\n score: number;\n threshold: number;\n promptText: string;\n runId?: string;\n hook?: HookLabel;\n toolName?: string;\n toolCallId?: string;\n result?: BlockResult;\n }) {\n super(FirewallBlockedException.formatMessage(params));\n this.name = \"FirewallBlockedException\";\n this.score = params.score;\n this.threshold = params.threshold;\n this.promptText = params.promptText;\n this.runId = params.runId;\n this.hook = params.hook;\n this.toolName = params.toolName;\n this.toolCallId = params.toolCallId;\n this.result = params.result;\n Object.setPrototypeOf(this, FirewallBlockedException.prototype);\n }\n\n private static formatMessage(params: {\n score: number;\n threshold: number;\n promptText: string;\n }): string {\n const truncated =\n params.promptText.length > MAX_PROMPT_DISPLAY_LEN\n ? `${params.promptText.slice(0, MAX_PROMPT_DISPLAY_LEN)}...`\n : params.promptText;\n return (\n `Request blocked by Silmaril Firewall ` +\n `(score=${params.score.toFixed(4)}, threshold=${params.threshold.toFixed(4)}): ` +\n `'${truncated}'`\n );\n }\n}\n\n/** @deprecated Use FirewallBlockedException instead. */\nexport const PromptBlockedException = FirewallBlockedException;\n/** @deprecated Use FirewallBlockedException instead. */\nexport type PromptBlockedException = FirewallBlockedException;\n\nexport class SilmarilApiError extends Error {\n readonly status: number;\n readonly statusText: string;\n readonly body: string;\n readonly details: MalformedInputDetails | undefined;\n readonly error: string | undefined;\n readonly apiMessage: string | undefined;\n\n constructor(params: {\n status: number;\n statusText: string;\n body: string;\n details?: MalformedInputDetails;\n error?: string;\n apiMessage?: string;\n }) {\n const statusText = params.statusText ? ` ${params.statusText}` : \"\";\n super(`Silmaril API error ${params.status}${statusText}`);\n this.name = \"SilmarilApiError\";\n this.status = params.status;\n this.statusText = params.statusText;\n this.body = params.body;\n const parsed = parseErrorBody(params.body);\n this.details = params.details ?? parsed.details;\n this.error = params.error ?? parsed.error;\n this.apiMessage = params.apiMessage ?? parsed.apiMessage;\n Object.setPrototypeOf(this, SilmarilApiError.prototype);\n }\n}\n\nfunction parseErrorBody(body: string): {\n details: MalformedInputDetails | undefined;\n error: string | undefined;\n apiMessage: string | undefined;\n} {\n try {\n const parsed = JSON.parse(body) as unknown;\n if (!parsed || typeof parsed !== \"object\") {\n return { details: undefined, error: undefined, apiMessage: undefined };\n }\n const data = parsed as Record<string, unknown>;\n return {\n details:\n data.details && typeof data.details === \"object\"\n ? (data.details as MalformedInputDetails)\n : undefined,\n error: typeof data.error === \"string\" ? data.error : undefined,\n apiMessage: typeof data.message === \"string\" ? data.message : undefined,\n };\n } catch {\n return { details: undefined, error: undefined, apiMessage: undefined };\n }\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport const HookLabel = {\n USER_INPUT: \"user_input\",\n SYSTEM_PROMPT: \"system_prompt\",\n TOOL_CALL: \"tool_call\",\n TOOL_RESPONSE: \"tool_response\",\n LLM_OUTPUT: \"llm_output\",\n UNKNOWN: \"unknown\",\n} as const;\n\nexport type HookLabel = (typeof HookLabel)[keyof typeof HookLabel];\n\nexport const FirewallHook = {\n LLM_START: \"on_llm_start\",\n CHAT_MODEL_START: \"on_chat_model_start\",\n TOOL_START: \"on_tool_start\",\n RETRIEVER_START: \"on_retriever_start\",\n LLM_END: \"on_llm_end\",\n TOOL_END: \"on_tool_end\",\n RETRIEVER_END: \"on_retriever_end\",\n} as const;\n\nexport type FirewallHook = (typeof FirewallHook)[keyof typeof FirewallHook];\n\nexport const DEFAULT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n]);\n\nexport const INPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n FirewallHook.TOOL_START,\n FirewallHook.RETRIEVER_START,\n]);\n\nexport const OUTPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_END,\n FirewallHook.TOOL_END,\n FirewallHook.RETRIEVER_END,\n]);\n\nexport const ALL_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n ...INPUT_HOOKS,\n ...OUTPUT_HOOKS,\n]);\n\nexport const FIREWALL_HOOK_TO_LABEL: Readonly<Record<FirewallHook, HookLabel>> = {\n [FirewallHook.CHAT_MODEL_START]: HookLabel.USER_INPUT,\n [FirewallHook.LLM_START]: HookLabel.USER_INPUT,\n [FirewallHook.TOOL_START]: HookLabel.TOOL_CALL,\n [FirewallHook.TOOL_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.RETRIEVER_START]: HookLabel.TOOL_CALL,\n [FirewallHook.RETRIEVER_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.LLM_END]: HookLabel.LLM_OUTPUT,\n};\n\nconst FIREWALL_HOOK_VALUES: ReadonlySet<string> = new Set(Object.values(FirewallHook));\n\nexport function resolveHooks(\n hooks: Iterable<FirewallHook | string> | undefined,\n): ReadonlySet<FirewallHook> {\n if (hooks === undefined) {\n return DEFAULT_HOOKS;\n }\n const resolved = new Set<FirewallHook>();\n for (const h of hooks) {\n if (!FIREWALL_HOOK_VALUES.has(h)) {\n throw new Error(`Invalid FirewallHook value: ${String(h)}`);\n }\n resolved.add(h as FirewallHook);\n }\n return resolved;\n}\n\nexport function prependHook(text: string, hook: HookLabel | string | undefined | null): string {\n if (hook === undefined || hook === null) {\n return text;\n }\n if (hook === HookLabel.UNKNOWN) {\n return text;\n }\n return `[HOOK:${hook}] ${text}`;\n}\n\nexport function prependToolName(text: string, toolName: string | undefined | null): string {\n if (toolName === undefined || toolName === null) {\n return text;\n }\n return `[TOOL:${toolName}] ${text}`;\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nconst SKIP_ROLES: ReadonlySet<string> = new Set([\"ai\", \"assistant\"]);\nconst SYSTEM_ROLES: ReadonlySet<string> = new Set([\"system\"]);\nconst TOOL_ROLES: ReadonlySet<string> = new Set([\"tool\", \"function\"]);\n\ntype MessageContent = string | ReadonlyArray<string | { type?: string; text?: string }>;\n\ninterface DucktypedMessage {\n role?: string;\n type?: string;\n content?: MessageContent;\n}\n\ninterface DucktypedGeneration {\n text?: string;\n}\n\ninterface DucktypedLLMResult {\n generations?: ReadonlyArray<ReadonlyArray<DucktypedGeneration>>;\n}\n\ninterface DucktypedDocument {\n pageContent?: string;\n}\n\nfunction extractContentText(content: MessageContent | undefined): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && typeof block === \"object\" && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n }\n return \"\";\n}\n\nfunction getRole(message: DucktypedMessage): string {\n if (message.role !== undefined) {\n return message.role.toLowerCase();\n }\n if (typeof message.type === \"string\") {\n return message.type.toLowerCase();\n }\n return \"\";\n}\n\nexport function extractTextFromMessages(\n messages: ReadonlyArray<DucktypedMessage>,\n options: { includeSystem?: boolean; includeTool?: boolean } = {},\n): string {\n const includeSystem = options.includeSystem ?? true;\n const includeTool = options.includeTool ?? true;\n const parts: string[] = [];\n for (const message of messages) {\n const role = getRole(message);\n if (SKIP_ROLES.has(role)) {\n continue;\n }\n if (!includeSystem && SYSTEM_ROLES.has(role)) {\n continue;\n }\n if (!includeTool && TOOL_ROLES.has(role)) {\n continue;\n }\n const text = extractContentText(message.content);\n const stripped = text.trim();\n if (stripped) {\n parts.push(stripped);\n }\n }\n return parts.join(\"\\n\");\n}\n\nexport function extractTextFromPrompts(prompts: readonly string[]): string {\n return prompts\n .map((p) => p.trim())\n .filter((p) => p.length > 0)\n .join(\"\\n\");\n}\n\nexport function extractTextFromToolInput(inputStr: string): string {\n return inputStr.trim();\n}\n\nexport function extractTextFromLLMResult(response: DucktypedLLMResult): string {\n const parts: string[] = [];\n for (const genList of response.generations ?? []) {\n for (const gen of genList) {\n const text = (gen.text ?? \"\").trim();\n if (text) {\n parts.push(text);\n }\n }\n }\n return parts.join(\"\\n\");\n}\n\nexport function extractTextFromDocuments(documents: ReadonlyArray<DucktypedDocument>): string {\n const parts: string[] = [];\n for (const doc of documents) {\n const text = (doc.pageContent ?? \"\").trim();\n if (text) {\n parts.push(text);\n }\n }\n return parts.join(\"\\n\");\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { BaseCallbackHandler } from \"@langchain/core/callbacks/base\";\n\nimport type { Firewall } from \"../firewall.js\";\nimport { FirewallBlockedException } from \"../exceptions.js\";\nimport {\n FIREWALL_HOOK_TO_LABEL,\n FirewallHook,\n HookLabel,\n resolveHooks,\n} from \"../hooks.js\";\nimport type { BlockResult, ClassifyEvent, LangChainAdapterOptions } from \"../types.js\";\nimport {\n extractTextFromDocuments,\n extractTextFromLLMResult,\n extractTextFromPrompts,\n extractTextFromToolInput,\n} from \"../utils/extract.js\";\n\nconst USER_ROLES: ReadonlySet<string> = new Set([\"human\", \"user\"]);\n\ninterface LangChainDucktypedMessage {\n role?: string;\n type?: string;\n content?: string | ReadonlyArray<string | { type?: string; text?: string }>;\n}\n\nfunction getMessageRole(message: LangChainDucktypedMessage): string {\n if (typeof message.role === \"string\") {\n return message.role.toLowerCase();\n }\n if (typeof message.type === \"string\") {\n return message.type.toLowerCase();\n }\n return \"\";\n}\n\nfunction extractMessageText(content: LangChainDucktypedMessage[\"content\"]): string {\n if (content === undefined) {\n return \"\";\n }\n if (typeof content === \"string\") {\n return content;\n }\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n}\n\nfunction findLastUserMessage(\n messages: ReadonlyArray<LangChainDucktypedMessage>,\n): LangChainDucktypedMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (USER_ROLES.has(getMessageRole(msg))) {\n return msg;\n }\n }\n return undefined;\n}\n\nexport async function createLangChainHandler(\n firewall: Firewall,\n options: LangChainAdapterOptions = {},\n): Promise<BaseCallbackHandler> {\n const { BaseCallbackHandler } = await import(\"@langchain/core/callbacks/base\");\n\n const enabledHooks = resolveHooks(options.hooks);\n // includeSystem / includeTool are retained in LangChainAdapterOptions for\n // backwards compat but are inert under the per-message hook-routing algorithm:\n // handleChatModelStart only scans the last user-role message; system and tool\n // messages are either trusted or already classified by their own hooks.\n const failOpen = options.failOpen ?? true;\n const logger =\n options.logger ??\n ((message: string, error: unknown): void => {\n // eslint-disable-next-line no-console\n console.warn(`silmaril.firewall: ${message}`, error);\n });\n const shadowMode = options.shadowMode ?? firewall.shadowMode;\n const onClassify = options.onClassify;\n\n const fireOnClassify = (event: ClassifyEvent): void => {\n if (!onClassify) {\n return;\n }\n try {\n onClassify(event);\n } catch (err) {\n logger(\"onClassify callback threw\", err);\n }\n };\n\n const classify = async (\n text: string,\n hookLabel: HookLabel,\n runId: string,\n toolName?: string,\n ): Promise<void> => {\n let result: BlockResult;\n try {\n result = await firewall.classify(text, {\n hook: hookLabel,\n ...(toolName !== undefined ? { toolName } : {}),\n });\n } catch (err) {\n if (!failOpen) {\n throw err;\n }\n logger(\"classification failed, allowing prompt through\", err);\n return;\n }\n const threshold = result.threshold;\n const blocked = result.prediction === \"MALICIOUS\";\n const commonEventFields = {\n hook: hookLabel,\n ...(toolName !== undefined ? { toolName } : {}),\n runId,\n text,\n result,\n };\n fireOnClassify({\n ...commonEventFields,\n blocked,\n shadowMode,\n });\n if (!blocked || shadowMode) {\n return;\n }\n\n throw new FirewallBlockedException({\n score: result.score,\n threshold,\n promptText: text,\n runId,\n hook: hookLabel,\n ...(toolName !== undefined ? { toolName } : {}),\n result,\n });\n };\n\n class SilmarilFirewallHandler extends BaseCallbackHandler {\n override name = \"silmaril_firewall_handler\";\n override raiseError = true;\n override awaitHandlers = true;\n\n override async handleChatModelStart(\n _llm: unknown,\n messages: unknown,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.CHAT_MODEL_START)) {\n return;\n }\n const batches = messages as ReadonlyArray<ReadonlyArray<LangChainDucktypedMessage>>;\n const flat: LangChainDucktypedMessage[] = [];\n for (const batch of batches) {\n for (const m of batch) {\n flat.push(m);\n }\n }\n const lastUser = findLastUserMessage(flat);\n if (!lastUser) {\n return;\n }\n const text = extractMessageText(lastUser.content).trim();\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.CHAT_MODEL_START], runId);\n }\n\n override async handleLLMStart(\n _llm: unknown,\n prompts: string[],\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.LLM_START)) {\n return;\n }\n const text = extractTextFromPrompts(prompts);\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_START], runId);\n }\n\n override async handleToolStart(\n tool: { name?: string } | undefined,\n inputStr: string,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.TOOL_START)) {\n return;\n }\n const text = extractTextFromToolInput(inputStr);\n if (!text) {\n return;\n }\n const toolName = tool?.name;\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_START], runId, toolName);\n }\n\n override async handleRetrieverStart(\n _retriever: unknown,\n query: string,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.RETRIEVER_START)) {\n return;\n }\n const text = query.trim();\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_START], runId);\n }\n\n override async handleLLMEnd(output: unknown, runId: string): Promise<void> {\n if (!enabledHooks.has(FirewallHook.LLM_END)) {\n return;\n }\n const text = extractTextFromLLMResult(output as { generations?: ReadonlyArray<ReadonlyArray<{ text?: string }>> });\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_END], runId);\n }\n\n override async handleToolEnd(\n output: unknown,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _kwargs?: { name?: string },\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.TOOL_END)) {\n return;\n }\n const text = String(output).trim();\n if (!text) {\n return;\n }\n const toolName = _kwargs?.name;\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_END], runId, toolName);\n }\n\n override async handleRetrieverEnd(\n documents: ReadonlyArray<{ pageContent?: string }>,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.RETRIEVER_END)) {\n return;\n }\n const text = extractTextFromDocuments(documents);\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_END], runId);\n }\n }\n\n return new SilmarilFirewallHandler();\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { createMiddleware, type FirewallMiddleware } from \"./adapters/vercel.js\";\nimport { SilmarilApiError } from \"./exceptions.js\";\nimport { normalizeHarmfulOutcomeMap, normalizePrimaryOutcome } from \"./outcomes.js\";\nimport { sanitizeText } from \"./sanitization.js\";\nimport type {\n BlockResult,\n ClassifyBatchOptions,\n ClassifyOptions,\n ClassificationMetadata,\n FirewallOptions,\n LangChainAdapterOptions,\n LangChainFirewallHandler,\n MiddlewareOptions,\n Prediction,\n} from \"./types.js\";\n\nexport const SDK_VERSION = \"0.5.0\";\nexport const DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_RETRIES = 5;\nconst MAX_BACKOFF_SECONDS = 30;\nconst MAX_ERROR_BODY_BYTES = 1 << 16;\n\ninterface SingleClassifyPayload {\n text: string;\n hook?: string;\n tool_name?: string;\n metadata?: ClassificationMetadata;\n}\n\ninterface BatchClassifyPayload {\n texts: readonly string[];\n hooks?: readonly string[];\n tool_names?: readonly (string | null)[];\n metadata?: readonly (ClassificationMetadata | null)[];\n}\n\ninterface SingleClassifyResponse {\n prediction: Prediction;\n score: number;\n threshold: number;\n primary_outcome?: unknown;\n outcome_scores?: unknown;\n detector_scores?: unknown;\n detector_counts?: unknown;\n}\n\ninterface BatchClassifyResponse {\n predictions: readonly SingleClassifyResponse[];\n}\n\nfunction blockResultFromResponse(data: SingleClassifyResponse): BlockResult {\n if (data.prediction !== \"BENIGN\" && data.prediction !== \"MALICIOUS\") {\n throw new Error(\"Firewall: response prediction must be BENIGN or MALICIOUS\");\n }\n const result: {\n prediction: Prediction;\n score: number;\n threshold: number;\n primaryOutcome?: NonNullable<BlockResult[\"primaryOutcome\"]>;\n outcomeScores?: NonNullable<BlockResult[\"outcomeScores\"]>;\n detectorScores?: NonNullable<BlockResult[\"detectorScores\"]>;\n detectorCounts?: NonNullable<BlockResult[\"detectorCounts\"]>;\n } = {\n prediction: data.prediction,\n score: Number(data.score),\n threshold: Number(data.threshold),\n };\n if (data.primary_outcome !== undefined) {\n result.primaryOutcome = normalizePrimaryOutcome(data.primary_outcome);\n }\n if (data.outcome_scores !== undefined) {\n const outcomeScores = normalizeHarmfulOutcomeMap(data.outcome_scores, \"outcome_scores\");\n if (outcomeScores !== undefined) {\n result.outcomeScores = outcomeScores;\n }\n }\n if (data.detector_scores !== undefined) {\n const detectorScores = normalizeHarmfulOutcomeMap(data.detector_scores, \"detector_scores\");\n if (detectorScores !== undefined) {\n result.detectorScores = detectorScores;\n }\n }\n if (data.detector_counts !== undefined) {\n const detectorCounts = normalizeHarmfulOutcomeMap(data.detector_counts, \"detector_counts\");\n if (detectorCounts !== undefined) {\n result.detectorCounts = detectorCounts;\n }\n }\n return Object.freeze(result);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction withSdkMetadata(\n metadata: ClassificationMetadata | undefined,\n info: {\n requestId: string;\n inputIndex?: number;\n },\n): ClassificationMetadata {\n const payload: Record<string, unknown> = { ...(metadata ?? {}) };\n const existing = payload.silmaril;\n if (existing !== undefined && !isRecord(existing)) {\n throw new Error(\"Firewall: metadata.silmaril must be an object when provided\");\n }\n payload.silmaril = {\n ...(isRecord(existing) ? existing : {}),\n sdk_language: \"typescript\",\n sdk_version: SDK_VERSION,\n request_id: info.requestId,\n ...(info.inputIndex === undefined ? {} : { input_index: info.inputIndex }),\n };\n return payload;\n}\n\nasync function readCappedErrorBody(response: Response): Promise<string> {\n if (!response.body) {\n return response.text().then((body) => body.slice(0, MAX_ERROR_BODY_BYTES)).catch(() => \"\");\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let remaining = MAX_ERROR_BODY_BYTES;\n try {\n while (remaining > 0) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (!value) {\n continue;\n }\n const chunk = value.byteLength > remaining ? value.slice(0, remaining) : value;\n chunks.push(chunk);\n remaining -= chunk.byteLength;\n if (chunk.byteLength < value.byteLength) {\n break;\n }\n }\n } catch {\n return \"\";\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n\n const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nexport class Firewall {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly timeoutMs: number;\n readonly shadowMode: boolean;\n\n private readonly headers: Readonly<Record<string, string>>;\n\n constructor(options: FirewallOptions) {\n if (!options.apiKey) {\n throw new Error(\"Firewall: apiKey is required\");\n }\n if (!options.apiUrl) {\n throw new Error(\"Firewall: apiUrl is required\");\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (typeof this.timeoutMs !== \"number\" || !Number.isFinite(this.timeoutMs) || this.timeoutMs < 0) {\n throw new Error(`Firewall: timeoutMs must be a finite non-negative number, got ${this.timeoutMs}`);\n }\n this.shadowMode = options.shadowMode ?? false;\n this.headers = Object.freeze({\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\",\n });\n }\n\n async classify(text: string, options: ClassifyOptions = {}): Promise<BlockResult> {\n const requestId = options.requestId ?? randomUUID();\n return this.classifySingle(sanitizeText(text), options, { requestId });\n }\n\n async classifyBatch(\n texts: readonly string[],\n options: ClassifyBatchOptions = {},\n ): Promise<BlockResult[]> {\n if (texts.length === 0) {\n throw new Error(\"Firewall: texts must not be empty\");\n }\n if (options.hooks !== undefined && options.hooks.length !== texts.length) {\n throw new Error(\n `Firewall: hooks length ${options.hooks.length} does not match texts length ${texts.length}`,\n );\n }\n if (options.toolNames !== undefined && options.toolNames.length !== texts.length) {\n throw new Error(\n `Firewall: toolNames length ${options.toolNames.length} does not match texts length ${texts.length}`,\n );\n }\n if (options.metadata !== undefined && options.metadata.length !== texts.length) {\n throw new Error(\n `Firewall: metadata length ${options.metadata.length} does not match texts length ${texts.length}`,\n );\n }\n\n const requestId = options.requestId ?? randomUUID();\n const payload: BatchClassifyPayload = {\n texts: texts.map((text) => sanitizeText(text)),\n };\n if (options.hooks && options.hooks.length > 0) {\n payload.hooks = options.hooks.map((h) => String(h));\n }\n if (options.toolNames && options.toolNames.length > 0) {\n payload.tool_names = options.toolNames.map((t) => (t === undefined ? null : t));\n }\n payload.metadata = texts.map((_, index) =>\n withSdkMetadata(options.metadata?.[index], {\n requestId,\n inputIndex: index,\n }),\n );\n const data = await this.postWithRetry<BatchClassifyResponse>(payload);\n return data.predictions.map((p) => blockResultFromResponse(p));\n }\n\n asLangChainHandler<THandler = LangChainFirewallHandler>(\n options: LangChainAdapterOptions = {},\n ): Promise<THandler> {\n return import(\"./adapters/langchain.js\").then((m) =>\n m.createLangChainHandler(this, options) as Promise<THandler>,\n );\n }\n\n asMiddleware(options: MiddlewareOptions = {}): FirewallMiddleware {\n return createMiddleware(this, options);\n }\n\n private async postWithRetry<T>(\n payload: SingleClassifyPayload | BatchClassifyPayload,\n maxRetries: number = DEFAULT_MAX_RETRIES,\n ): Promise<T> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify(payload),\n redirect: \"error\",\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n if (response.status !== 429 || attempt === maxRetries) {\n if (!response.ok) {\n const body = await readCappedErrorBody(response);\n throw new SilmarilApiError({\n status: response.status,\n statusText: response.statusText,\n body,\n });\n }\n return (await response.json()) as T;\n }\n const waitSeconds = Math.min(2 ** attempt, MAX_BACKOFF_SECONDS);\n await new Promise<void>((resolve) => setTimeout(resolve, waitSeconds * 1000));\n }\n throw new Error(\"Firewall: exhausted retries (unreachable)\");\n }\n\n private async classifySingle(\n text: string,\n options: ClassifyOptions,\n metadataInfo: {\n requestId: string;\n },\n ): Promise<BlockResult> {\n const payload: SingleClassifyPayload = { text };\n if (options.hook !== undefined) {\n payload.hook = options.hook;\n }\n if (options.toolName !== undefined) {\n payload.tool_name = options.toolName;\n }\n payload.metadata = withSdkMetadata(options.metadata, metadataInfo);\n const data = await this.postWithRetry<SingleClassifyResponse>(payload);\n return blockResultFromResponse(data);\n }\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { Firewall } from \"../firewall.js\";\nimport { FirewallBlockedException } from \"../exceptions.js\";\nimport { HookLabel } from \"../hooks.js\";\nimport type { BlockResult, MiddlewareOptions } from \"../types.js\";\n\ninterface VercelContentPart {\n type?: string;\n text?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n output?: unknown;\n result?: unknown;\n}\n\ninterface VercelPromptMessage {\n role: string;\n content: string | ReadonlyArray<VercelContentPart | string>;\n}\n\ninterface VercelToolCall {\n toolCallType?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n input?: unknown;\n}\n\ninterface VercelGenerateResult {\n text?: string;\n toolCalls?: ReadonlyArray<VercelToolCall>;\n}\n\ninterface WrapGenerateArgs<TResult extends VercelGenerateResult & Record<string, unknown>> {\n params: { prompt?: ReadonlyArray<VercelPromptMessage> } & Record<string, unknown>;\n doGenerate: () => PromiseLike<TResult>;\n}\n\ninterface WrapStreamArgs<\n TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>,\n> {\n params: { prompt?: ReadonlyArray<VercelPromptMessage> } & Record<string, unknown>;\n doStream: () => PromiseLike<TResult>;\n}\n\ninterface StreamPart {\n type?: string;\n textDelta?: string;\n delta?: string;\n}\n\ninterface VercelStepContext {\n toolName: string | undefined;\n toolCallId: string | undefined;\n}\n\nfunction stringifyToolValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction extractContentText(content: VercelPromptMessage[\"content\"]): string {\n if (typeof content === \"string\") {\n return content;\n }\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n}\n\nfunction iterateToolResultParts(\n message: VercelPromptMessage,\n): Array<{ text: string; toolName: string | undefined; toolCallId: string | undefined }> {\n if (typeof message.content === \"string\") {\n return [];\n }\n const out: Array<{ text: string; toolName: string | undefined; toolCallId: string | undefined }> = [];\n for (const part of message.content) {\n if (typeof part === \"string\") {\n continue;\n }\n if (part.type === \"tool-result\") {\n const text = stringifyToolResult(part.result !== undefined ? part.result : part.output);\n if (text.trim()) {\n out.push({ text, toolName: part.toolName, toolCallId: part.toolCallId });\n }\n }\n }\n return out;\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (!isRecord(value)) {\n return stringifyToolValue(value);\n }\n if ((value.type === \"text\" || value.type === \"error-text\") && typeof value.value === \"string\") {\n return value.value;\n }\n if ((value.type === \"json\" || value.type === \"error-json\") && value.value !== undefined) {\n return stringifyToolValue(value.value);\n }\n if (value.type === \"content\" && Array.isArray(value.value)) {\n return value.value\n .map((part) => (isRecord(part) && part.type === \"text\" && typeof part.text === \"string\" ? part.text : \"\"))\n .filter((text) => text.length > 0)\n .join(\" \");\n }\n return stringifyToolValue(value);\n}\n\nfunction findLastUserMessage(\n messages: ReadonlyArray<VercelPromptMessage>,\n): VercelPromptMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role.toLowerCase() === \"user\") {\n return msg;\n }\n }\n return undefined;\n}\n\nexport interface FirewallMiddleware {\n readonly specificationVersion: \"v3\";\n readonly middlewareVersion: \"v2\";\n wrapGenerate: <TResult extends VercelGenerateResult & Record<string, unknown>>(\n args: WrapGenerateArgs<TResult>,\n ) => Promise<TResult>;\n wrapStream: <TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>>(\n args: WrapStreamArgs<TResult>,\n ) => Promise<TResult>;\n}\n\nexport function createMiddleware(\n firewall: Firewall,\n options: MiddlewareOptions = {},\n): FirewallMiddleware {\n const scanInput = options.scanInput ?? true;\n const scanOutput = options.scanOutput ?? false;\n const shadowMode = options.shadowMode ?? firewall.shadowMode;\n\n const classifyOrBlock = async (\n text: string,\n hook: HookLabel,\n context: VercelStepContext = { toolName: undefined, toolCallId: undefined },\n ): Promise<void> => {\n if (!text.trim()) {\n return;\n }\n const { toolName, toolCallId } = context;\n const result: BlockResult = await firewall.classify(\n text,\n toolName !== undefined ? { hook, toolName } : { hook },\n );\n const threshold = result.threshold;\n const blocked = result.prediction === \"MALICIOUS\";\n const commonEventFields = {\n hook,\n ...(toolName !== undefined ? { toolName } : {}),\n ...(toolCallId !== undefined ? { toolCallId } : {}),\n text,\n result,\n };\n options.onClassify?.({\n ...commonEventFields,\n blocked,\n shadowMode,\n });\n if (!blocked || shadowMode) {\n return;\n }\n\n const err = new FirewallBlockedException({\n score: result.score,\n threshold,\n promptText: text,\n hook,\n ...(toolName !== undefined ? { toolName } : {}),\n ...(toolCallId !== undefined ? { toolCallId } : {}),\n result,\n });\n options.onBlocked?.(err);\n throw err;\n };\n\n const scanPrompt = async (prompt: ReadonlyArray<VercelPromptMessage>): Promise<void> => {\n if (prompt.length === 0) {\n return;\n }\n const last = prompt[prompt.length - 1]!;\n const role = last.role.toLowerCase();\n\n // If the newest message is a tool result (typical mid-flow in a\n // tool-calling loop), classify each tool-result part individually with\n // tool_response + toolName. No manual wiring from the caller — the\n // toolName is read directly from the Vercel content part.\n if (role === \"tool\") {\n for (const { text, toolName, toolCallId } of iterateToolResultParts(last)) {\n await classifyOrBlock(text, HookLabel.TOOL_RESPONSE, { toolName, toolCallId });\n }\n return;\n }\n\n // Otherwise, fall back to scanning the most recent user message.\n // Covers: [user], [system, user], [user, assistant(text), user], etc.\n const lastUser = findLastUserMessage(prompt);\n if (!lastUser) {\n return;\n }\n const text = extractContentText(lastUser.content).trim();\n if (!text) {\n return;\n }\n await classifyOrBlock(text, HookLabel.USER_INPUT);\n };\n\n const scanGenerateResult = async (result: VercelGenerateResult): Promise<void> => {\n if (scanOutput && typeof result.text === \"string\" && result.text.length > 0) {\n await classifyOrBlock(result.text, HookLabel.LLM_OUTPUT);\n }\n if (options.scanToolCalls && Array.isArray(result.toolCalls)) {\n for (const call of result.toolCalls) {\n if (!call || typeof call !== \"object\") {\n continue;\n }\n const toolInput = call.args !== undefined ? call.args : call.input;\n const args =\n typeof toolInput === \"string\" ? toolInput : stringifyToolValue(toolInput);\n const toolName = typeof call.toolName === \"string\" ? call.toolName : undefined;\n const toolCallId = typeof call.toolCallId === \"string\" ? call.toolCallId : undefined;\n if (args.trim()) {\n await classifyOrBlock(args, HookLabel.TOOL_CALL, { toolName, toolCallId });\n }\n }\n }\n };\n\n return {\n specificationVersion: \"v3\",\n middlewareVersion: \"v2\",\n\n async wrapGenerate<TResult extends VercelGenerateResult & Record<string, unknown>>({\n params,\n doGenerate,\n }: WrapGenerateArgs<TResult>): Promise<TResult> {\n if (scanInput) {\n await scanPrompt(params.prompt ?? []);\n }\n const result = await doGenerate();\n await scanGenerateResult(result);\n return result;\n },\n\n async wrapStream<TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>>({\n params,\n doStream,\n }: WrapStreamArgs<TResult>): Promise<TResult> {\n if (scanInput) {\n await scanPrompt(params.prompt ?? []);\n }\n const { stream, ...rest } = await doStream();\n if (!scanOutput) {\n return { stream, ...rest } as unknown as TResult;\n }\n\n let buffered = \"\";\n const transformed = stream.pipeThrough(\n new TransformStream<unknown, unknown>({\n transform(chunk, controller): void {\n const part = chunk as StreamPart;\n if (part && part.type === \"text-delta\") {\n const delta = part.textDelta ?? part.delta ?? \"\";\n buffered += delta;\n }\n controller.enqueue(chunk);\n },\n async flush(controller): Promise<void> {\n if (!buffered.trim()) {\n return;\n }\n try {\n await classifyOrBlock(buffered, HookLabel.LLM_OUTPUT);\n } catch (err) {\n if (err instanceof FirewallBlockedException) {\n controller.enqueue({ type: \"error\", error: err });\n return;\n }\n throw err;\n }\n },\n }),\n );\n return { stream: transformed, ...rest } as unknown as TResult;\n },\n };\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport const Outcome = {\n Benign: \"benign\",\n InformationDisclosure: \"information_disclosure\",\n SecretExposure: \"secret_exposure\",\n ControlAbuse: \"control_abuse\",\n SystemCompromise: \"system_compromise\",\n ServiceDisruption: \"service_disruption\",\n} as const;\n\ndeclare const unknownOutcomeBrand: unique symbol;\n\nexport type KnownPrimaryOutcome = (typeof Outcome)[keyof typeof Outcome];\nexport type KnownHarmfulOutcome = Exclude<KnownPrimaryOutcome, typeof Outcome.Benign>;\nexport type UnknownOutcome = string & { readonly [unknownOutcomeBrand]: \"UnknownOutcome\" };\nexport type PrimaryOutcome = KnownPrimaryOutcome | UnknownOutcome;\nexport type HarmfulOutcome = KnownHarmfulOutcome | UnknownOutcome;\n\nexport const PRIMARY_OUTCOMES = [\n Outcome.Benign,\n Outcome.InformationDisclosure,\n Outcome.SecretExposure,\n Outcome.ControlAbuse,\n Outcome.SystemCompromise,\n Outcome.ServiceDisruption,\n] as const satisfies readonly PrimaryOutcome[];\n\nexport const HARMFUL_OUTCOMES = [\n Outcome.InformationDisclosure,\n Outcome.SecretExposure,\n Outcome.ControlAbuse,\n Outcome.SystemCompromise,\n Outcome.ServiceDisruption,\n] as const satisfies readonly KnownHarmfulOutcome[];\n\nexport const OUTCOME_DESCRIPTIONS = {\n [Outcome.Benign]: \"No harmful firewall outcome detected.\",\n [Outcome.InformationDisclosure]:\n \"Exposes private data, documents, internal context, logs, traces, customer data, SQL rows, topology, or similar non-secret sensitive information.\",\n [Outcome.SecretExposure]:\n \"Exposes credentials, tokens, API keys, cookies, passwords, signing keys, OAuth secrets, session material, or webhook secrets.\",\n [Outcome.ControlAbuse]:\n \"Misuses authorized tools or user privileges to send, change, approve, delete, operate, or bypass policy/RBAC without a stronger outcome.\",\n [Outcome.SystemCompromise]:\n \"Enables privilege escalation, account takeover, hostile integration or plugin takeover, persistence, lateral movement, attacker webhook registration, or code/plugin execution.\",\n [Outcome.ServiceDisruption]:\n \"Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence.\",\n} as const satisfies Readonly<Record<KnownPrimaryOutcome, string>>;\n\nconst PRIMARY_OUTCOME_SET = new Set<string>(PRIMARY_OUTCOMES);\nconst HARMFUL_OUTCOME_SET = new Set<string>(HARMFUL_OUTCOMES);\n\nexport function isPrimaryOutcome(value: unknown): value is KnownPrimaryOutcome {\n return typeof value === \"string\" && PRIMARY_OUTCOME_SET.has(value);\n}\n\nexport function isHarmfulOutcome(value: unknown): value is KnownHarmfulOutcome {\n return typeof value === \"string\" && HARMFUL_OUTCOME_SET.has(value);\n}\n\nexport function normalizePrimaryOutcome(\n value: unknown,\n fieldName = \"primary_outcome\",\n): PrimaryOutcome {\n if (typeof value !== \"string\") {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(value)}`);\n }\n return isPrimaryOutcome(value) ? value : (value as UnknownOutcome);\n}\n\nexport function normalizeHarmfulOutcome(\n value: unknown,\n fieldName = \"outcome\",\n): HarmfulOutcome {\n if (typeof value !== \"string\" || value === Outcome.Benign) {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(value)}`);\n }\n return isHarmfulOutcome(value) ? value : (value as UnknownOutcome);\n}\n\nexport function normalizeHarmfulOutcomeMap(\n values: unknown,\n fieldName: string,\n): Readonly<Partial<Record<HarmfulOutcome, number>>> | undefined {\n if (values === undefined || values === null) {\n return undefined;\n }\n if (typeof values !== \"object\" || Array.isArray(values)) {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(values)}`);\n }\n const out: Partial<Record<HarmfulOutcome, number>> = {};\n for (const [key, value] of Object.entries(values)) {\n const normalizedKey = normalizeHarmfulOutcome(key, `${fieldName} key`);\n if (typeof value !== \"number\") {\n throw new Error(`Firewall: invalid ${fieldName} value for ${JSON.stringify(key)}`);\n }\n out[normalizedKey] = value;\n }\n return Object.freeze(out);\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nfunction isHighSurrogate(code: number): boolean {\n return code >= 0xd800 && code <= 0xdbff;\n}\n\nfunction isLowSurrogate(code: number): boolean {\n return code >= 0xdc00 && code <= 0xdfff;\n}\n\nexport function sanitizeText(text: string): string {\n let out = \"\";\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (isHighSurrogate(code)) {\n if (i + 1 < text.length && isLowSurrogate(text.charCodeAt(i + 1))) {\n out += text[i]!;\n out += text[i + 1]!;\n i++;\n }\n continue;\n }\n if (!isLowSurrogate(code)) {\n out += text[i]!;\n }\n }\n return out;\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport {\n Firewall,\n DEFAULT_TIMEOUT_MS,\n} from \"./firewall.js\";\n\nexport { FirewallBlockedException, PromptBlockedException, SilmarilApiError } from \"./exceptions.js\";\nexport type { MalformedInputDetails } from \"./exceptions.js\";\n\nexport type { FirewallMiddleware } from \"./adapters/vercel.js\";\n\nexport {\n HookLabel,\n FirewallHook,\n DEFAULT_HOOKS,\n INPUT_HOOKS,\n OUTPUT_HOOKS,\n ALL_HOOKS,\n FIREWALL_HOOK_TO_LABEL,\n resolveHooks,\n prependHook,\n prependToolName,\n} from \"./hooks.js\";\n\nexport {\n Outcome,\n PRIMARY_OUTCOMES,\n HARMFUL_OUTCOMES,\n OUTCOME_DESCRIPTIONS,\n isPrimaryOutcome,\n isHarmfulOutcome,\n normalizePrimaryOutcome,\n normalizeHarmfulOutcome,\n normalizeHarmfulOutcomeMap,\n} from \"./outcomes.js\";\n\nexport type {\n KnownPrimaryOutcome,\n KnownHarmfulOutcome,\n PrimaryOutcome,\n HarmfulOutcome,\n UnknownOutcome,\n} from \"./outcomes.js\";\n\nexport type {\n BlockResult,\n ClassifyEvent,\n Prediction,\n ClassificationMetadata,\n FirewallOptions,\n ClassifyOptions,\n ClassifyBatchOptions,\n LangChainAdapterOptions,\n LangChainFirewallHandler,\n MiddlewareOptions,\n} from \"./types.js\";\n"],"mappings":"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","names":["findLastUserMessage","text","isRecord","body"]}
1
+ {"version":3,"sources":["../src/exceptions.ts","../src/hooks.ts","../src/utils/extract.ts","../src/adapters/langchain.ts","../src/firewall.ts","../src/adapters/vercel.ts","../src/outcomes.ts","../src/sanitization.ts","../src/index.ts"],"sourcesContent":["// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { HookLabel } from \"./hooks.js\";\nimport type { BlockResult } from \"./types.js\";\n\nconst MAX_PROMPT_DISPLAY_LEN = 100;\n\nexport interface MalformedInputDetails {\n field?: string;\n inputIndex?: number;\n charOffset?: number;\n malformedToken?: string;\n codePoint?: string;\n reason?: string;\n}\n\nexport class FirewallBlockedException extends Error {\n readonly score: number;\n readonly threshold: number;\n readonly promptText: string;\n readonly runId: string | undefined;\n readonly hook: HookLabel | undefined;\n readonly toolName: string | undefined;\n readonly toolCallId: string | undefined;\n readonly result: BlockResult | undefined;\n\n constructor(params: {\n score: number;\n threshold: number;\n promptText: string;\n runId?: string;\n hook?: HookLabel;\n toolName?: string;\n toolCallId?: string;\n result?: BlockResult;\n }) {\n super(FirewallBlockedException.formatMessage(params));\n this.name = \"FirewallBlockedException\";\n this.score = params.score;\n this.threshold = params.threshold;\n this.promptText = params.promptText;\n this.runId = params.runId;\n this.hook = params.hook;\n this.toolName = params.toolName;\n this.toolCallId = params.toolCallId;\n this.result = params.result;\n Object.setPrototypeOf(this, FirewallBlockedException.prototype);\n }\n\n private static formatMessage(params: {\n score: number;\n threshold: number;\n promptText: string;\n }): string {\n const truncated =\n params.promptText.length > MAX_PROMPT_DISPLAY_LEN\n ? `${params.promptText.slice(0, MAX_PROMPT_DISPLAY_LEN)}...`\n : params.promptText;\n return (\n `Request blocked by Silmaril Firewall ` +\n `(score=${params.score.toFixed(4)}, threshold=${params.threshold.toFixed(4)}): ` +\n `'${truncated}'`\n );\n }\n}\n\n/** @deprecated Use FirewallBlockedException instead. */\nexport const PromptBlockedException = FirewallBlockedException;\n/** @deprecated Use FirewallBlockedException instead. */\nexport type PromptBlockedException = FirewallBlockedException;\n\nexport class SilmarilApiError extends Error {\n readonly status: number;\n readonly statusText: string;\n readonly body: string;\n readonly details: MalformedInputDetails | undefined;\n readonly error: string | undefined;\n readonly apiMessage: string | undefined;\n\n constructor(params: {\n status: number;\n statusText: string;\n body: string;\n details?: MalformedInputDetails;\n error?: string;\n apiMessage?: string;\n }) {\n const statusText = params.statusText ? ` ${params.statusText}` : \"\";\n super(`Silmaril API error ${params.status}${statusText}`);\n this.name = \"SilmarilApiError\";\n this.status = params.status;\n this.statusText = params.statusText;\n this.body = params.body;\n const parsed = parseErrorBody(params.body);\n this.details = params.details ?? parsed.details;\n this.error = params.error ?? parsed.error;\n this.apiMessage = params.apiMessage ?? parsed.apiMessage;\n Object.setPrototypeOf(this, SilmarilApiError.prototype);\n }\n}\n\nfunction parseErrorBody(body: string): {\n details: MalformedInputDetails | undefined;\n error: string | undefined;\n apiMessage: string | undefined;\n} {\n try {\n const parsed = JSON.parse(body) as unknown;\n if (!parsed || typeof parsed !== \"object\") {\n return { details: undefined, error: undefined, apiMessage: undefined };\n }\n const data = parsed as Record<string, unknown>;\n return {\n details:\n data.details && typeof data.details === \"object\"\n ? (data.details as MalformedInputDetails)\n : undefined,\n error: typeof data.error === \"string\" ? data.error : undefined,\n apiMessage: typeof data.message === \"string\" ? data.message : undefined,\n };\n } catch {\n return { details: undefined, error: undefined, apiMessage: undefined };\n }\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport const HookLabel = {\n USER_INPUT: \"user_input\",\n SYSTEM_PROMPT: \"system_prompt\",\n TOOL_CALL: \"tool_call\",\n TOOL_RESPONSE: \"tool_response\",\n LLM_OUTPUT: \"llm_output\",\n UNKNOWN: \"unknown\",\n} as const;\n\nexport type HookLabel = (typeof HookLabel)[keyof typeof HookLabel];\n\nexport const FirewallHook = {\n LLM_START: \"on_llm_start\",\n CHAT_MODEL_START: \"on_chat_model_start\",\n TOOL_START: \"on_tool_start\",\n RETRIEVER_START: \"on_retriever_start\",\n LLM_END: \"on_llm_end\",\n TOOL_END: \"on_tool_end\",\n RETRIEVER_END: \"on_retriever_end\",\n} as const;\n\nexport type FirewallHook = (typeof FirewallHook)[keyof typeof FirewallHook];\n\nexport const DEFAULT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n]);\n\nexport const INPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_START,\n FirewallHook.CHAT_MODEL_START,\n FirewallHook.TOOL_START,\n FirewallHook.RETRIEVER_START,\n]);\n\nexport const OUTPUT_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n FirewallHook.LLM_END,\n FirewallHook.TOOL_END,\n FirewallHook.RETRIEVER_END,\n]);\n\nexport const ALL_HOOKS: ReadonlySet<FirewallHook> = new Set<FirewallHook>([\n ...INPUT_HOOKS,\n ...OUTPUT_HOOKS,\n]);\n\nexport const FIREWALL_HOOK_TO_LABEL: Readonly<Record<FirewallHook, HookLabel>> = {\n [FirewallHook.CHAT_MODEL_START]: HookLabel.USER_INPUT,\n [FirewallHook.LLM_START]: HookLabel.USER_INPUT,\n [FirewallHook.TOOL_START]: HookLabel.TOOL_CALL,\n [FirewallHook.TOOL_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.RETRIEVER_START]: HookLabel.TOOL_CALL,\n [FirewallHook.RETRIEVER_END]: HookLabel.TOOL_RESPONSE,\n [FirewallHook.LLM_END]: HookLabel.LLM_OUTPUT,\n};\n\nconst FIREWALL_HOOK_VALUES: ReadonlySet<string> = new Set(Object.values(FirewallHook));\n\nexport function resolveHooks(\n hooks: Iterable<FirewallHook | string> | undefined,\n): ReadonlySet<FirewallHook> {\n if (hooks === undefined) {\n return DEFAULT_HOOKS;\n }\n const resolved = new Set<FirewallHook>();\n for (const h of hooks) {\n if (!FIREWALL_HOOK_VALUES.has(h)) {\n throw new Error(`Invalid FirewallHook value: ${String(h)}`);\n }\n resolved.add(h as FirewallHook);\n }\n return resolved;\n}\n\nexport function prependHook(text: string, hook: HookLabel | string | undefined | null): string {\n if (hook === undefined || hook === null) {\n return text;\n }\n if (hook === HookLabel.UNKNOWN) {\n return text;\n }\n return `[HOOK:${hook}] ${text}`;\n}\n\nexport function prependToolName(text: string, toolName: string | undefined | null): string {\n if (toolName === undefined || toolName === null) {\n return text;\n }\n return `[TOOL:${toolName}] ${text}`;\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nconst SKIP_ROLES: ReadonlySet<string> = new Set([\"ai\", \"assistant\"]);\nconst SYSTEM_ROLES: ReadonlySet<string> = new Set([\"system\"]);\nconst TOOL_ROLES: ReadonlySet<string> = new Set([\"tool\", \"function\"]);\n\ntype MessageContent = string | ReadonlyArray<string | { type?: string; text?: string }>;\n\ninterface DucktypedMessage {\n role?: string;\n type?: string;\n content?: MessageContent;\n}\n\ninterface DucktypedGeneration {\n text?: string;\n}\n\ninterface DucktypedLLMResult {\n generations?: ReadonlyArray<ReadonlyArray<DucktypedGeneration>>;\n}\n\ninterface DucktypedDocument {\n pageContent?: string;\n}\n\nfunction extractContentText(content: MessageContent | undefined): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && typeof block === \"object\" && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n }\n return \"\";\n}\n\nfunction getRole(message: DucktypedMessage): string {\n if (message.role !== undefined) {\n return message.role.toLowerCase();\n }\n if (typeof message.type === \"string\") {\n return message.type.toLowerCase();\n }\n return \"\";\n}\n\nexport function extractTextFromMessages(\n messages: ReadonlyArray<DucktypedMessage>,\n options: { includeSystem?: boolean; includeTool?: boolean } = {},\n): string {\n const includeSystem = options.includeSystem ?? true;\n const includeTool = options.includeTool ?? true;\n const parts: string[] = [];\n for (const message of messages) {\n const role = getRole(message);\n if (SKIP_ROLES.has(role)) {\n continue;\n }\n if (!includeSystem && SYSTEM_ROLES.has(role)) {\n continue;\n }\n if (!includeTool && TOOL_ROLES.has(role)) {\n continue;\n }\n const text = extractContentText(message.content);\n const stripped = text.trim();\n if (stripped) {\n parts.push(stripped);\n }\n }\n return parts.join(\"\\n\");\n}\n\nexport function extractTextFromPrompts(prompts: readonly string[]): string {\n return prompts\n .map((p) => p.trim())\n .filter((p) => p.length > 0)\n .join(\"\\n\");\n}\n\nexport function extractTextFromToolInput(inputStr: string): string {\n return inputStr.trim();\n}\n\nexport function extractTextFromLLMResult(response: DucktypedLLMResult): string {\n const parts: string[] = [];\n for (const genList of response.generations ?? []) {\n for (const gen of genList) {\n const text = (gen.text ?? \"\").trim();\n if (text) {\n parts.push(text);\n }\n }\n }\n return parts.join(\"\\n\");\n}\n\nexport function extractTextFromDocuments(documents: ReadonlyArray<DucktypedDocument>): string {\n const parts: string[] = [];\n for (const doc of documents) {\n const text = (doc.pageContent ?? \"\").trim();\n if (text) {\n parts.push(text);\n }\n }\n return parts.join(\"\\n\");\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { BaseCallbackHandler } from \"@langchain/core/callbacks/base\";\n\nimport type { Firewall } from \"../firewall.js\";\nimport { FirewallBlockedException } from \"../exceptions.js\";\nimport {\n FIREWALL_HOOK_TO_LABEL,\n FirewallHook,\n HookLabel,\n resolveHooks,\n} from \"../hooks.js\";\nimport type { BlockResult, ClassifyEvent, LangChainAdapterOptions } from \"../types.js\";\nimport {\n extractTextFromDocuments,\n extractTextFromLLMResult,\n extractTextFromPrompts,\n extractTextFromToolInput,\n} from \"../utils/extract.js\";\n\nconst USER_ROLES: ReadonlySet<string> = new Set([\"human\", \"user\"]);\n\ninterface LangChainDucktypedMessage {\n role?: string;\n type?: string;\n content?: string | ReadonlyArray<string | { type?: string; text?: string }>;\n}\n\nfunction getMessageRole(message: LangChainDucktypedMessage): string {\n if (typeof message.role === \"string\") {\n return message.role.toLowerCase();\n }\n if (typeof message.type === \"string\") {\n return message.type.toLowerCase();\n }\n return \"\";\n}\n\nfunction extractMessageText(content: LangChainDucktypedMessage[\"content\"]): string {\n if (content === undefined) {\n return \"\";\n }\n if (typeof content === \"string\") {\n return content;\n }\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n}\n\nfunction findLastUserMessage(\n messages: ReadonlyArray<LangChainDucktypedMessage>,\n): LangChainDucktypedMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (USER_ROLES.has(getMessageRole(msg))) {\n return msg;\n }\n }\n return undefined;\n}\n\nexport async function createLangChainHandler(\n firewall: Firewall,\n options: LangChainAdapterOptions = {},\n): Promise<BaseCallbackHandler> {\n const { BaseCallbackHandler } = await import(\"@langchain/core/callbacks/base\");\n\n const enabledHooks = resolveHooks(options.hooks);\n // includeSystem / includeTool are retained in LangChainAdapterOptions for\n // backwards compat but are inert under the per-message hook-routing algorithm:\n // handleChatModelStart only scans the last user-role message; system and tool\n // messages are either trusted or already classified by their own hooks.\n const failOpen = options.failOpen ?? true;\n const logger =\n options.logger ??\n ((message: string, error: unknown): void => {\n // eslint-disable-next-line no-console\n console.warn(`silmaril.firewall: ${message}`, error);\n });\n const requestedMode = options.mode ?? (\n options.shadowMode === undefined\n ? firewall.mode\n : options.shadowMode ? \"shadow\" : \"block\"\n );\n const onClassify = options.onClassify;\n\n const fireOnClassify = (event: ClassifyEvent): void => {\n if (!onClassify) {\n return;\n }\n try {\n onClassify(event);\n } catch (err) {\n logger(\"onClassify callback threw\", err);\n }\n };\n\n const classify = async (\n text: string,\n hookLabel: HookLabel,\n runId: string,\n toolName?: string,\n ): Promise<void> => {\n let result: BlockResult;\n try {\n result = await firewall.classify(text, {\n hook: hookLabel,\n ...(requestedMode !== undefined ? { mode: requestedMode } : {}),\n ...(toolName !== undefined ? { toolName } : {}),\n });\n } catch (err) {\n if (!failOpen) {\n throw err;\n }\n logger(\"classification failed, allowing prompt through\", err);\n return;\n }\n const threshold = result.threshold;\n const blocked = result.prediction === \"MALICIOUS\";\n const effectiveMode = requestedMode ?? result.mode ?? \"block\";\n const commonEventFields = {\n hook: hookLabel,\n ...(toolName !== undefined ? { toolName } : {}),\n runId,\n text,\n result,\n };\n fireOnClassify({\n ...commonEventFields,\n blocked,\n mode: effectiveMode,\n shadowMode: effectiveMode === \"shadow\",\n });\n if (!blocked || effectiveMode !== \"block\") {\n return;\n }\n\n throw new FirewallBlockedException({\n score: result.score,\n threshold,\n promptText: text,\n runId,\n hook: hookLabel,\n ...(toolName !== undefined ? { toolName } : {}),\n result,\n });\n };\n\n class SilmarilFirewallHandler extends BaseCallbackHandler {\n override name = \"silmaril_firewall_handler\";\n override raiseError = true;\n override awaitHandlers = true;\n\n override async handleChatModelStart(\n _llm: unknown,\n messages: unknown,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.CHAT_MODEL_START)) {\n return;\n }\n const batches = messages as ReadonlyArray<ReadonlyArray<LangChainDucktypedMessage>>;\n const flat: LangChainDucktypedMessage[] = [];\n for (const batch of batches) {\n for (const m of batch) {\n flat.push(m);\n }\n }\n const lastUser = findLastUserMessage(flat);\n if (!lastUser) {\n return;\n }\n const text = extractMessageText(lastUser.content).trim();\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.CHAT_MODEL_START], runId);\n }\n\n override async handleLLMStart(\n _llm: unknown,\n prompts: string[],\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.LLM_START)) {\n return;\n }\n const text = extractTextFromPrompts(prompts);\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_START], runId);\n }\n\n override async handleToolStart(\n tool: { name?: string } | undefined,\n inputStr: string,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.TOOL_START)) {\n return;\n }\n const text = extractTextFromToolInput(inputStr);\n if (!text) {\n return;\n }\n const toolName = tool?.name;\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_START], runId, toolName);\n }\n\n override async handleRetrieverStart(\n _retriever: unknown,\n query: string,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.RETRIEVER_START)) {\n return;\n }\n const text = query.trim();\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_START], runId);\n }\n\n override async handleLLMEnd(output: unknown, runId: string): Promise<void> {\n if (!enabledHooks.has(FirewallHook.LLM_END)) {\n return;\n }\n const text = extractTextFromLLMResult(output as { generations?: ReadonlyArray<ReadonlyArray<{ text?: string }>> });\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_END], runId);\n }\n\n override async handleToolEnd(\n output: unknown,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _kwargs?: { name?: string },\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.TOOL_END)) {\n return;\n }\n const text = String(output).trim();\n if (!text) {\n return;\n }\n const toolName = _kwargs?.name;\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_END], runId, toolName);\n }\n\n override async handleRetrieverEnd(\n documents: ReadonlyArray<{ pageContent?: string }>,\n runId: string,\n ): Promise<void> {\n if (!enabledHooks.has(FirewallHook.RETRIEVER_END)) {\n return;\n }\n const text = extractTextFromDocuments(documents);\n if (!text) {\n return;\n }\n await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_END], runId);\n }\n }\n\n return new SilmarilFirewallHandler();\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { createMiddleware, type FirewallMiddleware } from \"./adapters/vercel.js\";\nimport { SilmarilApiError } from \"./exceptions.js\";\nimport { normalizeHarmfulOutcomeMap, normalizePrimaryOutcome } from \"./outcomes.js\";\nimport { sanitizeText } from \"./sanitization.js\";\nimport type {\n BlockResult,\n ClassifyBatchOptions,\n ClassifyOptions,\n ClassificationMetadata,\n FirewallOptions,\n FirewallMode,\n LangChainAdapterOptions,\n LangChainFirewallHandler,\n MiddlewareOptions,\n Prediction,\n} from \"./types.js\";\n\nexport const SDK_VERSION = \"0.6.0\";\nexport const DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_RETRIES = 5;\nconst MAX_BACKOFF_SECONDS = 30;\nconst MAX_ERROR_BODY_BYTES = 1 << 16;\n\ninterface SingleClassifyPayload {\n text: string;\n mode?: FirewallMode;\n hook?: string;\n tool_name?: string;\n metadata?: ClassificationMetadata;\n}\n\ninterface BatchClassifyPayload {\n texts: readonly string[];\n mode?: FirewallMode;\n hooks?: readonly string[];\n tool_names?: readonly (string | null)[];\n metadata?: readonly (ClassificationMetadata | null)[];\n}\n\ninterface SingleClassifyResponse {\n prediction: Prediction;\n score: number;\n threshold: number;\n mode?: unknown;\n primary_outcome?: unknown;\n outcome_scores?: unknown;\n detector_scores?: unknown;\n detector_counts?: unknown;\n}\n\ninterface BatchClassifyResponse {\n predictions: readonly SingleClassifyResponse[];\n}\n\nfunction resolveMode(value: unknown, requestedMode?: FirewallMode): FirewallMode | undefined {\n let responseMode: FirewallMode | undefined;\n if (value === \"shadow\" || value === \"warn\" || value === \"block\") {\n responseMode = value;\n } else if (value !== undefined) {\n throw new Error(\"Firewall: response mode must be shadow, warn, or block\");\n }\n\n // A supplied mode is the per-request override contract. Prefer it during\n // rolling upgrades so a missing or stale response field cannot strengthen\n // enforcement beyond what the caller requested.\n return requestedMode ?? responseMode;\n}\n\nfunction legacyMode(shadowMode: boolean | undefined): FirewallMode | undefined {\n return shadowMode === undefined ? undefined : shadowMode ? \"shadow\" : \"block\";\n}\n\nfunction blockResultFromResponse(\n data: SingleClassifyResponse,\n requestedMode?: FirewallMode,\n): BlockResult {\n if (data.prediction !== \"BENIGN\" && data.prediction !== \"MALICIOUS\") {\n throw new Error(\"Firewall: response prediction must be BENIGN or MALICIOUS\");\n }\n const result: {\n prediction: Prediction;\n score: number;\n threshold: number;\n mode?: FirewallMode;\n primaryOutcome?: NonNullable<BlockResult[\"primaryOutcome\"]>;\n outcomeScores?: NonNullable<BlockResult[\"outcomeScores\"]>;\n detectorScores?: NonNullable<BlockResult[\"detectorScores\"]>;\n detectorCounts?: NonNullable<BlockResult[\"detectorCounts\"]>;\n } = {\n prediction: data.prediction,\n score: Number(data.score),\n threshold: Number(data.threshold),\n };\n const mode = resolveMode(data.mode, requestedMode);\n if (mode !== undefined) {\n result.mode = mode;\n }\n if (data.primary_outcome !== undefined) {\n result.primaryOutcome = normalizePrimaryOutcome(data.primary_outcome);\n }\n if (data.outcome_scores !== undefined) {\n const outcomeScores = normalizeHarmfulOutcomeMap(data.outcome_scores, \"outcome_scores\");\n if (outcomeScores !== undefined) {\n result.outcomeScores = outcomeScores;\n }\n }\n if (data.detector_scores !== undefined) {\n const detectorScores = normalizeHarmfulOutcomeMap(data.detector_scores, \"detector_scores\");\n if (detectorScores !== undefined) {\n result.detectorScores = detectorScores;\n }\n }\n if (data.detector_counts !== undefined) {\n const detectorCounts = normalizeHarmfulOutcomeMap(data.detector_counts, \"detector_counts\");\n if (detectorCounts !== undefined) {\n result.detectorCounts = detectorCounts;\n }\n }\n return Object.freeze(result);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction withSdkMetadata(\n metadata: ClassificationMetadata | undefined,\n info: {\n requestId: string;\n inputIndex?: number;\n },\n): ClassificationMetadata {\n const payload: Record<string, unknown> = { ...(metadata ?? {}) };\n const existing = payload.silmaril;\n if (existing !== undefined && !isRecord(existing)) {\n throw new Error(\"Firewall: metadata.silmaril must be an object when provided\");\n }\n payload.silmaril = {\n ...(isRecord(existing) ? existing : {}),\n sdk_language: \"typescript\",\n sdk_version: SDK_VERSION,\n request_id: info.requestId,\n ...(info.inputIndex === undefined ? {} : { input_index: info.inputIndex }),\n };\n return payload;\n}\n\nasync function readCappedErrorBody(response: Response): Promise<string> {\n if (!response.body) {\n return response.text().then((body) => body.slice(0, MAX_ERROR_BODY_BYTES)).catch(() => \"\");\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let remaining = MAX_ERROR_BODY_BYTES;\n try {\n while (remaining > 0) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (!value) {\n continue;\n }\n const chunk = value.byteLength > remaining ? value.slice(0, remaining) : value;\n chunks.push(chunk);\n remaining -= chunk.byteLength;\n if (chunk.byteLength < value.byteLength) {\n break;\n }\n }\n } catch {\n return \"\";\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n\n const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nexport class Firewall {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly timeoutMs: number;\n readonly shadowMode: boolean;\n readonly mode: FirewallMode | undefined;\n\n private readonly headers: Readonly<Record<string, string>>;\n\n constructor(options: FirewallOptions) {\n if (!options.apiKey) {\n throw new Error(\"Firewall: apiKey is required\");\n }\n if (!options.apiUrl) {\n throw new Error(\"Firewall: apiUrl is required\");\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (typeof this.timeoutMs !== \"number\" || !Number.isFinite(this.timeoutMs) || this.timeoutMs < 0) {\n throw new Error(`Firewall: timeoutMs must be a finite non-negative number, got ${this.timeoutMs}`);\n }\n this.mode = options.mode ?? legacyMode(options.shadowMode);\n this.shadowMode = this.mode === \"shadow\";\n this.headers = Object.freeze({\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\",\n });\n }\n\n async classify(text: string, options: ClassifyOptions = {}): Promise<BlockResult> {\n const requestId = options.requestId ?? randomUUID();\n return this.classifySingle(sanitizeText(text), options, { requestId });\n }\n\n async classifyBatch(\n texts: readonly string[],\n options: ClassifyBatchOptions = {},\n ): Promise<BlockResult[]> {\n if (texts.length === 0) {\n throw new Error(\"Firewall: texts must not be empty\");\n }\n if (options.hooks !== undefined && options.hooks.length !== texts.length) {\n throw new Error(\n `Firewall: hooks length ${options.hooks.length} does not match texts length ${texts.length}`,\n );\n }\n if (options.toolNames !== undefined && options.toolNames.length !== texts.length) {\n throw new Error(\n `Firewall: toolNames length ${options.toolNames.length} does not match texts length ${texts.length}`,\n );\n }\n if (options.metadata !== undefined && options.metadata.length !== texts.length) {\n throw new Error(\n `Firewall: metadata length ${options.metadata.length} does not match texts length ${texts.length}`,\n );\n }\n\n const requestId = options.requestId ?? randomUUID();\n const payload: BatchClassifyPayload = {\n texts: texts.map((text) => sanitizeText(text)),\n };\n const requestedMode = options.mode ?? this.mode;\n if (requestedMode !== undefined) {\n payload.mode = requestedMode;\n }\n if (options.hooks && options.hooks.length > 0) {\n payload.hooks = options.hooks.map((h) => String(h));\n }\n if (options.toolNames && options.toolNames.length > 0) {\n payload.tool_names = options.toolNames.map((t) => (t === undefined ? null : t));\n }\n payload.metadata = texts.map((_, index) =>\n withSdkMetadata(options.metadata?.[index], {\n requestId,\n inputIndex: index,\n }),\n );\n const data = await this.postWithRetry<BatchClassifyResponse>(payload);\n return data.predictions.map((p) => blockResultFromResponse(p, requestedMode));\n }\n\n asLangChainHandler<THandler = LangChainFirewallHandler>(\n options: LangChainAdapterOptions = {},\n ): Promise<THandler> {\n return import(\"./adapters/langchain.js\").then((m) =>\n m.createLangChainHandler(this, options) as Promise<THandler>,\n );\n }\n\n asMiddleware(options: MiddlewareOptions = {}): FirewallMiddleware {\n return createMiddleware(this, options);\n }\n\n private async postWithRetry<T>(\n payload: SingleClassifyPayload | BatchClassifyPayload,\n maxRetries: number = DEFAULT_MAX_RETRIES,\n ): Promise<T> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(this.apiUrl, {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify(payload),\n redirect: \"error\",\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n if (response.status !== 429 || attempt === maxRetries) {\n if (!response.ok) {\n const body = await readCappedErrorBody(response);\n throw new SilmarilApiError({\n status: response.status,\n statusText: response.statusText,\n body,\n });\n }\n return (await response.json()) as T;\n }\n const waitSeconds = Math.min(2 ** attempt, MAX_BACKOFF_SECONDS);\n await new Promise<void>((resolve) => setTimeout(resolve, waitSeconds * 1000));\n }\n throw new Error(\"Firewall: exhausted retries (unreachable)\");\n }\n\n private async classifySingle(\n text: string,\n options: ClassifyOptions,\n metadataInfo: {\n requestId: string;\n },\n ): Promise<BlockResult> {\n const payload: SingleClassifyPayload = { text };\n const requestedMode = options.mode ?? this.mode;\n if (requestedMode !== undefined) {\n payload.mode = requestedMode;\n }\n if (options.hook !== undefined) {\n payload.hook = options.hook;\n }\n if (options.toolName !== undefined) {\n payload.tool_name = options.toolName;\n }\n payload.metadata = withSdkMetadata(options.metadata, metadataInfo);\n const data = await this.postWithRetry<SingleClassifyResponse>(payload);\n return blockResultFromResponse(data, requestedMode);\n }\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nimport type { Firewall } from \"../firewall.js\";\nimport { FirewallBlockedException } from \"../exceptions.js\";\nimport { HookLabel } from \"../hooks.js\";\nimport type { BlockResult, MiddlewareOptions } from \"../types.js\";\n\ninterface VercelContentPart {\n type?: string;\n text?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n output?: unknown;\n result?: unknown;\n}\n\ninterface VercelPromptMessage {\n role: string;\n content: string | ReadonlyArray<VercelContentPart | string>;\n}\n\ninterface VercelToolCall {\n toolCallType?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n input?: unknown;\n}\n\ninterface VercelGenerateResult {\n text?: string;\n toolCalls?: ReadonlyArray<VercelToolCall>;\n}\n\ninterface WrapGenerateArgs<TResult extends VercelGenerateResult & Record<string, unknown>> {\n params: { prompt?: ReadonlyArray<VercelPromptMessage> } & Record<string, unknown>;\n doGenerate: () => PromiseLike<TResult>;\n}\n\ninterface WrapStreamArgs<\n TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>,\n> {\n params: { prompt?: ReadonlyArray<VercelPromptMessage> } & Record<string, unknown>;\n doStream: () => PromiseLike<TResult>;\n}\n\ninterface StreamPart {\n type?: string;\n textDelta?: string;\n delta?: string;\n}\n\ninterface VercelStepContext {\n toolName: string | undefined;\n toolCallId: string | undefined;\n}\n\nfunction stringifyToolValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction extractContentText(content: VercelPromptMessage[\"content\"]): string {\n if (typeof content === \"string\") {\n return content;\n }\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block === \"string\") {\n parts.push(block);\n } else if (block && block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n return parts.join(\" \");\n}\n\nfunction iterateToolResultParts(\n message: VercelPromptMessage,\n): Array<{ text: string; toolName: string | undefined; toolCallId: string | undefined }> {\n if (typeof message.content === \"string\") {\n return [];\n }\n const out: Array<{ text: string; toolName: string | undefined; toolCallId: string | undefined }> = [];\n for (const part of message.content) {\n if (typeof part === \"string\") {\n continue;\n }\n if (part.type === \"tool-result\") {\n const text = stringifyToolResult(part.result !== undefined ? part.result : part.output);\n if (text.trim()) {\n out.push({ text, toolName: part.toolName, toolCallId: part.toolCallId });\n }\n }\n }\n return out;\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (!isRecord(value)) {\n return stringifyToolValue(value);\n }\n if ((value.type === \"text\" || value.type === \"error-text\") && typeof value.value === \"string\") {\n return value.value;\n }\n if ((value.type === \"json\" || value.type === \"error-json\") && value.value !== undefined) {\n return stringifyToolValue(value.value);\n }\n if (value.type === \"content\" && Array.isArray(value.value)) {\n return value.value\n .map((part) => (isRecord(part) && part.type === \"text\" && typeof part.text === \"string\" ? part.text : \"\"))\n .filter((text) => text.length > 0)\n .join(\" \");\n }\n return stringifyToolValue(value);\n}\n\nfunction findLastUserMessage(\n messages: ReadonlyArray<VercelPromptMessage>,\n): VercelPromptMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role.toLowerCase() === \"user\") {\n return msg;\n }\n }\n return undefined;\n}\n\nexport interface FirewallMiddleware {\n readonly specificationVersion: \"v3\";\n readonly middlewareVersion: \"v2\";\n wrapGenerate: <TResult extends VercelGenerateResult & Record<string, unknown>>(\n args: WrapGenerateArgs<TResult>,\n ) => Promise<TResult>;\n wrapStream: <TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>>(\n args: WrapStreamArgs<TResult>,\n ) => Promise<TResult>;\n}\n\nexport function createMiddleware(\n firewall: Firewall,\n options: MiddlewareOptions = {},\n): FirewallMiddleware {\n const scanInput = options.scanInput ?? true;\n const scanOutput = options.scanOutput ?? false;\n const requestedMode = options.mode ?? (\n options.shadowMode === undefined\n ? firewall.mode\n : options.shadowMode ? \"shadow\" : \"block\"\n );\n\n const classifyOrBlock = async (\n text: string,\n hook: HookLabel,\n context: VercelStepContext = { toolName: undefined, toolCallId: undefined },\n ): Promise<void> => {\n if (!text.trim()) {\n return;\n }\n const { toolName, toolCallId } = context;\n const result: BlockResult = await firewall.classify(\n text,\n {\n hook,\n ...(toolName !== undefined ? { toolName } : {}),\n ...(requestedMode !== undefined ? { mode: requestedMode } : {}),\n },\n );\n const threshold = result.threshold;\n const blocked = result.prediction === \"MALICIOUS\";\n const effectiveMode = requestedMode ?? result.mode ?? \"block\";\n const commonEventFields = {\n hook,\n ...(toolName !== undefined ? { toolName } : {}),\n ...(toolCallId !== undefined ? { toolCallId } : {}),\n text,\n result,\n };\n options.onClassify?.({\n ...commonEventFields,\n blocked,\n mode: effectiveMode,\n shadowMode: effectiveMode === \"shadow\",\n });\n if (!blocked || effectiveMode !== \"block\") {\n return;\n }\n\n const err = new FirewallBlockedException({\n score: result.score,\n threshold,\n promptText: text,\n hook,\n ...(toolName !== undefined ? { toolName } : {}),\n ...(toolCallId !== undefined ? { toolCallId } : {}),\n result,\n });\n options.onBlocked?.(err);\n throw err;\n };\n\n const scanPrompt = async (prompt: ReadonlyArray<VercelPromptMessage>): Promise<void> => {\n if (prompt.length === 0) {\n return;\n }\n const last = prompt[prompt.length - 1]!;\n const role = last.role.toLowerCase();\n\n // If the newest message is a tool result (typical mid-flow in a\n // tool-calling loop), classify each tool-result part individually with\n // tool_response + toolName. No manual wiring from the caller — the\n // toolName is read directly from the Vercel content part.\n if (role === \"tool\") {\n for (const { text, toolName, toolCallId } of iterateToolResultParts(last)) {\n await classifyOrBlock(text, HookLabel.TOOL_RESPONSE, { toolName, toolCallId });\n }\n return;\n }\n\n // Otherwise, fall back to scanning the most recent user message.\n // Covers: [user], [system, user], [user, assistant(text), user], etc.\n const lastUser = findLastUserMessage(prompt);\n if (!lastUser) {\n return;\n }\n const text = extractContentText(lastUser.content).trim();\n if (!text) {\n return;\n }\n await classifyOrBlock(text, HookLabel.USER_INPUT);\n };\n\n const scanGenerateResult = async (result: VercelGenerateResult): Promise<void> => {\n if (scanOutput && typeof result.text === \"string\" && result.text.length > 0) {\n await classifyOrBlock(result.text, HookLabel.LLM_OUTPUT);\n }\n if (options.scanToolCalls && Array.isArray(result.toolCalls)) {\n for (const call of result.toolCalls) {\n if (!call || typeof call !== \"object\") {\n continue;\n }\n const toolInput = call.args !== undefined ? call.args : call.input;\n const args =\n typeof toolInput === \"string\" ? toolInput : stringifyToolValue(toolInput);\n const toolName = typeof call.toolName === \"string\" ? call.toolName : undefined;\n const toolCallId = typeof call.toolCallId === \"string\" ? call.toolCallId : undefined;\n if (args.trim()) {\n await classifyOrBlock(args, HookLabel.TOOL_CALL, { toolName, toolCallId });\n }\n }\n }\n };\n\n return {\n specificationVersion: \"v3\",\n middlewareVersion: \"v2\",\n\n async wrapGenerate<TResult extends VercelGenerateResult & Record<string, unknown>>({\n params,\n doGenerate,\n }: WrapGenerateArgs<TResult>): Promise<TResult> {\n if (scanInput) {\n await scanPrompt(params.prompt ?? []);\n }\n const result = await doGenerate();\n await scanGenerateResult(result);\n return result;\n },\n\n async wrapStream<TResult extends { stream: ReadableStream<unknown> } & Record<string, unknown>>({\n params,\n doStream,\n }: WrapStreamArgs<TResult>): Promise<TResult> {\n if (scanInput) {\n await scanPrompt(params.prompt ?? []);\n }\n const { stream, ...rest } = await doStream();\n if (!scanOutput) {\n return { stream, ...rest } as unknown as TResult;\n }\n\n let buffered = \"\";\n const transformed = stream.pipeThrough(\n new TransformStream<unknown, unknown>({\n transform(chunk, controller): void {\n const part = chunk as StreamPart;\n if (part && part.type === \"text-delta\") {\n const delta = part.textDelta ?? part.delta ?? \"\";\n buffered += delta;\n }\n controller.enqueue(chunk);\n },\n async flush(controller): Promise<void> {\n if (!buffered.trim()) {\n return;\n }\n try {\n await classifyOrBlock(buffered, HookLabel.LLM_OUTPUT);\n } catch (err) {\n if (err instanceof FirewallBlockedException) {\n controller.enqueue({ type: \"error\", error: err });\n return;\n }\n throw err;\n }\n },\n }),\n );\n return { stream: transformed, ...rest } as unknown as TResult;\n },\n };\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport const Outcome = {\n Benign: \"benign\",\n InformationDisclosure: \"information_disclosure\",\n SecretExposure: \"secret_exposure\",\n ControlAbuse: \"control_abuse\",\n SystemCompromise: \"system_compromise\",\n ServiceDisruption: \"service_disruption\",\n CodeGeneration: \"code_generation\",\n StoryScriptGeneration: \"story_script_generation\",\n GameGeneration: \"game_generation\",\n WebsiteGeneration: \"website_generation\",\n ClickUpTermsViolation: \"clickup_terms_violation\",\n TraditionalAiAbuse: \"traditional_ai_abuse\",\n} as const;\n\ndeclare const unknownOutcomeBrand: unique symbol;\n\nexport type KnownPrimaryOutcome = (typeof Outcome)[keyof typeof Outcome];\nexport type KnownHarmfulOutcome = Exclude<KnownPrimaryOutcome, typeof Outcome.Benign>;\nexport type UnknownOutcome = string & { readonly [unknownOutcomeBrand]: \"UnknownOutcome\" };\nexport type PrimaryOutcome = KnownPrimaryOutcome | UnknownOutcome;\nexport type HarmfulOutcome = KnownHarmfulOutcome | UnknownOutcome;\n\nexport const PRIMARY_OUTCOMES = [\n Outcome.Benign,\n Outcome.InformationDisclosure,\n Outcome.SecretExposure,\n Outcome.ControlAbuse,\n Outcome.SystemCompromise,\n Outcome.ServiceDisruption,\n Outcome.CodeGeneration,\n Outcome.StoryScriptGeneration,\n Outcome.GameGeneration,\n Outcome.WebsiteGeneration,\n Outcome.ClickUpTermsViolation,\n Outcome.TraditionalAiAbuse,\n] as const satisfies readonly PrimaryOutcome[];\n\nexport const HARMFUL_OUTCOMES = [\n Outcome.InformationDisclosure,\n Outcome.SecretExposure,\n Outcome.ControlAbuse,\n Outcome.SystemCompromise,\n Outcome.ServiceDisruption,\n Outcome.CodeGeneration,\n Outcome.StoryScriptGeneration,\n Outcome.GameGeneration,\n Outcome.WebsiteGeneration,\n Outcome.ClickUpTermsViolation,\n Outcome.TraditionalAiAbuse,\n] as const satisfies readonly KnownHarmfulOutcome[];\n\nexport const OUTCOME_DESCRIPTIONS = {\n [Outcome.Benign]: \"No harmful firewall outcome detected.\",\n [Outcome.InformationDisclosure]:\n \"Exposes private data, documents, internal context, logs, traces, customer data, SQL rows, topology, or similar non-secret sensitive information.\",\n [Outcome.SecretExposure]:\n \"Exposes credentials, tokens, API keys, cookies, passwords, signing keys, OAuth secrets, session material, or webhook secrets.\",\n [Outcome.ControlAbuse]:\n \"Misuses authorized tools or user privileges to send, change, approve, delete, operate, or bypass policy/RBAC without a stronger outcome.\",\n [Outcome.SystemCompromise]:\n \"Enables privilege escalation, account takeover, hostile integration or plugin takeover, persistence, lateral movement, attacker webhook registration, or code/plugin execution.\",\n [Outcome.ServiceDisruption]:\n \"Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence.\",\n [Outcome.CodeGeneration]:\n \"Requests generation or material modification of executable code, scripts, workflows, or configuration.\",\n [Outcome.StoryScriptGeneration]:\n \"Requests generation of narrative prose, dialogue, scripts, or story artifacts.\",\n [Outcome.GameGeneration]:\n \"Requests generation of a game, quest, level, mechanic, or playable experience.\",\n [Outcome.WebsiteGeneration]:\n \"Requests generation of a website, landing page, storefront, or web experience.\",\n [Outcome.ClickUpTermsViolation]:\n \"Requests content or actions that violate the configured ClickUp tenant policy.\",\n [Outcome.TraditionalAiAbuse]:\n \"Requests unsafe AI assistance outside the concrete security outcome classes.\",\n} as const satisfies Readonly<Record<KnownPrimaryOutcome, string>>;\n\nconst PRIMARY_OUTCOME_SET = new Set<string>(PRIMARY_OUTCOMES);\nconst HARMFUL_OUTCOME_SET = new Set<string>(HARMFUL_OUTCOMES);\n\nexport function isPrimaryOutcome(value: unknown): value is KnownPrimaryOutcome {\n return typeof value === \"string\" && PRIMARY_OUTCOME_SET.has(value);\n}\n\nexport function isHarmfulOutcome(value: unknown): value is KnownHarmfulOutcome {\n return typeof value === \"string\" && HARMFUL_OUTCOME_SET.has(value);\n}\n\nexport function normalizePrimaryOutcome(\n value: unknown,\n fieldName = \"primary_outcome\",\n): PrimaryOutcome {\n if (typeof value !== \"string\") {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(value)}`);\n }\n return isPrimaryOutcome(value) ? value : (value as UnknownOutcome);\n}\n\nexport function normalizeHarmfulOutcome(\n value: unknown,\n fieldName = \"outcome\",\n): HarmfulOutcome {\n if (typeof value !== \"string\" || value === Outcome.Benign) {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(value)}`);\n }\n return isHarmfulOutcome(value) ? value : (value as UnknownOutcome);\n}\n\nexport function normalizeHarmfulOutcomeMap(\n values: unknown,\n fieldName: string,\n): Readonly<Partial<Record<HarmfulOutcome, number>>> | undefined {\n if (values === undefined || values === null) {\n return undefined;\n }\n if (typeof values !== \"object\" || Array.isArray(values)) {\n throw new Error(`Firewall: invalid ${fieldName} ${JSON.stringify(values)}`);\n }\n const out: Partial<Record<HarmfulOutcome, number>> = {};\n for (const [key, value] of Object.entries(values)) {\n const normalizedKey = normalizeHarmfulOutcome(key, `${fieldName} key`);\n if (typeof value !== \"number\") {\n throw new Error(`Firewall: invalid ${fieldName} value for ${JSON.stringify(key)}`);\n }\n out[normalizedKey] = value;\n }\n return Object.freeze(out);\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nfunction isHighSurrogate(code: number): boolean {\n return code >= 0xd800 && code <= 0xdbff;\n}\n\nfunction isLowSurrogate(code: number): boolean {\n return code >= 0xdc00 && code <= 0xdfff;\n}\n\nexport function sanitizeText(text: string): string {\n let out = \"\";\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (isHighSurrogate(code)) {\n if (i + 1 < text.length && isLowSurrogate(text.charCodeAt(i + 1))) {\n out += text[i]!;\n out += text[i + 1]!;\n i++;\n }\n continue;\n }\n if (!isLowSurrogate(code)) {\n out += text[i]!;\n }\n }\n return out;\n}\n","// Copyright (c) 2024-2025 Silmaril Security Inc. All rights reserved.\n// PROPRIETARY AND CONFIDENTIAL\n\nexport {\n Firewall,\n DEFAULT_TIMEOUT_MS,\n} from \"./firewall.js\";\n\nexport { FirewallBlockedException, PromptBlockedException, SilmarilApiError } from \"./exceptions.js\";\nexport type { MalformedInputDetails } from \"./exceptions.js\";\n\nexport type { FirewallMiddleware } from \"./adapters/vercel.js\";\n\nexport {\n HookLabel,\n FirewallHook,\n DEFAULT_HOOKS,\n INPUT_HOOKS,\n OUTPUT_HOOKS,\n ALL_HOOKS,\n FIREWALL_HOOK_TO_LABEL,\n resolveHooks,\n prependHook,\n prependToolName,\n} from \"./hooks.js\";\n\nexport {\n Outcome,\n PRIMARY_OUTCOMES,\n HARMFUL_OUTCOMES,\n OUTCOME_DESCRIPTIONS,\n isPrimaryOutcome,\n isHarmfulOutcome,\n normalizePrimaryOutcome,\n normalizeHarmfulOutcome,\n normalizeHarmfulOutcomeMap,\n} from \"./outcomes.js\";\n\nexport type {\n KnownPrimaryOutcome,\n KnownHarmfulOutcome,\n PrimaryOutcome,\n HarmfulOutcome,\n UnknownOutcome,\n} from \"./outcomes.js\";\n\nexport type {\n BlockResult,\n ClassifyEvent,\n Prediction,\n FirewallMode,\n ClassificationMetadata,\n FirewallOptions,\n ClassifyOptions,\n ClassifyBatchOptions,\n LangChainAdapterOptions,\n LangChainFirewallHandler,\n MiddlewareOptions,\n} from \"./types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;AAsGA,SAAS,eAAe,MAItB;AACA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,aAAO,EAAE,SAAS,QAAW,OAAO,QAAW,YAAY,OAAU;AAAA,IACvE;AACA,UAAM,OAAO;AACb,WAAO;AAAA,MACL,SACE,KAAK,WAAW,OAAO,KAAK,YAAY,WACnC,KAAK,UACN;AAAA,MACN,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,MACrD,YAAY,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAAA,IAChE;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,SAAS,QAAW,OAAO,QAAW,YAAY,OAAU;AAAA,EACvE;AACF;AA5HA,IAMM,wBAWO,0BAmDA,wBAIA;AAxEb;AAAA;AAAA;AAMA,IAAM,yBAAyB;AAWxB,IAAM,2BAAN,MAAM,kCAAiC,MAAM;AAAA,MACzC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAET,YAAY,QAST;AACD,cAAM,0BAAyB,cAAc,MAAM,CAAC;AACpD,aAAK,OAAO;AACZ,aAAK,QAAQ,OAAO;AACpB,aAAK,YAAY,OAAO;AACxB,aAAK,aAAa,OAAO;AACzB,aAAK,QAAQ,OAAO;AACpB,aAAK,OAAO,OAAO;AACnB,aAAK,WAAW,OAAO;AACvB,aAAK,aAAa,OAAO;AACzB,aAAK,SAAS,OAAO;AACrB,eAAO,eAAe,MAAM,0BAAyB,SAAS;AAAA,MAChE;AAAA,MAEA,OAAe,cAAc,QAIlB;AACT,cAAM,YACJ,OAAO,WAAW,SAAS,yBACvB,GAAG,OAAO,WAAW,MAAM,GAAG,sBAAsB,CAAC,QACrD,OAAO;AACb,eACE,+CACU,OAAO,MAAM,QAAQ,CAAC,CAAC,eAAe,OAAO,UAAU,QAAQ,CAAC,CAAC,OACvE,SAAS;AAAA,MAEjB;AAAA,IACF;AAGO,IAAM,yBAAyB;AAI/B,IAAM,mBAAN,MAAM,0BAAyB,MAAM;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAET,YAAY,QAOT;AACD,cAAM,aAAa,OAAO,aAAa,IAAI,OAAO,UAAU,KAAK;AACjE,cAAM,sBAAsB,OAAO,MAAM,GAAG,UAAU,EAAE;AACxD,aAAK,OAAO;AACZ,aAAK,SAAS,OAAO;AACrB,aAAK,aAAa,OAAO;AACzB,aAAK,OAAO,OAAO;AACnB,cAAM,SAAS,eAAe,OAAO,IAAI;AACzC,aAAK,UAAU,OAAO,WAAW,OAAO;AACxC,aAAK,QAAQ,OAAO,SAAS,OAAO;AACpC,aAAK,aAAa,OAAO,cAAc,OAAO;AAC9C,eAAO,eAAe,MAAM,kBAAiB,SAAS;AAAA,MACxD;AAAA,IACF;AAAA;AAAA;;;ACvCO,SAAS,aACd,OAC2B;AAC3B,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,oBAAI,IAAkB;AACvC,aAAW,KAAK,OAAO;AACrB,QAAI,CAAC,qBAAqB,IAAI,CAAC,GAAG;AAChC,YAAM,IAAI,MAAM,+BAA+B,OAAO,CAAC,CAAC,EAAE;AAAA,IAC5D;AACA,aAAS,IAAI,CAAiB;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,YAAY,MAAc,MAAqD;AAC7F,MAAI,SAAS,UAAa,SAAS,MAAM;AACvC,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAU,SAAS;AAC9B,WAAO;AAAA,EACT;AACA,SAAO,SAAS,IAAI,KAAK,IAAI;AAC/B;AAEO,SAAS,gBAAgB,MAAc,UAA6C;AACzF,MAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,WAAO;AAAA,EACT;AACA,SAAO,SAAS,QAAQ,KAAK,IAAI;AACnC;AA5FA,IAGa,WAWA,cAYA,eAKA,aAOA,cAMA,WAKA,wBAUP;AA3DN;AAAA;AAAA;AAGO,IAAM,YAAY;AAAA,MACvB,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,WAAW;AAAA,MACX,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,SAAS;AAAA,IACX;AAIO,IAAM,eAAe;AAAA,MAC1B,WAAW;AAAA,MACX,kBAAkB;AAAA,MAClB,YAAY;AAAA,MACZ,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,eAAe;AAAA,IACjB;AAIO,IAAM,gBAA2C,oBAAI,IAAkB;AAAA,MAC5E,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAEM,IAAM,cAAyC,oBAAI,IAAkB;AAAA,MAC1E,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAEM,IAAM,eAA0C,oBAAI,IAAkB;AAAA,MAC3E,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAEM,IAAM,YAAuC,oBAAI,IAAkB;AAAA,MACxE,GAAG;AAAA,MACH,GAAG;AAAA,IACL,CAAC;AAEM,IAAM,yBAAoE;AAAA,MAC/E,CAAC,aAAa,gBAAgB,GAAG,UAAU;AAAA,MAC3C,CAAC,aAAa,SAAS,GAAG,UAAU;AAAA,MACpC,CAAC,aAAa,UAAU,GAAG,UAAU;AAAA,MACrC,CAAC,aAAa,QAAQ,GAAG,UAAU;AAAA,MACnC,CAAC,aAAa,eAAe,GAAG,UAAU;AAAA,MAC1C,CAAC,aAAa,aAAa,GAAG,UAAU;AAAA,MACxC,CAAC,aAAa,OAAO,GAAG,UAAU;AAAA,IACpC;AAEA,IAAM,uBAA4C,IAAI,IAAI,OAAO,OAAO,YAAY,CAAC;AAAA;AAAA;;;ACuB9E,SAAS,uBAAuB,SAAoC;AACzE,SAAO,QACJ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1B,KAAK,IAAI;AACd;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,SAAS,KAAK;AACvB;AAEO,SAAS,yBAAyB,UAAsC;AAC7E,QAAM,QAAkB,CAAC;AACzB,aAAW,WAAW,SAAS,eAAe,CAAC,GAAG;AAChD,eAAW,OAAO,SAAS;AACzB,YAAM,QAAQ,IAAI,QAAQ,IAAI,KAAK;AACnC,UAAI,MAAM;AACR,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,yBAAyB,WAAqD;AAC5F,QAAM,QAAkB,CAAC;AACzB,aAAW,OAAO,WAAW;AAC3B,UAAM,QAAQ,IAAI,eAAe,IAAI,KAAK;AAC1C,QAAI,MAAM;AACR,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAnHA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AA6BA,SAAS,eAAe,SAA4C;AAClE,MAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,WAAO,QAAQ,KAAK,YAAY;AAAA,EAClC;AACA,MAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,WAAO,QAAQ,KAAK,YAAY;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,SAAuD;AACjF,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,KAAK,KAAK;AAAA,IAClB,WAAW,SAAS,MAAM,SAAS,QAAQ;AACzC,YAAM,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC7B;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAASA,qBACP,UACuC;AACvC,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAM,MAAM,SAAS,CAAC;AACtB,QAAI,WAAW,IAAI,eAAe,GAAG,CAAC,GAAG;AACvC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,uBACpB,UACA,UAAmC,CAAC,GACN;AAC9B,QAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,gCAAgC;AAE7E,QAAM,eAAe,aAAa,QAAQ,KAAK;AAK/C,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,SACJ,QAAQ,WACP,CAAC,SAAiB,UAAyB;AAE1C,YAAQ,KAAK,sBAAsB,OAAO,IAAI,KAAK;AAAA,EACrD;AACF,QAAM,gBAAgB,QAAQ,SAC5B,QAAQ,eAAe,SACnB,SAAS,OACT,QAAQ,aAAa,WAAW;AAEtC,QAAM,aAAa,QAAQ;AAE3B,QAAM,iBAAiB,CAAC,UAA+B;AACrD,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AACA,QAAI;AACF,iBAAW,KAAK;AAAA,IAClB,SAAS,KAAK;AACZ,aAAO,6BAA6B,GAAG;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,WAAW,OACf,MACA,WACA,OACA,aACkB;AAClB,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,SAAS,SAAS,MAAM;AAAA,QACrC,MAAM;AAAA,QACN,GAAI,kBAAkB,SAAY,EAAE,MAAM,cAAc,IAAI,CAAC;AAAA,QAC7D,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/C,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,CAAC,UAAU;AACb,cAAM;AAAA,MACR;AACA,aAAO,kDAAkD,GAAG;AAC5D;AAAA,IACF;AACA,UAAM,YAAY,OAAO;AACzB,UAAM,UAAU,OAAO,eAAe;AACtC,UAAM,gBAAgB,iBAAiB,OAAO,QAAQ;AACtD,UAAM,oBAAoB;AAAA,MACxB,MAAM;AAAA,MACN,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,mBAAe;AAAA,MACb,GAAG;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,YAAY,kBAAkB;AAAA,IAChC,CAAC;AACD,QAAI,CAAC,WAAW,kBAAkB,SAAS;AACzC;AAAA,IACF;AAEA,UAAM,IAAI,yBAAyB;AAAA,MACjC,OAAO,OAAO;AAAA,MACd;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,MAAM;AAAA,MACN,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gCAAgC,oBAAoB;AAAA,IAC/C,OAAO;AAAA,IACP,aAAa;AAAA,IACb,gBAAgB;AAAA,IAEzB,MAAe,qBACb,MACA,UACA,OACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,gBAAgB,GAAG;AACpD;AAAA,MACF;AACA,YAAM,UAAU;AAChB,YAAM,OAAoC,CAAC;AAC3C,iBAAW,SAAS,SAAS;AAC3B,mBAAW,KAAK,OAAO;AACrB,eAAK,KAAK,CAAC;AAAA,QACb;AAAA,MACF;AACA,YAAM,WAAWA,qBAAoB,IAAI;AACzC,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AACA,YAAM,OAAO,mBAAmB,SAAS,OAAO,EAAE,KAAK;AACvD,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,SAAS,MAAM,uBAAuB,aAAa,gBAAgB,GAAG,KAAK;AAAA,IACnF;AAAA,IAEA,MAAe,eACb,MACA,SACA,OACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,SAAS,GAAG;AAC7C;AAAA,MACF;AACA,YAAM,OAAO,uBAAuB,OAAO;AAC3C,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,SAAS,MAAM,uBAAuB,aAAa,SAAS,GAAG,KAAK;AAAA,IAC5E;AAAA,IAEA,MAAe,gBACb,MACA,UACA,OACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,UAAU,GAAG;AAC9C;AAAA,MACF;AACA,YAAM,OAAO,yBAAyB,QAAQ;AAC9C,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,WAAW,MAAM;AACvB,YAAM,SAAS,MAAM,uBAAuB,aAAa,UAAU,GAAG,OAAO,QAAQ;AAAA,IACvF;AAAA,IAEA,MAAe,qBACb,YACA,OACA,OACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,eAAe,GAAG;AACnD;AAAA,MACF;AACA,YAAM,OAAO,MAAM,KAAK;AACxB,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,SAAS,MAAM,uBAAuB,aAAa,eAAe,GAAG,KAAK;AAAA,IAClF;AAAA,IAEA,MAAe,aAAa,QAAiB,OAA8B;AACzE,UAAI,CAAC,aAAa,IAAI,aAAa,OAAO,GAAG;AAC3C;AAAA,MACF;AACA,YAAM,OAAO,yBAAyB,MAA2E;AACjH,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,SAAS,MAAM,uBAAuB,aAAa,OAAO,GAAG,KAAK;AAAA,IAC1E;AAAA,IAEA,MAAe,cACb,QACA,OACA,cACA,OACA,SACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,QAAQ,GAAG;AAC5C;AAAA,MACF;AACA,YAAM,OAAO,OAAO,MAAM,EAAE,KAAK;AACjC,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,WAAW,SAAS;AAC1B,YAAM,SAAS,MAAM,uBAAuB,aAAa,QAAQ,GAAG,OAAO,QAAQ;AAAA,IACrF;AAAA,IAEA,MAAe,mBACb,WACA,OACe;AACf,UAAI,CAAC,aAAa,IAAI,aAAa,aAAa,GAAG;AACjD;AAAA,MACF;AACA,YAAM,OAAO,yBAAyB,SAAS;AAC/C,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA,YAAM,SAAS,MAAM,uBAAuB,aAAa,aAAa,GAAG,KAAK;AAAA,IAChF;AAAA,EACF;AAEA,SAAO,IAAI,wBAAwB;AACrC;AAtRA,IAqBM;AArBN;AAAA;AAAA;AAMA;AACA;AAOA;AAOA,IAAM,aAAkC,oBAAI,IAAI,CAAC,SAAS,MAAM,CAAC;AAAA;AAAA;;;AClBjE,SAAS,kBAAkB;;;ACC3B;AACA;AAsDA,SAAS,mBAAmB,OAAwB;AAClD,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,mBAAmB,SAAiD;AAC3E,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,KAAK,KAAK;AAAA,IAClB,WAAW,SAAS,MAAM,SAAS,QAAQ;AACzC,YAAM,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC7B;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAS,uBACP,SACuF;AACvF,MAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAA6F,CAAC;AACpG,aAAW,QAAQ,QAAQ,SAAS;AAClC,QAAI,OAAO,SAAS,UAAU;AAC5B;AAAA,IACF;AACA,QAAI,KAAK,SAAS,eAAe;AAC/B,YAAM,OAAO,oBAAoB,KAAK,WAAW,SAAY,KAAK,SAAS,KAAK,MAAM;AACtF,UAAI,KAAK,KAAK,GAAG;AACf,YAAI,KAAK,EAAE,MAAM,UAAU,KAAK,UAAU,YAAY,KAAK,WAAW,CAAC;AAAA,MACzE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,OAAwB;AACnD,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO,mBAAmB,KAAK;AAAA,EACjC;AACA,OAAK,MAAM,SAAS,UAAU,MAAM,SAAS,iBAAiB,OAAO,MAAM,UAAU,UAAU;AAC7F,WAAO,MAAM;AAAA,EACf;AACA,OAAK,MAAM,SAAS,UAAU,MAAM,SAAS,iBAAiB,MAAM,UAAU,QAAW;AACvF,WAAO,mBAAmB,MAAM,KAAK;AAAA,EACvC;AACA,MAAI,MAAM,SAAS,aAAa,MAAM,QAAQ,MAAM,KAAK,GAAG;AAC1D,WAAO,MAAM,MACV,IAAI,CAAC,SAAU,SAAS,IAAI,KAAK,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,EAAG,EACxG,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAChC,KAAK,GAAG;AAAA,EACb;AACA,SAAO,mBAAmB,KAAK;AACjC;AAEA,SAAS,oBACP,UACiC;AACjC,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAM,MAAM,SAAS,CAAC;AACtB,QAAI,IAAI,KAAK,YAAY,MAAM,QAAQ;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,iBACd,UACA,UAA6B,CAAC,GACV;AACpB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,gBAAgB,QAAQ,SAC5B,QAAQ,eAAe,SACnB,SAAS,OACT,QAAQ,aAAa,WAAW;AAGtC,QAAM,kBAAkB,OACtB,MACA,MACA,UAA6B,EAAE,UAAU,QAAW,YAAY,OAAU,MACxD;AAClB,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB;AAAA,IACF;AACA,UAAM,EAAE,UAAU,WAAW,IAAI;AACjC,UAAM,SAAsB,MAAM,SAAS;AAAA,MACzC;AAAA,MACA;AAAA,QACE;AAAA,QACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7C,GAAI,kBAAkB,SAAY,EAAE,MAAM,cAAc,IAAI,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,UAAM,YAAY,OAAO;AACzB,UAAM,UAAU,OAAO,eAAe;AACtC,UAAM,gBAAgB,iBAAiB,OAAO,QAAQ;AACtD,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,MACjD;AAAA,MACA;AAAA,IACF;AACA,YAAQ,aAAa;AAAA,MACnB,GAAG;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,YAAY,kBAAkB;AAAA,IAChC,CAAC;AACD,QAAI,CAAC,WAAW,kBAAkB,SAAS;AACzC;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,yBAAyB;AAAA,MACvC,OAAO,OAAO;AAAA,MACd;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,MACjD;AAAA,IACF,CAAC;AACD,YAAQ,YAAY,GAAG;AACvB,UAAM;AAAA,EACR;AAEA,QAAM,aAAa,OAAO,WAA8D;AACtF,QAAI,OAAO,WAAW,GAAG;AACvB;AAAA,IACF;AACA,UAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,UAAM,OAAO,KAAK,KAAK,YAAY;AAMnC,QAAI,SAAS,QAAQ;AACnB,iBAAW,EAAE,MAAAC,OAAM,UAAU,WAAW,KAAK,uBAAuB,IAAI,GAAG;AACzE,cAAM,gBAAgBA,OAAM,UAAU,eAAe,EAAE,UAAU,WAAW,CAAC;AAAA,MAC/E;AACA;AAAA,IACF;AAIA,UAAM,WAAW,oBAAoB,MAAM;AAC3C,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,UAAM,OAAO,mBAAmB,SAAS,OAAO,EAAE,KAAK;AACvD,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AACA,UAAM,gBAAgB,MAAM,UAAU,UAAU;AAAA,EAClD;AAEA,QAAM,qBAAqB,OAAO,WAAgD;AAChF,QAAI,cAAc,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,SAAS,GAAG;AAC3E,YAAM,gBAAgB,OAAO,MAAM,UAAU,UAAU;AAAA,IACzD;AACA,QAAI,QAAQ,iBAAiB,MAAM,QAAQ,OAAO,SAAS,GAAG;AAC5D,iBAAW,QAAQ,OAAO,WAAW;AACnC,YAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC;AAAA,QACF;AACA,cAAM,YAAY,KAAK,SAAS,SAAY,KAAK,OAAO,KAAK;AAC7D,cAAM,OACJ,OAAO,cAAc,WAAW,YAAY,mBAAmB,SAAS;AAC1E,cAAM,WAAW,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;AACrE,cAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC3E,YAAI,KAAK,KAAK,GAAG;AACf,gBAAM,gBAAgB,MAAM,UAAU,WAAW,EAAE,UAAU,WAAW,CAAC;AAAA,QAC3E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IAEnB,MAAM,aAA6E;AAAA,MACjF;AAAA,MACA;AAAA,IACF,GAAgD;AAC9C,UAAI,WAAW;AACb,cAAM,WAAW,OAAO,UAAU,CAAC,CAAC;AAAA,MACtC;AACA,YAAM,SAAS,MAAM,WAAW;AAChC,YAAM,mBAAmB,MAAM;AAC/B,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,WAA0F;AAAA,MAC9F;AAAA,MACA;AAAA,IACF,GAA8C;AAC5C,UAAI,WAAW;AACb,cAAM,WAAW,OAAO,UAAU,CAAC,CAAC;AAAA,MACtC;AACA,YAAM,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM,SAAS;AAC3C,UAAI,CAAC,YAAY;AACf,eAAO,EAAE,QAAQ,GAAG,KAAK;AAAA,MAC3B;AAEA,UAAI,WAAW;AACf,YAAM,cAAc,OAAO;AAAA,QACzB,IAAI,gBAAkC;AAAA,UACpC,UAAU,OAAO,YAAkB;AACjC,kBAAM,OAAO;AACb,gBAAI,QAAQ,KAAK,SAAS,cAAc;AACtC,oBAAM,QAAQ,KAAK,aAAa,KAAK,SAAS;AAC9C,0BAAY;AAAA,YACd;AACA,uBAAW,QAAQ,KAAK;AAAA,UAC1B;AAAA,UACA,MAAM,MAAM,YAA2B;AACrC,gBAAI,CAAC,SAAS,KAAK,GAAG;AACpB;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,gBAAgB,UAAU,UAAU,UAAU;AAAA,YACtD,SAAS,KAAK;AACZ,kBAAI,eAAe,0BAA0B;AAC3C,2BAAW,QAAQ,EAAE,MAAM,SAAS,OAAO,IAAI,CAAC;AAChD;AAAA,cACF;AACA,oBAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO,EAAE,QAAQ,aAAa,GAAG,KAAK;AAAA,IACxC;AAAA,EACF;AACF;;;ADjUA;;;AEHO,IAAM,UAAU;AAAA,EACrB,QAAQ;AAAA,EACR,uBAAuB;AAAA,EACvB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,oBAAoB;AACtB;AAUO,IAAM,mBAAmB;AAAA,EAC9B,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,IAAM,mBAAmB;AAAA,EAC9B,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,IAAM,uBAAuB;AAAA,EAClC,CAAC,QAAQ,MAAM,GAAG;AAAA,EAClB,CAAC,QAAQ,qBAAqB,GAC5B;AAAA,EACF,CAAC,QAAQ,cAAc,GACrB;AAAA,EACF,CAAC,QAAQ,YAAY,GACnB;AAAA,EACF,CAAC,QAAQ,gBAAgB,GACvB;AAAA,EACF,CAAC,QAAQ,iBAAiB,GACxB;AAAA,EACF,CAAC,QAAQ,cAAc,GACrB;AAAA,EACF,CAAC,QAAQ,qBAAqB,GAC5B;AAAA,EACF,CAAC,QAAQ,cAAc,GACrB;AAAA,EACF,CAAC,QAAQ,iBAAiB,GACxB;AAAA,EACF,CAAC,QAAQ,qBAAqB,GAC5B;AAAA,EACF,CAAC,QAAQ,kBAAkB,GACzB;AACJ;AAEA,IAAM,sBAAsB,IAAI,IAAY,gBAAgB;AAC5D,IAAM,sBAAsB,IAAI,IAAY,gBAAgB;AAErD,SAAS,iBAAiB,OAA8C;AAC7E,SAAO,OAAO,UAAU,YAAY,oBAAoB,IAAI,KAAK;AACnE;AAEO,SAAS,iBAAiB,OAA8C;AAC7E,SAAO,OAAO,UAAU,YAAY,oBAAoB,IAAI,KAAK;AACnE;AAEO,SAAS,wBACd,OACA,YAAY,mBACI;AAChB,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,EAC3E;AACA,SAAO,iBAAiB,KAAK,IAAI,QAAS;AAC5C;AAEO,SAAS,wBACd,OACA,YAAY,WACI;AAChB,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,QAAQ;AACzD,UAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,EAC3E;AACA,SAAO,iBAAiB,KAAK,IAAI,QAAS;AAC5C;AAEO,SAAS,2BACd,QACA,WAC+D;AAC/D,MAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACvD,UAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC5E;AACA,QAAM,MAA+C,CAAC;AACtD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAM,gBAAgB,wBAAwB,KAAK,GAAG,SAAS,MAAM;AACrE,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,IAAI,MAAM,qBAAqB,SAAS,cAAc,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,IACnF;AACA,QAAI,aAAa,IAAI;AAAA,EACvB;AACA,SAAO,OAAO,OAAO,GAAG;AAC1B;;;AChIA,SAAS,gBAAgB,MAAuB;AAC9C,SAAO,QAAQ,SAAU,QAAQ;AACnC;AAEA,SAAS,eAAe,MAAuB;AAC7C,SAAO,QAAQ,SAAU,QAAQ;AACnC;AAEO,SAAS,aAAa,MAAsB;AACjD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,OAAO,KAAK,WAAW,CAAC;AAC9B,QAAI,gBAAgB,IAAI,GAAG;AACzB,UAAI,IAAI,IAAI,KAAK,UAAU,eAAe,KAAK,WAAW,IAAI,CAAC,CAAC,GAAG;AACjE,eAAO,KAAK,CAAC;AACb,eAAO,KAAK,IAAI,CAAC;AACjB;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,CAAC,eAAe,IAAI,GAAG;AACzB,aAAO,KAAK,CAAC;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;;;AHNO,IAAM,cAAc;AACpB,IAAM,qBAAqB;AAClC,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,uBAAuB,KAAK;AAiClC,SAAS,YAAY,OAAgB,eAAwD;AAC3F,MAAI;AACJ,MAAI,UAAU,YAAY,UAAU,UAAU,UAAU,SAAS;AAC/D,mBAAe;AAAA,EACjB,WAAW,UAAU,QAAW;AAC9B,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AAKA,SAAO,iBAAiB;AAC1B;AAEA,SAAS,WAAW,YAA2D;AAC7E,SAAO,eAAe,SAAY,SAAY,aAAa,WAAW;AACxE;AAEA,SAAS,wBACP,MACA,eACa;AACb,MAAI,KAAK,eAAe,YAAY,KAAK,eAAe,aAAa;AACnE,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AACA,QAAM,SASF;AAAA,IACF,YAAY,KAAK;AAAA,IACjB,OAAO,OAAO,KAAK,KAAK;AAAA,IACxB,WAAW,OAAO,KAAK,SAAS;AAAA,EAClC;AACA,QAAM,OAAO,YAAY,KAAK,MAAM,aAAa;AACjD,MAAI,SAAS,QAAW;AACtB,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,KAAK,oBAAoB,QAAW;AACtC,WAAO,iBAAiB,wBAAwB,KAAK,eAAe;AAAA,EACtE;AACA,MAAI,KAAK,mBAAmB,QAAW;AACrC,UAAM,gBAAgB,2BAA2B,KAAK,gBAAgB,gBAAgB;AACtF,QAAI,kBAAkB,QAAW;AAC/B,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF;AACA,MAAI,KAAK,oBAAoB,QAAW;AACtC,UAAM,iBAAiB,2BAA2B,KAAK,iBAAiB,iBAAiB;AACzF,QAAI,mBAAmB,QAAW;AAChC,aAAO,iBAAiB;AAAA,IAC1B;AAAA,EACF;AACA,MAAI,KAAK,oBAAoB,QAAW;AACtC,UAAM,iBAAiB,2BAA2B,KAAK,iBAAiB,iBAAiB;AACzF,QAAI,mBAAmB,QAAW;AAChC,aAAO,iBAAiB;AAAA,IAC1B;AAAA,EACF;AACA,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEA,SAASC,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,gBACP,UACA,MAIwB;AACxB,QAAM,UAAmC,EAAE,GAAI,YAAY,CAAC,EAAG;AAC/D,QAAM,WAAW,QAAQ;AACzB,MAAI,aAAa,UAAa,CAACA,UAAS,QAAQ,GAAG;AACjD,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,UAAQ,WAAW;AAAA,IACjB,GAAIA,UAAS,QAAQ,IAAI,WAAW,CAAC;AAAA,IACrC,cAAc;AAAA,IACd,aAAa;AAAA,IACb,YAAY,KAAK;AAAA,IACjB,GAAI,KAAK,eAAe,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,WAAW;AAAA,EAC1E;AACA,SAAO;AACT;AAEA,eAAe,oBAAoB,UAAqC;AACtE,MAAI,CAAC,SAAS,MAAM;AAClB,WAAO,SAAS,KAAK,EAAE,KAAK,CAACC,UAASA,MAAK,MAAM,GAAG,oBAAoB,CAAC,EAAE,MAAM,MAAM,EAAE;AAAA,EAC3F;AAEA,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAM,SAAuB,CAAC;AAC9B,MAAI,YAAY;AAChB,MAAI;AACF,WAAO,YAAY,GAAG;AACpB,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,MAAM;AACR;AAAA,MACF;AACA,UAAI,CAAC,OAAO;AACV;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,aAAa,YAAY,MAAM,MAAM,GAAG,SAAS,IAAI;AACzE,aAAO,KAAK,KAAK;AACjB,mBAAa,MAAM;AACnB,UAAI,MAAM,aAAa,MAAM,YAAY;AACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,UAAM,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAAA,EAC7C;AAEA,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,YAAY,CAAC;AACrE,QAAM,OAAO,IAAI,WAAW,KAAK;AACjC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,SAAK,IAAI,OAAO,MAAM;AACtB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACtC;AAEO,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EAEjB,YAAY,SAA0B;AACpC,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ;AACtB,SAAK,YAAY,QAAQ,aAAa;AACtC,QAAI,OAAO,KAAK,cAAc,YAAY,CAAC,OAAO,SAAS,KAAK,SAAS,KAAK,KAAK,YAAY,GAAG;AAChG,YAAM,IAAI,MAAM,iEAAiE,KAAK,SAAS,EAAE;AAAA,IACnG;AACA,SAAK,OAAO,QAAQ,QAAQ,WAAW,QAAQ,UAAU;AACzD,SAAK,aAAa,KAAK,SAAS;AAChC,SAAK,UAAU,OAAO,OAAO;AAAA,MAC3B,aAAa,KAAK;AAAA,MAClB,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SAAS,MAAc,UAA2B,CAAC,GAAyB;AAChF,UAAM,YAAY,QAAQ,aAAa,WAAW;AAClD,WAAO,KAAK,eAAe,aAAa,IAAI,GAAG,SAAS,EAAE,UAAU,CAAC;AAAA,EACvE;AAAA,EAEA,MAAM,cACJ,OACA,UAAgC,CAAC,GACT;AACxB,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AACA,QAAI,QAAQ,UAAU,UAAa,QAAQ,MAAM,WAAW,MAAM,QAAQ;AACxE,YAAM,IAAI;AAAA,QACR,0BAA0B,QAAQ,MAAM,MAAM,gCAAgC,MAAM,MAAM;AAAA,MAC5F;AAAA,IACF;AACA,QAAI,QAAQ,cAAc,UAAa,QAAQ,UAAU,WAAW,MAAM,QAAQ;AAChF,YAAM,IAAI;AAAA,QACR,8BAA8B,QAAQ,UAAU,MAAM,gCAAgC,MAAM,MAAM;AAAA,MACpG;AAAA,IACF;AACA,QAAI,QAAQ,aAAa,UAAa,QAAQ,SAAS,WAAW,MAAM,QAAQ;AAC9E,YAAM,IAAI;AAAA,QACR,6BAA6B,QAAQ,SAAS,MAAM,gCAAgC,MAAM,MAAM;AAAA,MAClG;AAAA,IACF;AAEA,UAAM,YAAY,QAAQ,aAAa,WAAW;AAClD,UAAM,UAAgC;AAAA,MACpC,OAAO,MAAM,IAAI,CAAC,SAAS,aAAa,IAAI,CAAC;AAAA,IAC/C;AACA,UAAM,gBAAgB,QAAQ,QAAQ,KAAK;AAC3C,QAAI,kBAAkB,QAAW;AAC/B,cAAQ,OAAO;AAAA,IACjB;AACA,QAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC7C,cAAQ,QAAQ,QAAQ,MAAM,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;AAAA,IACpD;AACA,QAAI,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;AACrD,cAAQ,aAAa,QAAQ,UAAU,IAAI,CAAC,MAAO,MAAM,SAAY,OAAO,CAAE;AAAA,IAChF;AACA,YAAQ,WAAW,MAAM;AAAA,MAAI,CAAC,GAAG,UAC/B,gBAAgB,QAAQ,WAAW,KAAK,GAAG;AAAA,QACzC;AAAA,QACA,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AACA,UAAM,OAAO,MAAM,KAAK,cAAqC,OAAO;AACpE,WAAO,KAAK,YAAY,IAAI,CAAC,MAAM,wBAAwB,GAAG,aAAa,CAAC;AAAA,EAC9E;AAAA,EAEA,mBACE,UAAmC,CAAC,GACjB;AACnB,WAAO,oEAAkC;AAAA,MAAK,CAAC,MAC7C,EAAE,uBAAuB,MAAM,OAAO;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,aAAa,UAA6B,CAAC,GAAuB;AAChE,WAAO,iBAAiB,MAAM,OAAO;AAAA,EACvC;AAAA,EAEA,MAAc,cACZ,SACA,aAAqB,qBACT;AACZ,aAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,YAAM,WAAW,MAAM,MAAM,KAAK,QAAQ;AAAA,QACxC,QAAQ;AAAA,QACR,SAAS,KAAK;AAAA,QACd,MAAM,KAAK,UAAU,OAAO;AAAA,QAC5B,UAAU;AAAA,QACV,QAAQ,YAAY,QAAQ,KAAK,SAAS;AAAA,MAC5C,CAAC;AACD,UAAI,SAAS,WAAW,OAAO,YAAY,YAAY;AACrD,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,OAAO,MAAM,oBAAoB,QAAQ;AAC/C,gBAAM,IAAI,iBAAiB;AAAA,YACzB,QAAQ,SAAS;AAAA,YACjB,YAAY,SAAS;AAAA,YACrB;AAAA,UACF,CAAC;AAAA,QACH;AACA,eAAQ,MAAM,SAAS,KAAK;AAAA,MAC9B;AACA,YAAM,cAAc,KAAK,IAAI,KAAK,SAAS,mBAAmB;AAC9D,YAAM,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,cAAc,GAAI,CAAC;AAAA,IAC9E;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAAA,EAEA,MAAc,eACZ,MACA,SACA,cAGsB;AACtB,UAAM,UAAiC,EAAE,KAAK;AAC9C,UAAM,gBAAgB,QAAQ,QAAQ,KAAK;AAC3C,QAAI,kBAAkB,QAAW;AAC/B,cAAQ,OAAO;AAAA,IACjB;AACA,QAAI,QAAQ,SAAS,QAAW;AAC9B,cAAQ,OAAO,QAAQ;AAAA,IACzB;AACA,QAAI,QAAQ,aAAa,QAAW;AAClC,cAAQ,YAAY,QAAQ;AAAA,IAC9B;AACA,YAAQ,WAAW,gBAAgB,QAAQ,UAAU,YAAY;AACjE,UAAM,OAAO,MAAM,KAAK,cAAsC,OAAO;AACrE,WAAO,wBAAwB,MAAM,aAAa;AAAA,EACpD;AACF;;;AIzUA;AAKA;","names":["findLastUserMessage","text","isRecord","body"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silmaril-security/sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "TypeScript SDK for Silmaril Firewall — prompt injection and jailbreak detection",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Silmaril Security Inc.",
@@ -103,12 +103,12 @@
103
103
  "eslint": "^8.57.0",
104
104
  "tsup": "^8.0.0",
105
105
  "typescript": "^5.4.0",
106
- "undici": "^6.15.0",
106
+ "undici": "^6.28.0",
107
107
  "vite": "6.4.3",
108
108
  "vitest": "3.2.6"
109
109
  },
110
110
  "overrides": {
111
111
  "esbuild": "0.28.1",
112
- "js-yaml": "4.2.0"
112
+ "js-yaml": "4.3.1"
113
113
  }
114
114
  }