@sandrobuilds/tracerney 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +702 -0
  2. package/dist/application/ShieldApplicationService.d.ts +94 -0
  3. package/dist/application/ShieldApplicationService.d.ts.map +1 -0
  4. package/dist/application/ShieldApplicationService.js +223 -0
  5. package/dist/application/ShieldApplicationService.js.map +1 -0
  6. package/dist/application/ShieldBlockError.d.ts +10 -0
  7. package/dist/application/ShieldBlockError.d.ts.map +1 -0
  8. package/dist/application/ShieldBlockError.js +13 -0
  9. package/dist/application/ShieldBlockError.js.map +1 -0
  10. package/dist/application/index.d.ts +9 -0
  11. package/dist/application/index.d.ts.map +1 -0
  12. package/dist/application/index.js +8 -0
  13. package/dist/application/index.js.map +1 -0
  14. package/dist/application/ports/ILLMProvider.d.ts +71 -0
  15. package/dist/application/ports/ILLMProvider.d.ts.map +1 -0
  16. package/dist/application/ports/ILLMProvider.js +15 -0
  17. package/dist/application/ports/ILLMProvider.js.map +1 -0
  18. package/dist/application/ports/IPatternRepository.d.ts +20 -0
  19. package/dist/application/ports/IPatternRepository.d.ts.map +1 -0
  20. package/dist/application/ports/IPatternRepository.js +7 -0
  21. package/dist/application/ports/IPatternRepository.js.map +1 -0
  22. package/dist/application/ports/ISentinel.d.ts +22 -0
  23. package/dist/application/ports/ISentinel.d.ts.map +1 -0
  24. package/dist/application/ports/ISentinel.js +8 -0
  25. package/dist/application/ports/ISentinel.js.map +1 -0
  26. package/dist/application/ports/ITelemetrySink.d.ts +35 -0
  27. package/dist/application/ports/ITelemetrySink.d.ts.map +1 -0
  28. package/dist/application/ports/ITelemetrySink.js +7 -0
  29. package/dist/application/ports/ITelemetrySink.js.map +1 -0
  30. package/dist/application/ports/index.d.ts +10 -0
  31. package/dist/application/ports/index.d.ts.map +1 -0
  32. package/dist/application/ports/index.js +7 -0
  33. package/dist/application/ports/index.js.map +1 -0
  34. package/dist/application/utils/index.d.ts +6 -0
  35. package/dist/application/utils/index.d.ts.map +1 -0
  36. package/dist/application/utils/index.js +6 -0
  37. package/dist/application/utils/index.js.map +1 -0
  38. package/dist/application/utils/jitter.d.ts +10 -0
  39. package/dist/application/utils/jitter.d.ts.map +1 -0
  40. package/dist/application/utils/jitter.js +13 -0
  41. package/dist/application/utils/jitter.js.map +1 -0
  42. package/dist/application/utils/normalizePrompt.d.ts +18 -0
  43. package/dist/application/utils/normalizePrompt.d.ts.map +1 -0
  44. package/dist/application/utils/normalizePrompt.js +36 -0
  45. package/dist/application/utils/normalizePrompt.js.map +1 -0
  46. package/dist/domain/detection/InjectionThreat.d.ts +19 -0
  47. package/dist/domain/detection/InjectionThreat.d.ts.map +1 -0
  48. package/dist/domain/detection/InjectionThreat.js +18 -0
  49. package/dist/domain/detection/InjectionThreat.js.map +1 -0
  50. package/dist/domain/detection/PatternMatcher.d.ts +36 -0
  51. package/dist/domain/detection/PatternMatcher.d.ts.map +1 -0
  52. package/dist/domain/detection/PatternMatcher.js +65 -0
  53. package/dist/domain/detection/PatternMatcher.js.map +1 -0
  54. package/dist/domain/detection/VanguardPattern.d.ts +19 -0
  55. package/dist/domain/detection/VanguardPattern.d.ts.map +1 -0
  56. package/dist/domain/detection/VanguardPattern.js +21 -0
  57. package/dist/domain/detection/VanguardPattern.js.map +1 -0
  58. package/dist/domain/detection/index.d.ts +11 -0
  59. package/dist/domain/detection/index.d.ts.map +1 -0
  60. package/dist/domain/detection/index.js +8 -0
  61. package/dist/domain/detection/index.js.map +1 -0
  62. package/dist/domain/events/SecurityEvent.d.ts +30 -0
  63. package/dist/domain/events/SecurityEvent.d.ts.map +1 -0
  64. package/dist/domain/events/SecurityEvent.js +21 -0
  65. package/dist/domain/events/SecurityEvent.js.map +1 -0
  66. package/dist/domain/events/SecurityEventType.d.ts +13 -0
  67. package/dist/domain/events/SecurityEventType.d.ts.map +1 -0
  68. package/dist/domain/events/SecurityEventType.js +15 -0
  69. package/dist/domain/events/SecurityEventType.js.map +1 -0
  70. package/dist/domain/events/ThreatSeverity.d.ts +13 -0
  71. package/dist/domain/events/ThreatSeverity.d.ts.map +1 -0
  72. package/dist/domain/events/ThreatSeverity.js +15 -0
  73. package/dist/domain/events/ThreatSeverity.js.map +1 -0
  74. package/dist/domain/events/index.d.ts +11 -0
  75. package/dist/domain/events/index.d.ts.map +1 -0
  76. package/dist/domain/events/index.js +8 -0
  77. package/dist/domain/events/index.js.map +1 -0
  78. package/dist/domain/guard/ToolGuard.d.ts +35 -0
  79. package/dist/domain/guard/ToolGuard.d.ts.map +1 -0
  80. package/dist/domain/guard/ToolGuard.js +49 -0
  81. package/dist/domain/guard/ToolGuard.js.map +1 -0
  82. package/dist/domain/guard/ToolPolicy.d.ts +16 -0
  83. package/dist/domain/guard/ToolPolicy.d.ts.map +1 -0
  84. package/dist/domain/guard/ToolPolicy.js +19 -0
  85. package/dist/domain/guard/ToolPolicy.js.map +1 -0
  86. package/dist/domain/guard/ToolViolation.d.ts +14 -0
  87. package/dist/domain/guard/ToolViolation.d.ts.map +1 -0
  88. package/dist/domain/guard/ToolViolation.js +15 -0
  89. package/dist/domain/guard/ToolViolation.js.map +1 -0
  90. package/dist/domain/guard/index.d.ts +11 -0
  91. package/dist/domain/guard/index.d.ts.map +1 -0
  92. package/dist/domain/guard/index.js +8 -0
  93. package/dist/domain/guard/index.js.map +1 -0
  94. package/dist/index.d.ts +168 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +173 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/infrastructure/llm/OpenRouterProvider.d.ts +32 -0
  99. package/dist/infrastructure/llm/OpenRouterProvider.d.ts.map +1 -0
  100. package/dist/infrastructure/llm/OpenRouterProvider.js +119 -0
  101. package/dist/infrastructure/llm/OpenRouterProvider.js.map +1 -0
  102. package/dist/infrastructure/llm/index.d.ts +7 -0
  103. package/dist/infrastructure/llm/index.d.ts.map +1 -0
  104. package/dist/infrastructure/llm/index.js +6 -0
  105. package/dist/infrastructure/llm/index.js.map +1 -0
  106. package/dist/infrastructure/patterns/BundledPatternRepository.d.ts +16 -0
  107. package/dist/infrastructure/patterns/BundledPatternRepository.d.ts.map +1 -0
  108. package/dist/infrastructure/patterns/BundledPatternRepository.js +19 -0
  109. package/dist/infrastructure/patterns/BundledPatternRepository.js.map +1 -0
  110. package/dist/infrastructure/patterns/RemotePatternRepository.d.ts +77 -0
  111. package/dist/infrastructure/patterns/RemotePatternRepository.d.ts.map +1 -0
  112. package/dist/infrastructure/patterns/RemotePatternRepository.js +176 -0
  113. package/dist/infrastructure/patterns/RemotePatternRepository.js.map +1 -0
  114. package/dist/infrastructure/patterns/bundled-patterns.d.ts +9 -0
  115. package/dist/infrastructure/patterns/bundled-patterns.d.ts.map +1 -0
  116. package/dist/infrastructure/patterns/bundled-patterns.js +2082 -0
  117. package/dist/infrastructure/patterns/bundled-patterns.js.map +1 -0
  118. package/dist/infrastructure/patterns/index.d.ts +9 -0
  119. package/dist/infrastructure/patterns/index.d.ts.map +1 -0
  120. package/dist/infrastructure/patterns/index.js +8 -0
  121. package/dist/infrastructure/patterns/index.js.map +1 -0
  122. package/dist/infrastructure/sentinel/LLMSentinel.d.ts +48 -0
  123. package/dist/infrastructure/sentinel/LLMSentinel.d.ts.map +1 -0
  124. package/dist/infrastructure/sentinel/LLMSentinel.js +142 -0
  125. package/dist/infrastructure/sentinel/LLMSentinel.js.map +1 -0
  126. package/dist/infrastructure/telemetry/HttpShadowLogSink.d.ts +30 -0
  127. package/dist/infrastructure/telemetry/HttpShadowLogSink.d.ts.map +1 -0
  128. package/dist/infrastructure/telemetry/HttpShadowLogSink.js +40 -0
  129. package/dist/infrastructure/telemetry/HttpShadowLogSink.js.map +1 -0
  130. package/dist/infrastructure/telemetry/HttpSignalSink.d.ts +51 -0
  131. package/dist/infrastructure/telemetry/HttpSignalSink.d.ts.map +1 -0
  132. package/dist/infrastructure/telemetry/HttpSignalSink.js +134 -0
  133. package/dist/infrastructure/telemetry/HttpSignalSink.js.map +1 -0
  134. package/dist/infrastructure/telemetry/index.d.ts +9 -0
  135. package/dist/infrastructure/telemetry/index.d.ts.map +1 -0
  136. package/dist/infrastructure/telemetry/index.js +7 -0
  137. package/dist/infrastructure/telemetry/index.js.map +1 -0
  138. package/package.json +44 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolGuard.js","sourceRoot":"","sources":["../../../src/domain/guard/ToolGuard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAc,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAiB,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAWrE,MAAM,OAAO,SAAS;IACpB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;QACpC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CACN,SAA0C,EAC1C,SAAiB;QAEjB,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,CAAC,8BAA8B;QAC7C,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;YAExC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC1C,OAAO,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,CAAC,wBAAwB;IACvC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,MAAkB;QAC7B,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tool Policy
3
+ * Domain value object: the allow-list rule set
4
+ */
5
+ export interface ToolPolicy {
6
+ readonly allowedTools: ReadonlySet<string>;
7
+ }
8
+ /**
9
+ * Factory to create a ToolPolicy from an array
10
+ */
11
+ export declare function createToolPolicy(allowedTools: readonly string[]): ToolPolicy;
12
+ /**
13
+ * Check if a tool is allowed by the policy
14
+ */
15
+ export declare function isToolAllowed(policy: ToolPolicy, toolName: string): boolean;
16
+ //# sourceMappingURL=ToolPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolPolicy.d.ts","sourceRoot":"","sources":["../../../src/domain/guard/ToolPolicy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAI5E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3E"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Tool Policy
3
+ * Domain value object: the allow-list rule set
4
+ */
5
+ /**
6
+ * Factory to create a ToolPolicy from an array
7
+ */
8
+ export function createToolPolicy(allowedTools) {
9
+ return {
10
+ allowedTools: new Set(allowedTools),
11
+ };
12
+ }
13
+ /**
14
+ * Check if a tool is allowed by the policy
15
+ */
16
+ export function isToolAllowed(policy, toolName) {
17
+ return policy.allowedTools.has(toolName);
18
+ }
19
+ //# sourceMappingURL=ToolPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolPolicy.js","sourceRoot":"","sources":["../../../src/domain/guard/ToolPolicy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAA+B;IAC9D,OAAO;QACL,YAAY,EAAE,IAAI,GAAG,CAAC,YAAY,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAkB,EAAE,QAAgB;IAChE,OAAO,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool Violation
3
+ * Domain value object: result of a policy breach
4
+ */
5
+ export interface ToolViolation {
6
+ readonly toolName: string;
7
+ readonly requestId: string;
8
+ readonly detectedAt: number;
9
+ }
10
+ /**
11
+ * Factory to create a ToolViolation
12
+ */
13
+ export declare function createToolViolation(toolName: string, requestId: string, detectedAt?: number): ToolViolation;
14
+ //# sourceMappingURL=ToolViolation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolViolation.d.ts","sourceRoot":"","sources":["../../../src/domain/guard/ToolViolation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,aAAa,CAMf"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Tool Violation
3
+ * Domain value object: result of a policy breach
4
+ */
5
+ /**
6
+ * Factory to create a ToolViolation
7
+ */
8
+ export function createToolViolation(toolName, requestId, detectedAt) {
9
+ return {
10
+ toolName,
11
+ requestId,
12
+ detectedAt: detectedAt ?? Date.now(),
13
+ };
14
+ }
15
+ //# sourceMappingURL=ToolViolation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolViolation.js","sourceRoot":"","sources":["../../../src/domain/guard/ToolViolation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,SAAiB,EACjB,UAAmB;IAEnB,OAAO;QACL,QAAQ;QACR,SAAS;QACT,UAAU,EAAE,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Guard Bounded Context
3
+ * Barrel export
4
+ */
5
+ export { createToolPolicy, isToolAllowed } from "./ToolPolicy";
6
+ export type { ToolPolicy } from "./ToolPolicy";
7
+ export { createToolViolation } from "./ToolViolation";
8
+ export type { ToolViolation } from "./ToolViolation";
9
+ export { ToolGuard } from "./ToolGuard";
10
+ export type { ToolCall } from "./ToolGuard";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/guard/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Guard Bounded Context
3
+ * Barrel export
4
+ */
5
+ export { createToolPolicy, isToolAllowed } from './ToolPolicy.js';
6
+ export { createToolViolation } from './ToolViolation.js';
7
+ export { ToolGuard } from './ToolGuard.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/guard/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Tracerny
3
+ * Transparent Proxy Runtime Sentinel for Prompt Injection Defense
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { Tracerny } from 'tracerney';
8
+ *
9
+ * const shield = new Tracerny({
10
+ * allowedTools: ['search', 'calculator'],
11
+ * apiEndpoint: 'https://api.myapp.com/v1/signal',
12
+ * });
13
+ *
14
+ * const response = await shield.wrap(() =>
15
+ * openai.chat.completions.create({...})
16
+ * );
17
+ * ```
18
+ */
19
+ import { type WrapOptions, type ServiceStatus } from "./application";
20
+ import { ShieldBlockError } from "./application/ShieldBlockError";
21
+ import { type LLMResponse } from "./application/ports/ILLMProvider";
22
+ /**
23
+ * Public configuration for Tracerny
24
+ */
25
+ export interface TracernyOptions {
26
+ /**
27
+ * List of tool names the LLM is allowed to call
28
+ */
29
+ allowedTools?: string[];
30
+ /**
31
+ * Base URL for your Tracerny backend (RECOMMENDED)
32
+ * Automatically constructs all required endpoints:
33
+ * - Signal endpoint: {baseUrl}/api/v1/signal
34
+ * - Verification endpoint: {baseUrl}/api/v1/verify-prompt
35
+ * - Shadow log endpoint: {baseUrl}/api/v1/shadow-log
36
+ * - Definitions endpoint: {baseUrl}/api/v1/definitions
37
+ *
38
+ * Example: https://myapp.com or http://localhost:3000
39
+ *
40
+ * If provided, individual endpoint URLs below are ignored.
41
+ */
42
+ baseUrl?: string;
43
+ /**
44
+ * Your backend's Signal Sink endpoint for receiving security events
45
+ * Only needed if NOT using baseUrl
46
+ * Example: https://myapp.com/api/v1/signal
47
+ */
48
+ apiEndpoint?: string;
49
+ /**
50
+ * API key for Signal Sink (optional, sent in Authorization header)
51
+ */
52
+ apiKey?: string;
53
+ /**
54
+ * URL to fetch pattern manifest from (for zero-day updates)
55
+ * If not provided, bundled patterns are used
56
+ */
57
+ manifestUrl?: string;
58
+ /**
59
+ * Enable telemetry reporting (default: true)
60
+ */
61
+ enableTelemetry?: boolean;
62
+ /**
63
+ * Local path to cache manifest (useful in serverless, e.g., /tmp)
64
+ */
65
+ localManifestPath?: string;
66
+ /**
67
+ * Layer 2: Backend endpoint for LLM verification
68
+ * SDK sends suspicious prompts here (backend calls OpenRouter internally)
69
+ * Example: https://myapp.com/api/v1/verify-prompt
70
+ */
71
+ sentinelEndpoint?: string;
72
+ /**
73
+ * Endpoint for shadow log (records of potential attacks)
74
+ * Example: https://myapp.com/api/v1/shadow-log
75
+ */
76
+ shadowLogEndpoint?: string;
77
+ /**
78
+ * Enable Layer 2 LLM Sentinel (default: true if sentinelEndpoint provided)
79
+ */
80
+ sentinelEnabled?: boolean;
81
+ }
82
+ /**
83
+ * Tracerny Facade
84
+ * Main entry point for the SDK
85
+ * Wires all dependencies: domain + application + infrastructure
86
+ */
87
+ export declare class Tracerny {
88
+ private service;
89
+ /**
90
+ * Constructor: wires the full dependency graph
91
+ */
92
+ constructor(options?: TracernyOptions);
93
+ /**
94
+ * Resolves baseUrl into individual endpoint URLs
95
+ * baseUrl takes precedence over individual endpoint options
96
+ */
97
+ private resolveEndpoints;
98
+ /**
99
+ * Main wrapper for LLM calls
100
+ *
101
+ * @param llmCall - Function that executes the LLM call
102
+ * @param options - Optional: prompt for pre-LLM scanning, request context
103
+ *
104
+ * @throws ShieldBlockError if an injection or unauthorized tool is detected
105
+ * @throws Other errors from the LLM provider or network failures
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * // With optional prompt for pre-LLM scanning (fixes Gap 3)
110
+ * const response = await shield.wrap(
111
+ * () => openai.chat.completions.create({...}),
112
+ * { prompt: userInput }
113
+ * );
114
+ * ```
115
+ */
116
+ wrap<T extends LLMResponse>(llmCall: () => Promise<T>, options?: WrapOptions): Promise<T>;
117
+ /**
118
+ * Scan a raw prompt for injection attempts (standalone use)
119
+ *
120
+ * @param prompt - The user input to scan
121
+ * @throws ShieldBlockError if injection is detected
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * try {
126
+ * await shield.scanPrompt(userInput);
127
+ * // Safe to proceed
128
+ * } catch (err) {
129
+ * if (err instanceof ShieldBlockError) {
130
+ * // Attack detected
131
+ * }
132
+ * }
133
+ * ```
134
+ */
135
+ scanPrompt(prompt: string): Promise<void>;
136
+ /**
137
+ * Update allowed tools at runtime
138
+ *
139
+ * @param tools - New list of allowed tool names
140
+ */
141
+ setAllowedTools(tools: string[]): void;
142
+ /**
143
+ * Get Shield status and diagnostics
144
+ */
145
+ getStatus(): ServiceStatus;
146
+ /**
147
+ * Graceful shutdown: flushes telemetry and releases resources
148
+ * Call this before process exit
149
+ */
150
+ destroy(): void;
151
+ }
152
+ export { ShieldBlockError };
153
+ export type { WrapOptions, ServiceStatus, LLMResponse };
154
+ export type { VanguardPattern, PatternCategory, InjectionThreat, } from "./domain/detection";
155
+ export type { ToolPolicy, ToolViolation } from "./domain/guard";
156
+ export type { SecurityEvent, SecurityEventMetadata, ThreatSeverity, SecurityEventType, } from "./domain/events";
157
+ export type { ILLMProvider, LLMRequest, LLMMessage, LLMChoice, ToolCall, LLMTool, TokenUsage, ITelemetrySink, IPatternRepository, } from "./application";
158
+ export { BundledPatternRepository, RemotePatternRepository } from "./infrastructure/patterns";
159
+ export type { RemotePatternRepositoryConfig } from "./infrastructure/patterns";
160
+ export { normalizePrompt, normalizePrompts, jitter } from "./application/utils";
161
+ export { HttpSignalSink } from "./infrastructure/telemetry";
162
+ export type { HttpSignalSinkConfig } from "./infrastructure/telemetry";
163
+ export { LLMSentinel } from "./infrastructure/sentinel/LLMSentinel";
164
+ export type { LLMSentinelOptions } from "./infrastructure/sentinel/LLMSentinel";
165
+ export { HttpShadowLogSink } from "./infrastructure/telemetry/HttpShadowLogSink";
166
+ export type { ShadowLogPayload } from "./infrastructure/telemetry/HttpShadowLogSink";
167
+ export { ShieldApplicationService } from "./application/ShieldApplicationService";
168
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Tracerny
3
+ * Transparent Proxy Runtime Sentinel for Prompt Injection Defense
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { Tracerny } from 'tracerney';
8
+ *
9
+ * const shield = new Tracerny({
10
+ * allowedTools: ['search', 'calculator'],
11
+ * apiEndpoint: 'https://api.myapp.com/v1/signal',
12
+ * });
13
+ *
14
+ * const response = await shield.wrap(() =>
15
+ * openai.chat.completions.create({...})
16
+ * );
17
+ * ```
18
+ */
19
+ import { ShieldApplicationService } from './application/index.js';
20
+ import { ShieldBlockError } from './application/ShieldBlockError.js';
21
+ import { createToolPolicy } from './domain/guard/ToolPolicy.js';
22
+ import { BundledPatternRepository } from './infrastructure/patterns/BundledPatternRepository.js';
23
+ import { HttpSignalSink } from './infrastructure/telemetry/HttpSignalSink.js';
24
+ // import { HttpShadowLogSink } from './infrastructure/telemetry/HttpShadowLogSink.js'; // Disabled
25
+ import { LLMSentinel } from './infrastructure/sentinel/LLMSentinel.js';
26
+ /**
27
+ * Tracerny Facade
28
+ * Main entry point for the SDK
29
+ * Wires all dependencies: domain + application + infrastructure
30
+ */
31
+ export class Tracerny {
32
+ /**
33
+ * Constructor: wires the full dependency graph
34
+ */
35
+ constructor(options = {}) {
36
+ // Step 0: Resolve endpoints from baseUrl if provided
37
+ const resolvedOptions = this.resolveEndpoints(options);
38
+ // Step 1: Build pattern repository
39
+ // Always use bundled patterns (288 forensic patterns)
40
+ // No remote updates - bundled patterns are production-ready
41
+ const patternRepo = new BundledPatternRepository();
42
+ // Step 2: Build telemetry sink
43
+ const telemetrySink = options.enableTelemetry !== false && resolvedOptions.apiEndpoint
44
+ ? new HttpSignalSink({
45
+ endpoint: resolvedOptions.apiEndpoint,
46
+ apiKey: resolvedOptions.apiKey,
47
+ })
48
+ : undefined;
49
+ // Step 3: Create tool policy
50
+ const toolPolicy = createToolPolicy(options.allowedTools ?? []);
51
+ // Step 4: Build Layer 2 LLM Sentinel (if enabled)
52
+ let sentinel = undefined;
53
+ if (options.sentinelEnabled !== false && resolvedOptions.sentinelEndpoint) {
54
+ sentinel = new LLMSentinel(resolvedOptions.sentinelEndpoint, resolvedOptions.apiKey);
55
+ }
56
+ // Step 5: Build shadow log sink (if endpoint provided)
57
+ // DISABLED FOR NOW - will re-enable after fixing endpoint
58
+ // let shadowLogSink = undefined;
59
+ // if (resolvedOptions.shadowLogEndpoint) {
60
+ // shadowLogSink = new HttpShadowLogSink({
61
+ // endpoint: resolvedOptions.shadowLogEndpoint,
62
+ // apiKey: resolvedOptions.apiKey,
63
+ // });
64
+ // }
65
+ const shadowLogSink = undefined;
66
+ // Step 6: Wire application service
67
+ this.service = new ShieldApplicationService({
68
+ patternRepository: patternRepo,
69
+ telemetrySink,
70
+ toolPolicy,
71
+ sentinel,
72
+ shadowLogSink,
73
+ sdkVersion: "0.2.0",
74
+ });
75
+ }
76
+ /**
77
+ * Resolves baseUrl into individual endpoint URLs
78
+ * baseUrl takes precedence over individual endpoint options
79
+ */
80
+ resolveEndpoints(options) {
81
+ if (options.baseUrl) {
82
+ // Remove trailing slash for consistency
83
+ const baseUrl = options.baseUrl.replace(/\/$/, '');
84
+ return {
85
+ ...options,
86
+ apiEndpoint: `${baseUrl}/api/v1/signal`,
87
+ sentinelEndpoint: `${baseUrl}/api/v1/verify-prompt`,
88
+ shadowLogEndpoint: `${baseUrl}/api/v1/shadow-log`,
89
+ manifestUrl: `${baseUrl}/api/v1/definitions`,
90
+ };
91
+ }
92
+ // No baseUrl, use individual options as-is
93
+ return options;
94
+ }
95
+ /**
96
+ * Main wrapper for LLM calls
97
+ *
98
+ * @param llmCall - Function that executes the LLM call
99
+ * @param options - Optional: prompt for pre-LLM scanning, request context
100
+ *
101
+ * @throws ShieldBlockError if an injection or unauthorized tool is detected
102
+ * @throws Other errors from the LLM provider or network failures
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // With optional prompt for pre-LLM scanning (fixes Gap 3)
107
+ * const response = await shield.wrap(
108
+ * () => openai.chat.completions.create({...}),
109
+ * { prompt: userInput }
110
+ * );
111
+ * ```
112
+ */
113
+ async wrap(llmCall, options) {
114
+ return this.service.wrap(llmCall, options);
115
+ }
116
+ /**
117
+ * Scan a raw prompt for injection attempts (standalone use)
118
+ *
119
+ * @param prompt - The user input to scan
120
+ * @throws ShieldBlockError if injection is detected
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * try {
125
+ * await shield.scanPrompt(userInput);
126
+ * // Safe to proceed
127
+ * } catch (err) {
128
+ * if (err instanceof ShieldBlockError) {
129
+ * // Attack detected
130
+ * }
131
+ * }
132
+ * ```
133
+ */
134
+ async scanPrompt(prompt) {
135
+ return this.service.scanPrompt(prompt);
136
+ }
137
+ /**
138
+ * Update allowed tools at runtime
139
+ *
140
+ * @param tools - New list of allowed tool names
141
+ */
142
+ setAllowedTools(tools) {
143
+ return this.service.setAllowedTools(tools);
144
+ }
145
+ /**
146
+ * Get Shield status and diagnostics
147
+ */
148
+ getStatus() {
149
+ return this.service.getStatus();
150
+ }
151
+ /**
152
+ * Graceful shutdown: flushes telemetry and releases resources
153
+ * Call this before process exit
154
+ */
155
+ destroy() {
156
+ return this.service.destroy();
157
+ }
158
+ }
159
+ // ============================================================================
160
+ // Public Exports
161
+ // ============================================================================
162
+ // Error class
163
+ export { ShieldBlockError };
164
+ // Infrastructure adapter exports (for advanced/custom usage)
165
+ export { BundledPatternRepository, RemotePatternRepository } from './infrastructure/patterns/index.js';
166
+ // Utility exports (for middleware & advanced use)
167
+ export { normalizePrompt, normalizePrompts, jitter } from './application/utils/index.js';
168
+ export { HttpSignalSink } from './infrastructure/telemetry/index.js';
169
+ // Layer 2 Sentinel exports
170
+ export { LLMSentinel } from './infrastructure/sentinel/LLMSentinel.js';
171
+ export { HttpShadowLogSink } from './infrastructure/telemetry/HttpShadowLogSink.js';
172
+ export { ShieldApplicationService } from './application/ShieldApplicationService.js';
173
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,wBAAwB,EAAwC,MAAM,eAAe,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,gGAAgG;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAwEpE;;;;GAIG;AACH,MAAM,OAAO,QAAQ;IAGnB;;OAEG;IACH,YAAY,UAA2B,EAAE;QACvC,qDAAqD;QACrD,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAEvD,mCAAmC;QACnC,sDAAsD;QACtD,4DAA4D;QAC5D,MAAM,WAAW,GAAG,IAAI,wBAAwB,EAAE,CAAC;QAEnD,+BAA+B;QAC/B,MAAM,aAAa,GACjB,OAAO,CAAC,eAAe,KAAK,KAAK,IAAI,eAAe,CAAC,WAAW;YAC9D,CAAC,CAAC,IAAI,cAAc,CAAC;gBACjB,QAAQ,EAAE,eAAe,CAAC,WAAW;gBACrC,MAAM,EAAE,eAAe,CAAC,MAAM;aAC/B,CAAC;YACJ,CAAC,CAAC,SAAS,CAAC;QAEhB,6BAA6B;QAC7B,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAEhE,kDAAkD;QAClD,IAAI,QAAQ,GAAG,SAAS,CAAC;QACzB,IAAI,OAAO,CAAC,eAAe,KAAK,KAAK,IAAI,eAAe,CAAC,gBAAgB,EAAE,CAAC;YAC1E,QAAQ,GAAG,IAAI,WAAW,CAAC,eAAe,CAAC,gBAAgB,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACvF,CAAC;QAED,uDAAuD;QACvD,0DAA0D;QAC1D,iCAAiC;QACjC,2CAA2C;QAC3C,4CAA4C;QAC5C,mDAAmD;QACnD,sCAAsC;QACtC,QAAQ;QACR,IAAI;QACJ,MAAM,aAAa,GAAG,SAAS,CAAC;QAEhC,mCAAmC;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,wBAAwB,CAAC;YAC1C,iBAAiB,EAAE,WAAW;YAC9B,aAAa;YACb,UAAU;YACV,QAAQ;YACR,aAAa;YACb,UAAU,EAAE,OAAO;SACpB,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,gBAAgB,CAAC,OAAwB;QAC/C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,wCAAwC;YACxC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAEnD,OAAO;gBACL,GAAG,OAAO;gBACV,WAAW,EAAE,GAAG,OAAO,gBAAgB;gBACvC,gBAAgB,EAAE,GAAG,OAAO,uBAAuB;gBACnD,iBAAiB,EAAE,GAAG,OAAO,oBAAoB;gBACjD,WAAW,EAAE,GAAG,OAAO,qBAAqB;aAC7C,CAAC;QACJ,CAAC;QAED,2CAA2C;QAC3C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,IAAI,CACR,OAAyB,EACzB,OAAqB;QAErB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,UAAU,CAAC,MAAc;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,KAAe;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;CACF;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAkC5B,6DAA6D;AAC7D,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAG9F,kDAAkD;AAClD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,2BAA2B;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAGpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AAGjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * OpenRouter LLM Provider
3
+ * Adapter: implements ILLMProvider for OpenRouter
4
+ * Uses native fetch — zero dependencies (no openai npm package)
5
+ */
6
+ import { ILLMProvider, LLMRequest, LLMResponse } from "../../application/ports/ILLMProvider";
7
+ export interface OpenRouterConfig {
8
+ apiKey: string;
9
+ baseUrl?: string;
10
+ siteUrl?: string;
11
+ siteTitle?: string;
12
+ defaultModel?: string;
13
+ timeoutMs?: number;
14
+ }
15
+ export declare class OpenRouterProvider implements ILLMProvider {
16
+ private readonly config;
17
+ readonly providerName = "openrouter";
18
+ private readonly baseUrl;
19
+ private readonly timeoutMs;
20
+ constructor(config: OpenRouterConfig);
21
+ /**
22
+ * Execute an LLM call via OpenRouter.
23
+ * Implements ILLMProvider.complete()
24
+ */
25
+ complete(request: LLMRequest): Promise<LLMResponse>;
26
+ /**
27
+ * Create an AbortSignal for request timeout.
28
+ * Node.js 17+ supports AbortSignal.timeout()
29
+ */
30
+ private createAbortSignal;
31
+ }
32
+ //# sourceMappingURL=OpenRouterProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterProvider.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/llm/OpenRouterProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,EACV,WAAW,EAEZ,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,kBAAmB,YAAW,YAAY;IAMzC,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,QAAQ,CAAC,YAAY,gBAAgB;IAErC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEN,MAAM,EAAE,gBAAgB;IASrD;;;OAGG;IACG,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IA0EzD;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CA2D1B"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * OpenRouter LLM Provider
3
+ * Adapter: implements ILLMProvider for OpenRouter
4
+ * Uses native fetch — zero dependencies (no openai npm package)
5
+ */
6
+ import { ProviderError, } from '../../application/ports/ILLMProvider.js';
7
+ export class OpenRouterProvider {
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.providerName = "openrouter";
11
+ this.baseUrl = config.baseUrl ?? "https://openrouter.ai/api/v1";
12
+ this.timeoutMs = config.timeoutMs ?? 30000;
13
+ if (!config.apiKey) {
14
+ throw new Error("[OpenRouterProvider] apiKey is required");
15
+ }
16
+ }
17
+ /**
18
+ * Execute an LLM call via OpenRouter.
19
+ * Implements ILLMProvider.complete()
20
+ */
21
+ async complete(request) {
22
+ const model = request.model || this.config.defaultModel || "openai/gpt-4o";
23
+ // Build the request body — OpenAI-compatible format
24
+ const body = {
25
+ model,
26
+ messages: request.messages,
27
+ ...(request.tools && { tools: request.tools }),
28
+ ...(request.temperature !== undefined && { temperature: request.temperature }),
29
+ ...(request.maxTokens !== undefined && { max_tokens: request.maxTokens }),
30
+ // Pass through any additional provider-specific parameters
31
+ ...Object.fromEntries(Object.entries(request).filter(([key]) => ![
32
+ "messages",
33
+ "model",
34
+ "tools",
35
+ "temperature",
36
+ "maxTokens",
37
+ ].includes(key))),
38
+ };
39
+ try {
40
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
41
+ method: "POST",
42
+ headers: {
43
+ "Content-Type": "application/json",
44
+ Authorization: `Bearer ${this.config.apiKey}`,
45
+ // OpenRouter required headers
46
+ "HTTP-Referer": this.config.siteUrl ?? "",
47
+ "X-Title": this.config.siteTitle ?? "Tracerny",
48
+ },
49
+ body: JSON.stringify(body),
50
+ signal: this.createAbortSignal(),
51
+ });
52
+ if (!response.ok) {
53
+ const errorBody = await response.text().catch(() => "");
54
+ throw new ProviderError(`OpenRouter returned ${response.status}: ${response.statusText}\n${errorBody}`, "openrouter", response.status);
55
+ }
56
+ // Response shape is OpenAI-compatible — cast directly
57
+ const data = (await response.json());
58
+ return data;
59
+ }
60
+ catch (error) {
61
+ if (error instanceof ProviderError) {
62
+ throw error;
63
+ }
64
+ if (error instanceof TypeError && error.message.includes("fetch")) {
65
+ throw new ProviderError(`Network error: ${error.message}`, "openrouter", undefined, error);
66
+ }
67
+ throw new ProviderError(`OpenRouter call failed: ${error instanceof Error ? error.message : String(error)}`, "openrouter", undefined, error);
68
+ }
69
+ }
70
+ /**
71
+ * Create an AbortSignal for request timeout.
72
+ * Node.js 17+ supports AbortSignal.timeout()
73
+ */
74
+ createAbortSignal() {
75
+ // Try Node.js 17+ AbortSignal.timeout()
76
+ if (AbortSignal && "timeout" in AbortSignal) {
77
+ try {
78
+ return AbortSignal.timeout(this.timeoutMs);
79
+ }
80
+ catch {
81
+ // Fallback if timeout() not available
82
+ }
83
+ }
84
+ // Fallback: use AbortController with timer
85
+ const controller = new AbortController();
86
+ const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
87
+ // Clean up timeout on early resolution
88
+ const originalSignal = controller.signal;
89
+ const wrappedSignal = new (class {
90
+ constructor() {
91
+ this.aborted = originalSignal.aborted;
92
+ this.addEventListener = (type, listener, options) => {
93
+ originalSignal.addEventListener(type, listener, options);
94
+ };
95
+ this.removeEventListener = (type, listener, options) => {
96
+ originalSignal.removeEventListener(type, listener, options);
97
+ };
98
+ this.dispatchEvent = (event) => {
99
+ clearTimeout(timeoutId);
100
+ return originalSignal.dispatchEvent(event);
101
+ };
102
+ }
103
+ get onabort() {
104
+ return originalSignal.onabort;
105
+ }
106
+ set onabort(handler) {
107
+ originalSignal.onabort = handler;
108
+ }
109
+ get reason() {
110
+ return originalSignal.reason;
111
+ }
112
+ throwIfAborted() {
113
+ originalSignal.throwIfAborted?.();
114
+ }
115
+ })();
116
+ return wrappedSignal;
117
+ }
118
+ }
119
+ //# sourceMappingURL=OpenRouterProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterProvider.js","sourceRoot":"","sources":["../../../src/infrastructure/llm/OpenRouterProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * LLM Provider Infrastructure
3
+ * Barrel export
4
+ */
5
+ export { OpenRouterProvider } from "./OpenRouterProvider";
6
+ export type { OpenRouterConfig } from "./OpenRouterProvider";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/llm/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * LLM Provider Infrastructure
3
+ * Barrel export
4
+ */
5
+ export { OpenRouterProvider } from './OpenRouterProvider.js';
6
+ //# sourceMappingURL=index.js.map