@optimizely-opal/opal-tool-ocp-sdk 1.0.0-beta.1 → 1.0.0-beta.10

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 (74) hide show
  1. package/README.md +169 -3
  2. package/dist/auth/AuthUtils.d.ts +12 -5
  3. package/dist/auth/AuthUtils.d.ts.map +1 -1
  4. package/dist/auth/AuthUtils.js +80 -25
  5. package/dist/auth/AuthUtils.js.map +1 -1
  6. package/dist/auth/AuthUtils.test.js +161 -117
  7. package/dist/auth/AuthUtils.test.js.map +1 -1
  8. package/dist/function/GlobalToolFunction.d.ts +5 -3
  9. package/dist/function/GlobalToolFunction.d.ts.map +1 -1
  10. package/dist/function/GlobalToolFunction.js +32 -8
  11. package/dist/function/GlobalToolFunction.js.map +1 -1
  12. package/dist/function/GlobalToolFunction.test.js +73 -12
  13. package/dist/function/GlobalToolFunction.test.js.map +1 -1
  14. package/dist/function/ToolFunction.d.ts +11 -4
  15. package/dist/function/ToolFunction.d.ts.map +1 -1
  16. package/dist/function/ToolFunction.js +45 -9
  17. package/dist/function/ToolFunction.js.map +1 -1
  18. package/dist/function/ToolFunction.test.js +278 -11
  19. package/dist/function/ToolFunction.test.js.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +3 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/logging/ToolLogger.d.ts +42 -0
  25. package/dist/logging/ToolLogger.d.ts.map +1 -0
  26. package/dist/logging/ToolLogger.js +255 -0
  27. package/dist/logging/ToolLogger.js.map +1 -0
  28. package/dist/logging/ToolLogger.test.d.ts +2 -0
  29. package/dist/logging/ToolLogger.test.d.ts.map +1 -0
  30. package/dist/logging/ToolLogger.test.js +864 -0
  31. package/dist/logging/ToolLogger.test.js.map +1 -0
  32. package/dist/service/Service.d.ts +88 -2
  33. package/dist/service/Service.d.ts.map +1 -1
  34. package/dist/service/Service.js +228 -39
  35. package/dist/service/Service.js.map +1 -1
  36. package/dist/service/Service.test.js +558 -22
  37. package/dist/service/Service.test.js.map +1 -1
  38. package/dist/types/Models.d.ts +7 -1
  39. package/dist/types/Models.d.ts.map +1 -1
  40. package/dist/types/Models.js +5 -1
  41. package/dist/types/Models.js.map +1 -1
  42. package/dist/types/ToolError.d.ts +72 -0
  43. package/dist/types/ToolError.d.ts.map +1 -0
  44. package/dist/types/ToolError.js +107 -0
  45. package/dist/types/ToolError.js.map +1 -0
  46. package/dist/types/ToolError.test.d.ts +2 -0
  47. package/dist/types/ToolError.test.d.ts.map +1 -0
  48. package/dist/types/ToolError.test.js +185 -0
  49. package/dist/types/ToolError.test.js.map +1 -0
  50. package/dist/validation/ParameterValidator.d.ts +31 -0
  51. package/dist/validation/ParameterValidator.d.ts.map +1 -0
  52. package/dist/validation/ParameterValidator.js +129 -0
  53. package/dist/validation/ParameterValidator.js.map +1 -0
  54. package/dist/validation/ParameterValidator.test.d.ts +2 -0
  55. package/dist/validation/ParameterValidator.test.d.ts.map +1 -0
  56. package/dist/validation/ParameterValidator.test.js +323 -0
  57. package/dist/validation/ParameterValidator.test.js.map +1 -0
  58. package/package.json +3 -3
  59. package/src/auth/AuthUtils.test.ts +176 -157
  60. package/src/auth/AuthUtils.ts +96 -33
  61. package/src/function/GlobalToolFunction.test.ts +78 -14
  62. package/src/function/GlobalToolFunction.ts +46 -11
  63. package/src/function/ToolFunction.test.ts +298 -13
  64. package/src/function/ToolFunction.ts +61 -13
  65. package/src/index.ts +2 -1
  66. package/src/logging/ToolLogger.test.ts +1020 -0
  67. package/src/logging/ToolLogger.ts +292 -0
  68. package/src/service/Service.test.ts +712 -28
  69. package/src/service/Service.ts +288 -38
  70. package/src/types/Models.ts +8 -1
  71. package/src/types/ToolError.test.ts +222 -0
  72. package/src/types/ToolError.ts +125 -0
  73. package/src/validation/ParameterValidator.test.ts +371 -0
  74. package/src/validation/ParameterValidator.ts +150 -0
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-call */
2
2
  import { getAppContext, logger } from '@zaiusinc/app-sdk';
3
3
  import { getTokenVerifier } from './TokenVerifier';
4
- import { authenticateRegularRequest, authenticateGlobalRequest } from './AuthUtils';
4
+ import { authenticateRegularRequest, authenticateGlobalRequest, authenticateInternalRequest } from './AuthUtils';
5
+ import { ToolError } from '../types/ToolError';
5
6
 
6
7
  // Mock the dependencies
7
8
  jest.mock('./TokenVerifier', () => ({
@@ -50,31 +51,27 @@ describe('AuthUtils', () => {
50
51
  });
51
52
 
52
53
  describe('when request is for discovery endpoint', () => {
53
- it('should return true without authentication', async () => {
54
+ it('should succeed without authentication', async () => {
54
55
  const request = { path: '/discovery' };
55
56
 
56
- const result = await authenticateRegularRequest(request);
57
-
58
- expect(result).toBe(true);
57
+ await expect(authenticateRegularRequest(request)).resolves.toBeUndefined();
59
58
  expect(mockGetTokenVerifier).not.toHaveBeenCalled();
60
59
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
61
60
  });
62
61
  });
63
62
 
64
63
  describe('when request is for ready endpoint', () => {
65
- it('should return true without authentication', async () => {
64
+ it('should succeed without authentication', async () => {
66
65
  const request = { path: '/ready' };
67
66
 
68
- const result = await authenticateRegularRequest(request);
69
-
70
- expect(result).toBe(true);
67
+ await expect(authenticateRegularRequest(request)).resolves.toBeUndefined();
71
68
  expect(mockGetTokenVerifier).not.toHaveBeenCalled();
72
69
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
73
70
  });
74
71
  });
75
72
 
76
73
  describe('when request has valid authentication', () => {
77
- it('should return true for valid OptiID token with matching organization', async () => {
74
+ it('should succeed for valid OptiID token with matching organization', async () => {
78
75
  const request = {
79
76
  path: '/some-tool',
80
77
  bodyJSON: {
@@ -88,9 +85,7 @@ describe('AuthUtils', () => {
88
85
  }
89
86
  };
90
87
 
91
- const result = await authenticateRegularRequest(request);
92
-
93
- expect(result).toBe(true);
88
+ await expect(authenticateRegularRequest(request)).resolves.toBeUndefined();
94
89
  expect(mockGetTokenVerifier).toHaveBeenCalled();
95
90
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
96
91
  });
@@ -109,9 +104,7 @@ describe('AuthUtils', () => {
109
104
  }
110
105
  };
111
106
 
112
- const result = await authenticateRegularRequest(request);
113
-
114
- expect(result).toBe(true);
107
+ await expect(authenticateRegularRequest(request)).resolves.toBeUndefined();
115
108
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
116
109
  });
117
110
 
@@ -129,39 +122,31 @@ describe('AuthUtils', () => {
129
122
  }
130
123
  };
131
124
 
132
- const result = await authenticateRegularRequest(request);
133
-
134
- expect(result).toBe(true);
125
+ await expect(authenticateRegularRequest(request)).resolves.toBeUndefined();
135
126
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
136
127
  });
137
128
  });
138
129
 
139
130
  describe('when authentication fails', () => {
140
- it('should return false when auth data is missing', async () => {
131
+ it('should throw ToolError when auth data is missing', async () => {
141
132
  const request = {
142
133
  path: '/some-tool',
143
134
  bodyJSON: {}
144
135
  };
145
136
 
146
- const result = await authenticateRegularRequest(request);
147
-
148
- expect(result).toBe(false);
149
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
137
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
150
138
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
151
139
  });
152
140
 
153
- it('should return false when bodyJSON is missing', async () => {
141
+ it('should throw ToolError when bodyJSON is missing', async () => {
154
142
  const request = {
155
143
  path: '/some-tool'
156
144
  };
157
145
 
158
- const result = await authenticateRegularRequest(request);
159
-
160
- expect(result).toBe(false);
161
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
146
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
162
147
  });
163
148
 
164
- it('should return false when provider is not OptiID', async () => {
149
+ it('should throw ToolError when provider is not OptiID', async () => {
165
150
  const request = {
166
151
  path: '/some-tool',
167
152
  bodyJSON: {
@@ -175,13 +160,10 @@ describe('AuthUtils', () => {
175
160
  }
176
161
  };
177
162
 
178
- const result = await authenticateRegularRequest(request);
179
-
180
- expect(result).toBe(false);
181
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
163
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
182
164
  });
183
165
 
184
- it('should return false when access token is missing', async () => {
166
+ it('should throw ToolError when access token is missing', async () => {
185
167
  const request = {
186
168
  path: '/some-tool',
187
169
  bodyJSON: {
@@ -195,13 +177,10 @@ describe('AuthUtils', () => {
195
177
  }
196
178
  };
197
179
 
198
- const result = await authenticateRegularRequest(request);
199
-
200
- expect(result).toBe(false);
201
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
180
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
202
181
  });
203
182
 
204
- it('should return false when access token is empty string', async () => {
183
+ it('should throw ToolError when access token is empty string', async () => {
205
184
  const request = {
206
185
  path: '/some-tool',
207
186
  bodyJSON: {
@@ -215,13 +194,10 @@ describe('AuthUtils', () => {
215
194
  }
216
195
  };
217
196
 
218
- const result = await authenticateRegularRequest(request);
219
-
220
- expect(result).toBe(false);
221
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
197
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
222
198
  });
223
199
 
224
- it('should return false when access token is undefined', async () => {
200
+ it('should throw ToolError when access token is undefined', async () => {
225
201
  const request = {
226
202
  path: '/some-tool',
227
203
  bodyJSON: {
@@ -235,15 +211,12 @@ describe('AuthUtils', () => {
235
211
  }
236
212
  };
237
213
 
238
- const result = await authenticateRegularRequest(request);
239
-
240
- expect(result).toBe(false);
241
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
214
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
242
215
  });
243
216
  });
244
217
 
245
218
  describe('when organization validation fails', () => {
246
- it('should return false when customer_id does not match app organization', async () => {
219
+ it('should throw ToolError when customer_id does not match app organization', async () => {
247
220
  const request = {
248
221
  path: '/some-tool',
249
222
  bodyJSON: {
@@ -257,16 +230,11 @@ describe('AuthUtils', () => {
257
230
  }
258
231
  };
259
232
 
260
- const result = await authenticateRegularRequest(request);
261
-
262
- expect(result).toBe(false);
263
- expect(logger.error).toHaveBeenCalledWith(
264
- 'Invalid organisation ID: expected test-org-123, received different-org-456'
265
- );
233
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
266
234
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
267
235
  });
268
236
 
269
- it('should return false when customer_id is missing', async () => {
237
+ it('should throw ToolError when customer_id is missing', async () => {
270
238
  const request = {
271
239
  path: '/some-tool',
272
240
  bodyJSON: {
@@ -280,13 +248,10 @@ describe('AuthUtils', () => {
280
248
  }
281
249
  };
282
250
 
283
- const result = await authenticateRegularRequest(request);
284
-
285
- expect(result).toBe(false);
286
- expect(logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
251
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
287
252
  });
288
253
 
289
- it('should return false when customer_id is empty string', async () => {
254
+ it('should throw ToolError when customer_id is empty string', async () => {
290
255
  const request = {
291
256
  path: '/some-tool',
292
257
  bodyJSON: {
@@ -300,10 +265,7 @@ describe('AuthUtils', () => {
300
265
  }
301
266
  };
302
267
 
303
- const result = await authenticateRegularRequest(request);
304
-
305
- expect(result).toBe(false);
306
- expect(logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
268
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
307
269
  });
308
270
 
309
271
  it('should handle case when app context has no account', async () => {
@@ -322,12 +284,7 @@ describe('AuthUtils', () => {
322
284
  }
323
285
  };
324
286
 
325
- const result = await authenticateRegularRequest(request);
326
-
327
- expect(result).toBe(false);
328
- expect(logger.error).toHaveBeenCalledWith(
329
- 'Invalid organisation ID: expected undefined, received some-org-123'
330
- );
287
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
331
288
  });
332
289
 
333
290
  it('should handle case when app context is null', async () => {
@@ -346,17 +303,12 @@ describe('AuthUtils', () => {
346
303
  }
347
304
  };
348
305
 
349
- const result = await authenticateRegularRequest(request);
350
-
351
- expect(result).toBe(false);
352
- expect(logger.error).toHaveBeenCalledWith(
353
- 'Invalid organisation ID: expected undefined, received some-org-123'
354
- );
306
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
355
307
  });
356
308
  });
357
309
 
358
310
  describe('when token validation fails', () => {
359
- it('should return false when token verifier returns false', async () => {
311
+ it('should throw ToolError when token verifier returns false', async () => {
360
312
  mockTokenVerifier.verify.mockResolvedValue(false);
361
313
 
362
314
  const request = {
@@ -372,13 +324,11 @@ describe('AuthUtils', () => {
372
324
  }
373
325
  };
374
326
 
375
- const result = await authenticateRegularRequest(request);
376
-
377
- expect(result).toBe(false);
327
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
378
328
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('invalid-token');
379
329
  });
380
330
 
381
- it('should return false when token verification throws an error', async () => {
331
+ it('should throw ToolError when token verification throws an error', async () => {
382
332
  const verificationError = new Error('Token verification failed');
383
333
  mockTokenVerifier.verify.mockRejectedValue(verificationError);
384
334
 
@@ -395,13 +345,10 @@ describe('AuthUtils', () => {
395
345
  }
396
346
  };
397
347
 
398
- const result = await authenticateRegularRequest(request);
399
-
400
- expect(result).toBe(false);
401
- expect(logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verificationError);
348
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
402
349
  });
403
350
 
404
- it('should return false when getTokenVerifier throws an error', async () => {
351
+ it('should throw ToolError when getTokenVerifier throws an error', async () => {
405
352
  const verifierError = new Error('Failed to get token verifier');
406
353
  mockGetTokenVerifier.mockRejectedValue(verifierError);
407
354
 
@@ -418,10 +365,7 @@ describe('AuthUtils', () => {
418
365
  }
419
366
  };
420
367
 
421
- const result = await authenticateRegularRequest(request);
422
-
423
- expect(result).toBe(false);
424
- expect(logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verifierError);
368
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
425
369
  });
426
370
  });
427
371
  });
@@ -433,31 +377,27 @@ describe('AuthUtils', () => {
433
377
  });
434
378
 
435
379
  describe('when request is for discovery endpoint', () => {
436
- it('should return true without authentication', async () => {
380
+ it('should succeed without authentication', async () => {
437
381
  const request = { path: '/discovery' };
438
382
 
439
- const result = await authenticateGlobalRequest(request);
440
-
441
- expect(result).toBe(true);
383
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
442
384
  expect(mockGetTokenVerifier).not.toHaveBeenCalled();
443
385
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
444
386
  });
445
387
  });
446
388
 
447
389
  describe('when request is for ready endpoint', () => {
448
- it('should return true without authentication', async () => {
390
+ it('should succeed without authentication', async () => {
449
391
  const request = { path: '/ready' };
450
392
 
451
- const result = await authenticateGlobalRequest(request);
452
-
453
- expect(result).toBe(true);
393
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
454
394
  expect(mockGetTokenVerifier).not.toHaveBeenCalled();
455
395
  expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
456
396
  });
457
397
  });
458
398
 
459
399
  describe('when request has valid authentication', () => {
460
- it('should return true for valid OptiID token regardless of organization', async () => {
400
+ it('should succeed for valid OptiID token regardless of organization', async () => {
461
401
  const request = {
462
402
  path: '/global-tool',
463
403
  bodyJSON: {
@@ -471,9 +411,7 @@ describe('AuthUtils', () => {
471
411
  }
472
412
  };
473
413
 
474
- const result = await authenticateGlobalRequest(request);
475
-
476
- expect(result).toBe(true);
414
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
477
415
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
478
416
  // Should not log organization validation errors for global requests
479
417
  expect(logger.error).not.toHaveBeenCalledWith(
@@ -481,7 +419,7 @@ describe('AuthUtils', () => {
481
419
  );
482
420
  });
483
421
 
484
- it('should return true even without customer_id', async () => {
422
+ it('should succeed even without customer_id', async () => {
485
423
  const request = {
486
424
  path: '/global-tool',
487
425
  bodyJSON: {
@@ -495,9 +433,7 @@ describe('AuthUtils', () => {
495
433
  }
496
434
  };
497
435
 
498
- const result = await authenticateGlobalRequest(request);
499
-
500
- expect(result).toBe(true);
436
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
501
437
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
502
438
  });
503
439
 
@@ -515,27 +451,22 @@ describe('AuthUtils', () => {
515
451
  }
516
452
  };
517
453
 
518
- const result = await authenticateGlobalRequest(request);
519
-
520
- expect(result).toBe(true);
454
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
521
455
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
522
456
  });
523
457
  });
524
458
 
525
459
  describe('when authentication fails', () => {
526
- it('should return false when auth data is missing', async () => {
460
+ it('should throw ToolError when auth data is missing', async () => {
527
461
  const request = {
528
462
  path: '/global-tool',
529
463
  bodyJSON: {}
530
464
  };
531
465
 
532
- const result = await authenticateGlobalRequest(request);
533
-
534
- expect(result).toBe(false);
535
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
466
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
536
467
  });
537
468
 
538
- it('should return false when provider is not OptiID', async () => {
469
+ it('should throw ToolError when provider is not OptiID', async () => {
539
470
  const request = {
540
471
  path: '/global-tool',
541
472
  bodyJSON: {
@@ -549,13 +480,10 @@ describe('AuthUtils', () => {
549
480
  }
550
481
  };
551
482
 
552
- const result = await authenticateGlobalRequest(request);
553
-
554
- expect(result).toBe(false);
555
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
483
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
556
484
  });
557
485
 
558
- it('should return false when access token is missing', async () => {
486
+ it('should throw ToolError when access token is missing', async () => {
559
487
  const request = {
560
488
  path: '/global-tool',
561
489
  bodyJSON: {
@@ -569,13 +497,10 @@ describe('AuthUtils', () => {
569
497
  }
570
498
  };
571
499
 
572
- const result = await authenticateGlobalRequest(request);
573
-
574
- expect(result).toBe(false);
575
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
500
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
576
501
  });
577
502
 
578
- it('should return false when access token is empty', async () => {
503
+ it('should throw ToolError when access token is empty', async () => {
579
504
  const request = {
580
505
  path: '/global-tool',
581
506
  bodyJSON: {
@@ -589,15 +514,12 @@ describe('AuthUtils', () => {
589
514
  }
590
515
  };
591
516
 
592
- const result = await authenticateGlobalRequest(request);
593
-
594
- expect(result).toBe(false);
595
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
517
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
596
518
  });
597
519
  });
598
520
 
599
521
  describe('when token validation fails', () => {
600
- it('should return false when token verifier returns false', async () => {
522
+ it('should throw ToolError when token verifier returns false', async () => {
601
523
  mockTokenVerifier.verify.mockResolvedValue(false);
602
524
 
603
525
  const request = {
@@ -613,13 +535,11 @@ describe('AuthUtils', () => {
613
535
  }
614
536
  };
615
537
 
616
- const result = await authenticateGlobalRequest(request);
617
-
618
- expect(result).toBe(false);
538
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
619
539
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('invalid-token');
620
540
  });
621
541
 
622
- it('should return false when token verification throws an error', async () => {
542
+ it('should throw ToolError when token verification throws an error', async () => {
623
543
  const verificationError = new Error('Global token verification failed');
624
544
  mockTokenVerifier.verify.mockRejectedValue(verificationError);
625
545
 
@@ -636,10 +556,7 @@ describe('AuthUtils', () => {
636
556
  }
637
557
  };
638
558
 
639
- const result = await authenticateGlobalRequest(request);
640
-
641
- expect(result).toBe(false);
642
- expect(logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verificationError);
559
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
643
560
  });
644
561
  });
645
562
 
@@ -658,9 +575,7 @@ describe('AuthUtils', () => {
658
575
  }
659
576
  };
660
577
 
661
- const result = await authenticateGlobalRequest(request);
662
-
663
- expect(result).toBe(true);
578
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
664
579
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
665
580
  // Should NOT log organization validation errors
666
581
  expect(logger.error).not.toHaveBeenCalledWith(
@@ -687,9 +602,7 @@ describe('AuthUtils', () => {
687
602
  }
688
603
  };
689
604
 
690
- const result = await authenticateGlobalRequest(request);
691
-
692
- expect(result).toBe(true);
605
+ await expect(authenticateGlobalRequest(request)).resolves.toBeUndefined();
693
606
  expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
694
607
  });
695
608
  });
@@ -702,12 +615,8 @@ describe('AuthUtils', () => {
702
615
  bodyJSON: null
703
616
  };
704
617
 
705
- const result1 = await authenticateRegularRequest(request);
706
- const result2 = await authenticateGlobalRequest(request);
707
-
708
- expect(result1).toBe(false);
709
- expect(result2).toBe(false);
710
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
618
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
619
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
711
620
  });
712
621
 
713
622
  it('should handle malformed auth objects', async () => {
@@ -718,12 +627,122 @@ describe('AuthUtils', () => {
718
627
  }
719
628
  };
720
629
 
721
- const result1 = await authenticateRegularRequest(request);
722
- const result2 = await authenticateGlobalRequest(request);
630
+ await expect(authenticateRegularRequest(request)).rejects.toThrow(ToolError);
631
+ await expect(authenticateGlobalRequest(request)).rejects.toThrow(ToolError);
632
+ });
633
+ });
634
+
635
+ describe('authenticateInternalRequest', () => {
636
+ it('should return true for valid OptiID token in Authorization header', async () => {
637
+ mockTokenVerifier.verify.mockResolvedValue(true);
638
+
639
+ const mockRequest = {
640
+ headers: {
641
+ get: jest.fn().mockImplementation((name: string) => {
642
+ if (name === 'Authorization') return 'valid-internal-token';
643
+ return null;
644
+ })
645
+ }
646
+ } as any;
647
+
648
+ await expect(authenticateInternalRequest(mockRequest)).resolves.toBeUndefined();
649
+ expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-internal-token');
650
+ });
651
+
652
+ it('should return true for valid OptiID token in lowercase header', async () => {
653
+ mockTokenVerifier.verify.mockResolvedValue(true);
654
+
655
+ const mockRequest = {
656
+ headers: {
657
+ get: jest.fn().mockImplementation((name: string) => {
658
+ if (name === 'authorization') return 'valid-internal-token';
659
+ return null;
660
+ })
661
+ }
662
+ } as any;
663
+
664
+ await expect(authenticateInternalRequest(mockRequest)).resolves.toBeUndefined();
665
+ expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-internal-token');
666
+ });
667
+
668
+ it('should throw ToolError when Authorization header is missing', async () => {
669
+ const mockRequest = {
670
+ headers: {
671
+ get: jest.fn().mockReturnValue(null) // No Authorization header
672
+ }
673
+ } as any;
674
+
675
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
676
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
677
+ });
678
+
679
+ it('should throw ToolError when headers object is missing', async () => {
680
+ const mockRequest = {} as any; // No headers object
681
+
682
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
683
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
684
+ });
685
+
686
+ it('should throw ToolError when token verification fails', async () => {
687
+ mockTokenVerifier.verify.mockResolvedValue(false);
688
+
689
+ const mockRequest = {
690
+ headers: {
691
+ get: jest.fn().mockImplementation((name: string) => {
692
+ if (name === 'Authorization') return 'invalid-token';
693
+ return null;
694
+ })
695
+ }
696
+ } as any;
697
+
698
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
699
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
700
+ });
701
+
702
+ it('should throw ToolError when token verifier throws an error', async () => {
703
+ mockTokenVerifier.verify.mockRejectedValue(new Error('Token service unavailable'));
704
+
705
+ const mockRequest = {
706
+ headers: {
707
+ get: jest.fn().mockImplementation((name: string) => {
708
+ if (name === 'Authorization') return 'some-token';
709
+ return null;
710
+ })
711
+ }
712
+ } as any;
713
+
714
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
715
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
716
+ });
717
+
718
+ it('should throw ToolError when token verification throws an error', async () => {
719
+ mockTokenVerifier.verify.mockRejectedValue(new Error('Service error'));
720
+
721
+ const mockRequest = {
722
+ headers: {
723
+ get: jest.fn().mockImplementation((name: string) => {
724
+ if (name === 'Authorization') return 'valid-token';
725
+ return null;
726
+ })
727
+ }
728
+ } as any;
729
+
730
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
731
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
732
+ });
733
+
734
+ it('should handle empty string token', async () => {
735
+ const mockRequest = {
736
+ headers: {
737
+ get: jest.fn().mockImplementation((name: string) => {
738
+ if (name === 'Authorization') return '';
739
+ return null;
740
+ })
741
+ }
742
+ } as any;
723
743
 
724
- expect(result1).toBe(false);
725
- expect(result2).toBe(false);
726
- expect(logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
744
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow(ToolError);
745
+ await expect(authenticateInternalRequest(mockRequest)).rejects.toThrow('Unauthorized');
727
746
  });
728
747
  });
729
748
  });