librechat-data-provider 0.8.402 → 0.8.404

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 (109) hide show
  1. package/dist/index.es.js +1 -1
  2. package/dist/index.es.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/react-query/index.es.js +1 -1
  6. package/dist/react-query/index.es.js.map +1 -1
  7. package/dist/types/accessPermissions.d.ts +744 -0
  8. package/dist/types/actions.d.ts +118 -0
  9. package/dist/types/api-endpoints.d.ts +150 -0
  10. package/dist/types/artifacts.d.ts +97 -0
  11. package/dist/types/azure.d.ts +22 -0
  12. package/dist/types/bedrock.d.ts +1220 -0
  13. package/dist/types/config.d.ts +14849 -0
  14. package/dist/types/config.spec.d.ts +1 -0
  15. package/dist/types/createPayload.d.ts +5 -0
  16. package/dist/types/data-service.d.ts +287 -0
  17. package/dist/types/feedback.d.ts +36 -0
  18. package/dist/types/file-config.d.ts +263 -0
  19. package/dist/types/file-config.spec.d.ts +1 -0
  20. package/dist/types/generate.d.ts +597 -0
  21. package/dist/types/headers-helpers.d.ts +2 -0
  22. package/{src/index.ts → dist/types/index.d.ts} +0 -15
  23. package/dist/types/keys.d.ts +92 -0
  24. package/dist/types/mcp.d.ts +2760 -0
  25. package/dist/types/messages.d.ts +10 -0
  26. package/dist/types/models.d.ts +1547 -0
  27. package/dist/types/parameterSettings.d.ts +69 -0
  28. package/dist/types/parsers.d.ts +110 -0
  29. package/dist/types/permissions.d.ts +522 -0
  30. package/dist/types/react-query/react-query-service.d.ts +85 -0
  31. package/dist/types/request.d.ts +25 -0
  32. package/dist/types/roles.d.ts +554 -0
  33. package/dist/types/roles.spec.d.ts +1 -0
  34. package/dist/types/schemas.d.ts +5110 -0
  35. package/dist/types/schemas.spec.d.ts +1 -0
  36. package/dist/types/types/agents.d.ts +433 -0
  37. package/dist/types/types/assistants.d.ts +547 -0
  38. package/dist/types/types/files.d.ts +172 -0
  39. package/dist/types/types/graph.d.ts +135 -0
  40. package/{src/types/mcpServers.ts → dist/types/types/mcpServers.d.ts} +12 -18
  41. package/dist/types/types/mutations.d.ts +209 -0
  42. package/dist/types/types/queries.d.ts +169 -0
  43. package/dist/types/types/runs.d.ts +36 -0
  44. package/dist/types/types/web.d.ts +520 -0
  45. package/dist/types/types.d.ts +503 -0
  46. package/dist/types/utils.d.ts +12 -0
  47. package/package.json +5 -1
  48. package/babel.config.js +0 -4
  49. package/check_updates.sh +0 -52
  50. package/jest.config.js +0 -19
  51. package/react-query/package-lock.json +0 -292
  52. package/react-query/package.json +0 -10
  53. package/rollup.config.js +0 -74
  54. package/server-rollup.config.js +0 -40
  55. package/specs/actions.spec.ts +0 -2533
  56. package/specs/api-endpoints-subdir.spec.ts +0 -140
  57. package/specs/api-endpoints.spec.ts +0 -74
  58. package/specs/azure.spec.ts +0 -844
  59. package/specs/bedrock.spec.ts +0 -862
  60. package/specs/filetypes.spec.ts +0 -175
  61. package/specs/generate.spec.ts +0 -770
  62. package/specs/headers-helpers.spec.ts +0 -24
  63. package/specs/mcp.spec.ts +0 -147
  64. package/specs/openapiSpecs.ts +0 -524
  65. package/specs/parsers.spec.ts +0 -601
  66. package/specs/request-interceptor.spec.ts +0 -304
  67. package/specs/utils.spec.ts +0 -196
  68. package/src/accessPermissions.ts +0 -346
  69. package/src/actions.ts +0 -813
  70. package/src/api-endpoints.ts +0 -440
  71. package/src/artifacts.ts +0 -3104
  72. package/src/azure.ts +0 -328
  73. package/src/bedrock.ts +0 -425
  74. package/src/config.spec.ts +0 -315
  75. package/src/config.ts +0 -2006
  76. package/src/createPayload.ts +0 -46
  77. package/src/data-service.ts +0 -1087
  78. package/src/feedback.ts +0 -141
  79. package/src/file-config.spec.ts +0 -1248
  80. package/src/file-config.ts +0 -764
  81. package/src/generate.ts +0 -634
  82. package/src/headers-helpers.ts +0 -13
  83. package/src/keys.ts +0 -99
  84. package/src/mcp.ts +0 -271
  85. package/src/messages.ts +0 -50
  86. package/src/models.ts +0 -69
  87. package/src/parameterSettings.ts +0 -1111
  88. package/src/parsers.ts +0 -563
  89. package/src/permissions.ts +0 -188
  90. package/src/react-query/react-query-service.ts +0 -566
  91. package/src/request.ts +0 -171
  92. package/src/roles.spec.ts +0 -132
  93. package/src/roles.ts +0 -225
  94. package/src/schemas.spec.ts +0 -355
  95. package/src/schemas.ts +0 -1234
  96. package/src/types/agents.ts +0 -470
  97. package/src/types/assistants.ts +0 -654
  98. package/src/types/files.ts +0 -191
  99. package/src/types/graph.ts +0 -145
  100. package/src/types/mutations.ts +0 -422
  101. package/src/types/queries.ts +0 -208
  102. package/src/types/runs.ts +0 -40
  103. package/src/types/web.ts +0 -588
  104. package/src/types.ts +0 -676
  105. package/src/utils.ts +0 -85
  106. package/tsconfig.json +0 -28
  107. package/tsconfig.spec.json +0 -10
  108. /package/{src/react-query/index.ts → dist/types/react-query/index.d.ts} +0 -0
  109. /package/{src/types/index.ts → dist/types/types/index.d.ts} +0 -0
@@ -1,304 +0,0 @@
1
- /**
2
- * @jest-environment @happy-dom/jest-environment
3
- */
4
- import axios from 'axios';
5
- import { setTokenHeader } from '../src/headers-helpers';
6
-
7
- /**
8
- * The response interceptor in request.ts registers at import time when
9
- * `typeof window !== 'undefined'` (happy-dom provides window).
10
- *
11
- * We use axios's built-in request adapter mock to avoid real HTTP calls,
12
- * and verify the interceptor's behavior by observing whether a 401 triggers
13
- * a refresh POST or is immediately rejected.
14
- *
15
- * happy-dom is used instead of jsdom because it allows overriding
16
- * window.location via Object.defineProperty, which jsdom 26+ blocks.
17
- */
18
-
19
- const mockAdapter = jest.fn();
20
- let originalAdapter: typeof axios.defaults.adapter;
21
- let savedLocation: Location;
22
-
23
- beforeAll(async () => {
24
- originalAdapter = axios.defaults.adapter;
25
- axios.defaults.adapter = mockAdapter;
26
-
27
- await import('../src/request');
28
- });
29
-
30
- beforeEach(() => {
31
- mockAdapter.mockReset();
32
- savedLocation = window.location;
33
- });
34
-
35
- afterAll(() => {
36
- axios.defaults.adapter = originalAdapter;
37
- });
38
-
39
- afterEach(() => {
40
- delete axios.defaults.headers.common['Authorization'];
41
- Object.defineProperty(window, 'location', {
42
- value: savedLocation,
43
- writable: true,
44
- configurable: true,
45
- });
46
- });
47
-
48
- function setWindowLocation(overrides: Partial<Location>) {
49
- Object.defineProperty(window, 'location', {
50
- value: { ...window.location, ...overrides },
51
- writable: true,
52
- configurable: true,
53
- });
54
- }
55
-
56
- describe('axios 401 interceptor — Authorization header guard', () => {
57
- it('skips refresh and rejects when Authorization header is cleared', async () => {
58
- expect.assertions(1);
59
- setTokenHeader(undefined);
60
-
61
- mockAdapter.mockRejectedValueOnce({
62
- response: { status: 401 },
63
- config: { url: '/api/messages', headers: {} },
64
- });
65
-
66
- try {
67
- await axios.get('/api/messages');
68
- } catch {
69
- // expected rejection
70
- }
71
-
72
- expect(mockAdapter).toHaveBeenCalledTimes(1);
73
- });
74
-
75
- it('attempts refresh on shared link page even without Authorization header', async () => {
76
- expect.assertions(2);
77
- setTokenHeader(undefined);
78
-
79
- setWindowLocation({
80
- href: 'http://localhost/share/abc123',
81
- pathname: '/share/abc123',
82
- search: '',
83
- hash: '',
84
- } as Partial<Location>);
85
-
86
- mockAdapter.mockRejectedValueOnce({
87
- response: { status: 401 },
88
- config: { url: '/api/share/abc123', headers: {} },
89
- });
90
-
91
- mockAdapter.mockResolvedValueOnce({
92
- data: { token: 'new-token' },
93
- status: 200,
94
- headers: {},
95
- config: {},
96
- });
97
-
98
- mockAdapter.mockResolvedValueOnce({
99
- data: { sharedLink: {} },
100
- status: 200,
101
- headers: {},
102
- config: {},
103
- });
104
-
105
- try {
106
- await axios.get('/api/share/abc123');
107
- } catch {
108
- // may reject depending on exact flow
109
- }
110
-
111
- expect(mockAdapter.mock.calls.length).toBe(3);
112
-
113
- const refreshCall = mockAdapter.mock.calls[1];
114
- expect(refreshCall[0].url).toContain('api/auth/refresh');
115
- });
116
-
117
- it('does not bypass guard when share/ appears only in query params', async () => {
118
- expect.assertions(1);
119
- setTokenHeader(undefined);
120
-
121
- setWindowLocation({
122
- href: 'http://localhost/c/chat?ref=share/token',
123
- pathname: '/c/chat',
124
- search: '?ref=share/token',
125
- hash: '',
126
- } as Partial<Location>);
127
-
128
- mockAdapter.mockRejectedValueOnce({
129
- response: { status: 401 },
130
- config: { url: '/api/messages', headers: {} },
131
- });
132
-
133
- try {
134
- await axios.get('/api/messages');
135
- } catch {
136
- // expected rejection
137
- }
138
-
139
- expect(mockAdapter).toHaveBeenCalledTimes(1);
140
- });
141
-
142
- it('redirects to login with redirect_to when unauthenticated on share page and refresh fails', async () => {
143
- expect.assertions(1);
144
- setTokenHeader(undefined);
145
-
146
- setWindowLocation({
147
- href: 'http://localhost/share/abc123',
148
- pathname: '/share/abc123',
149
- search: '',
150
- hash: '',
151
- } as Partial<Location>);
152
-
153
- mockAdapter.mockRejectedValueOnce({
154
- response: { status: 401 },
155
- config: { url: '/api/share/abc123', headers: {} },
156
- });
157
-
158
- mockAdapter.mockResolvedValueOnce({
159
- data: { token: '' },
160
- status: 200,
161
- headers: {},
162
- config: {},
163
- });
164
-
165
- try {
166
- await axios.get('/api/share/abc123');
167
- } catch {
168
- // expected rejection
169
- }
170
-
171
- expect(window.location.href).toBe('/login?redirect_to=%2Fshare%2Fabc123');
172
- });
173
-
174
- it('redirects to login with redirect_to when authenticated and refresh returns no token on share page', async () => {
175
- expect.assertions(1);
176
- setTokenHeader('some-token');
177
-
178
- setWindowLocation({
179
- href: 'http://localhost/share/abc123',
180
- pathname: '/share/abc123',
181
- search: '',
182
- hash: '',
183
- } as Partial<Location>);
184
-
185
- mockAdapter.mockRejectedValueOnce({
186
- response: { status: 401 },
187
- config: { url: '/api/share/abc123', headers: {} },
188
- });
189
-
190
- mockAdapter.mockResolvedValueOnce({
191
- data: { token: '' },
192
- status: 200,
193
- headers: {},
194
- config: {},
195
- });
196
-
197
- try {
198
- await axios.get('/api/share/abc123');
199
- } catch {
200
- // expected rejection
201
- }
202
-
203
- expect(window.location.href).toBe('/login?redirect_to=%2Fshare%2Fabc123');
204
- });
205
-
206
- it('redirects to login with redirect_to when refresh returns no token on regular page', async () => {
207
- expect.assertions(1);
208
- setTokenHeader('some-token');
209
-
210
- setWindowLocation({
211
- href: 'http://localhost/c/some-conversation',
212
- pathname: '/c/some-conversation',
213
- search: '',
214
- hash: '',
215
- } as Partial<Location>);
216
-
217
- mockAdapter.mockRejectedValueOnce({
218
- response: { status: 401 },
219
- config: { url: '/api/messages', headers: {} },
220
- });
221
-
222
- mockAdapter.mockResolvedValueOnce({
223
- data: { token: '' },
224
- status: 200,
225
- headers: {},
226
- config: {},
227
- });
228
-
229
- try {
230
- await axios.get('/api/messages');
231
- } catch {
232
- // expected rejection
233
- }
234
-
235
- expect(window.location.href).toBe('/login?redirect_to=%2Fc%2Fsome-conversation');
236
- });
237
-
238
- it('redirects to plain /login without redirect_to when already on a login path', async () => {
239
- expect.assertions(1);
240
- setTokenHeader('some-token');
241
-
242
- setWindowLocation({
243
- href: 'http://localhost/login/2fa',
244
- pathname: '/login/2fa',
245
- search: '',
246
- hash: '',
247
- } as Partial<Location>);
248
-
249
- mockAdapter.mockRejectedValueOnce({
250
- response: { status: 401 },
251
- config: { url: '/api/messages', headers: {} },
252
- });
253
-
254
- mockAdapter.mockResolvedValueOnce({
255
- data: { token: '' },
256
- status: 200,
257
- headers: {},
258
- config: {},
259
- });
260
-
261
- try {
262
- await axios.get('/api/messages');
263
- } catch {
264
- // expected rejection
265
- }
266
-
267
- expect(window.location.href).toBe('/login');
268
- });
269
-
270
- it('attempts refresh when Authorization header is present', async () => {
271
- expect.assertions(2);
272
- setTokenHeader('valid-token');
273
-
274
- mockAdapter.mockRejectedValueOnce({
275
- response: { status: 401 },
276
- config: { url: '/api/messages', headers: {}, _retry: false },
277
- });
278
-
279
- mockAdapter.mockResolvedValueOnce({
280
- data: { token: 'new-token' },
281
- status: 200,
282
- headers: {},
283
- config: {},
284
- });
285
-
286
- mockAdapter.mockResolvedValueOnce({
287
- data: { messages: [] },
288
- status: 200,
289
- headers: {},
290
- config: {},
291
- });
292
-
293
- try {
294
- await axios.get('/api/messages');
295
- } catch {
296
- // may reject depending on exact flow
297
- }
298
-
299
- expect(mockAdapter.mock.calls.length).toBe(3);
300
-
301
- const refreshCall = mockAdapter.mock.calls[1];
302
- expect(refreshCall[0].url).toContain('api/auth/refresh');
303
- });
304
- });
@@ -1,196 +0,0 @@
1
- import { extractEnvVariable, isSensitiveEnvVar } from '../src/utils';
2
-
3
- describe('Environment Variable Extraction', () => {
4
- const originalEnv = process.env;
5
-
6
- beforeEach(() => {
7
- process.env = {
8
- ...originalEnv,
9
- TEST_API_KEY: 'test-api-key-value',
10
- ANOTHER_VALUE: 'another-value',
11
- };
12
- });
13
-
14
- afterEach(() => {
15
- process.env = originalEnv;
16
- });
17
-
18
- describe('extractEnvVariable (original tests)', () => {
19
- test('should return the value of the environment variable', () => {
20
- process.env.TEST_VAR = 'test_value';
21
- expect(extractEnvVariable('${TEST_VAR}')).toBe('test_value');
22
- });
23
-
24
- test('should return the original string if the envrionment variable is not defined correctly', () => {
25
- process.env.TEST_VAR = 'test_value';
26
- expect(extractEnvVariable('${ TEST_VAR }')).toBe('${ TEST_VAR }');
27
- });
28
-
29
- test('should return the original string if environment variable is not set', () => {
30
- expect(extractEnvVariable('${NON_EXISTENT_VAR}')).toBe('${NON_EXISTENT_VAR}');
31
- });
32
-
33
- test('should return the original string if it does not contain an environment variable', () => {
34
- expect(extractEnvVariable('some_string')).toBe('some_string');
35
- });
36
-
37
- test('should handle empty strings', () => {
38
- expect(extractEnvVariable('')).toBe('');
39
- });
40
-
41
- test('should handle strings without variable format', () => {
42
- expect(extractEnvVariable('no_var_here')).toBe('no_var_here');
43
- });
44
-
45
- /** No longer the expected behavior; keeping for reference */
46
- test.skip('should not process multiple variable formats', () => {
47
- process.env.FIRST_VAR = 'first';
48
- process.env.SECOND_VAR = 'second';
49
- expect(extractEnvVariable('${FIRST_VAR} and ${SECOND_VAR}')).toBe(
50
- '${FIRST_VAR} and ${SECOND_VAR}',
51
- );
52
- });
53
- });
54
-
55
- describe('extractEnvVariable function', () => {
56
- it('should extract environment variables from exact matches', () => {
57
- expect(extractEnvVariable('${TEST_API_KEY}')).toBe('test-api-key-value');
58
- expect(extractEnvVariable('${ANOTHER_VALUE}')).toBe('another-value');
59
- });
60
-
61
- it('should extract environment variables from strings with prefixes', () => {
62
- expect(extractEnvVariable('prefix-${TEST_API_KEY}')).toBe('prefix-test-api-key-value');
63
- });
64
-
65
- it('should extract environment variables from strings with suffixes', () => {
66
- expect(extractEnvVariable('${TEST_API_KEY}-suffix')).toBe('test-api-key-value-suffix');
67
- });
68
-
69
- it('should extract environment variables from strings with both prefixes and suffixes', () => {
70
- expect(extractEnvVariable('prefix-${TEST_API_KEY}-suffix')).toBe(
71
- 'prefix-test-api-key-value-suffix',
72
- );
73
- });
74
-
75
- it('should not match invalid patterns', () => {
76
- expect(extractEnvVariable('$TEST_API_KEY')).toBe('$TEST_API_KEY');
77
- expect(extractEnvVariable('{TEST_API_KEY}')).toBe('{TEST_API_KEY}');
78
- expect(extractEnvVariable('TEST_API_KEY')).toBe('TEST_API_KEY');
79
- });
80
- });
81
-
82
- describe('extractEnvVariable', () => {
83
- it('should extract environment variable values', () => {
84
- expect(extractEnvVariable('${TEST_API_KEY}')).toBe('test-api-key-value');
85
- expect(extractEnvVariable('${ANOTHER_VALUE}')).toBe('another-value');
86
- });
87
-
88
- it('should return the original string if environment variable is not found', () => {
89
- expect(extractEnvVariable('${NON_EXISTENT_VAR}')).toBe('${NON_EXISTENT_VAR}');
90
- });
91
-
92
- it('should return the original string if no environment variable pattern is found', () => {
93
- expect(extractEnvVariable('plain-string')).toBe('plain-string');
94
- });
95
- });
96
-
97
- describe('extractEnvVariable space trimming', () => {
98
- beforeEach(() => {
99
- process.env.HELLO = 'world';
100
- process.env.USER = 'testuser';
101
- });
102
-
103
- it('should extract the value when string contains only an environment variable with surrounding whitespace', () => {
104
- expect(extractEnvVariable(' ${HELLO} ')).toBe('world');
105
- expect(extractEnvVariable(' ${HELLO} ')).toBe('world');
106
- expect(extractEnvVariable('\t${HELLO}\n')).toBe('world');
107
- });
108
-
109
- it('should preserve content when variable is part of a larger string', () => {
110
- expect(extractEnvVariable('Hello ${USER}!')).toBe('Hello testuser!');
111
- expect(extractEnvVariable(' Hello ${USER}! ')).toBe('Hello testuser!');
112
- });
113
-
114
- it('should not handle multiple variables', () => {
115
- expect(extractEnvVariable('${HELLO} ${USER}')).toBe('${HELLO} ${USER}');
116
- expect(extractEnvVariable(' ${HELLO} ${USER} ')).toBe('${HELLO} ${USER}');
117
- });
118
-
119
- it('should handle undefined variables', () => {
120
- expect(extractEnvVariable(' ${UNDEFINED_VAR} ')).toBe('${UNDEFINED_VAR}');
121
- });
122
-
123
- it('should handle mixed content correctly', () => {
124
- expect(extractEnvVariable('Welcome, ${USER}!\nYour message: ${HELLO}')).toBe(
125
- 'Welcome, testuser!\nYour message: world',
126
- );
127
- });
128
- });
129
-
130
- describe('isSensitiveEnvVar', () => {
131
- it('should flag infrastructure secrets', () => {
132
- expect(isSensitiveEnvVar('JWT_SECRET')).toBe(true);
133
- expect(isSensitiveEnvVar('JWT_REFRESH_SECRET')).toBe(true);
134
- expect(isSensitiveEnvVar('CREDS_KEY')).toBe(true);
135
- expect(isSensitiveEnvVar('CREDS_IV')).toBe(true);
136
- expect(isSensitiveEnvVar('MEILI_MASTER_KEY')).toBe(true);
137
- expect(isSensitiveEnvVar('MONGO_URI')).toBe(true);
138
- expect(isSensitiveEnvVar('REDIS_URI')).toBe(true);
139
- expect(isSensitiveEnvVar('REDIS_PASSWORD')).toBe(true);
140
- });
141
-
142
- it('should allow non-infrastructure vars through (including operator-configured secrets)', () => {
143
- expect(isSensitiveEnvVar('OPENAI_API_KEY')).toBe(false);
144
- expect(isSensitiveEnvVar('ANTHROPIC_API_KEY')).toBe(false);
145
- expect(isSensitiveEnvVar('GOOGLE_KEY')).toBe(false);
146
- expect(isSensitiveEnvVar('PROXY')).toBe(false);
147
- expect(isSensitiveEnvVar('DEBUG_LOGGING')).toBe(false);
148
- expect(isSensitiveEnvVar('DOMAIN_CLIENT')).toBe(false);
149
- expect(isSensitiveEnvVar('APP_TITLE')).toBe(false);
150
- expect(isSensitiveEnvVar('OPENID_CLIENT_SECRET')).toBe(false);
151
- expect(isSensitiveEnvVar('DISCORD_CLIENT_SECRET')).toBe(false);
152
- expect(isSensitiveEnvVar('MY_CUSTOM_SECRET')).toBe(false);
153
- });
154
- });
155
-
156
- describe('extractEnvVariable sensitive var blocklist', () => {
157
- beforeEach(() => {
158
- process.env.JWT_SECRET = 'super-secret-jwt';
159
- process.env.JWT_REFRESH_SECRET = 'super-secret-refresh';
160
- process.env.CREDS_KEY = 'encryption-key';
161
- process.env.CREDS_IV = 'encryption-iv';
162
- process.env.MEILI_MASTER_KEY = 'meili-key';
163
- process.env.MONGO_URI = 'mongodb://user:pass@host/db';
164
- process.env.REDIS_URI = 'redis://:pass@host:6379';
165
- process.env.REDIS_PASSWORD = 'redis-pass';
166
- process.env.OPENAI_API_KEY = 'sk-legit-key';
167
- });
168
-
169
- it('should refuse to resolve sensitive vars (single-match path)', () => {
170
- expect(extractEnvVariable('${JWT_SECRET}')).toBe('${JWT_SECRET}');
171
- expect(extractEnvVariable('${JWT_REFRESH_SECRET}')).toBe('${JWT_REFRESH_SECRET}');
172
- expect(extractEnvVariable('${CREDS_KEY}')).toBe('${CREDS_KEY}');
173
- expect(extractEnvVariable('${CREDS_IV}')).toBe('${CREDS_IV}');
174
- expect(extractEnvVariable('${MEILI_MASTER_KEY}')).toBe('${MEILI_MASTER_KEY}');
175
- expect(extractEnvVariable('${MONGO_URI}')).toBe('${MONGO_URI}');
176
- expect(extractEnvVariable('${REDIS_URI}')).toBe('${REDIS_URI}');
177
- expect(extractEnvVariable('${REDIS_PASSWORD}')).toBe('${REDIS_PASSWORD}');
178
- });
179
-
180
- it('should refuse to resolve sensitive vars in composite strings (multi-match path)', () => {
181
- expect(extractEnvVariable('key=${JWT_SECRET}&more')).toBe('key=${JWT_SECRET}&more');
182
- expect(extractEnvVariable('db=${MONGO_URI}/extra')).toBe('db=${MONGO_URI}/extra');
183
- });
184
-
185
- it('should still resolve non-sensitive vars normally', () => {
186
- expect(extractEnvVariable('${OPENAI_API_KEY}')).toBe('sk-legit-key');
187
- expect(extractEnvVariable('Bearer ${OPENAI_API_KEY}')).toBe('Bearer sk-legit-key');
188
- });
189
-
190
- it('should resolve non-sensitive vars while blocking sensitive ones in the same string', () => {
191
- expect(extractEnvVariable('key=${OPENAI_API_KEY}&secret=${JWT_SECRET}')).toBe(
192
- 'key=sk-legit-key&secret=${JWT_SECRET}',
193
- );
194
- });
195
- });
196
- });