@optimizely-opal/opal-tool-ocp-sdk 0.0.0-beta.4 → 0.0.0-beta.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.
@@ -22,6 +22,7 @@ jest.mock('@zaiusinc/app-sdk', () => ({
22
22
  describe('ToolsService', () => {
23
23
  let mockTool: Tool<unknown>;
24
24
  let mockInteraction: Interaction<unknown>;
25
+ let mockToolFunction: ToolFunction;
25
26
 
26
27
  beforeEach(() => {
27
28
  // Clear registered functions and interactions before each test
@@ -31,6 +32,14 @@ describe('ToolsService', () => {
31
32
  // Reset all mocks
32
33
  jest.clearAllMocks();
33
34
 
35
+ // Create mock ToolFunction
36
+ mockToolFunction = {
37
+ ready: jest.fn().mockResolvedValue(true),
38
+ perform: jest.fn(),
39
+ validateBearerToken: jest.fn().mockReturnValue(true),
40
+ request: {} as any
41
+ } as any;
42
+
34
43
  // Create mock tool handler
35
44
  const mockToolHandler = jest.fn().mockResolvedValue({ result: 'success' });
36
45
 
@@ -94,7 +103,7 @@ describe('ToolsService', () => {
94
103
  );
95
104
 
96
105
  const discoveryRequest = createMockRequest({ path: '/discovery' });
97
- const response = await toolsService.processRequest(discoveryRequest);
106
+ const response = await toolsService.processRequest(discoveryRequest, mockToolFunction);
98
107
 
99
108
  expect(response.status).toBe(200);
100
109
  expect(response).toHaveProperty('bodyJSON');
@@ -119,7 +128,7 @@ describe('ToolsService', () => {
119
128
 
120
129
  it('should return empty functions array when no tools are registered', async () => {
121
130
  const discoveryRequest = createMockRequest({ path: '/discovery' });
122
- const response = await toolsService.processRequest(discoveryRequest);
131
+ const response = await toolsService.processRequest(discoveryRequest, mockToolFunction);
123
132
 
124
133
  expect(response.status).toBe(200);
125
134
  expect(response.bodyAsU8Array).toBeDefined();
@@ -153,7 +162,7 @@ describe('ToolsService', () => {
153
162
  );
154
163
 
155
164
  const discoveryRequest = createMockRequest({ path: '/discovery' });
156
- const response = await toolsService.processRequest(discoveryRequest);
165
+ const response = await toolsService.processRequest(discoveryRequest, mockToolFunction);
157
166
 
158
167
  expect(response.status).toBe(200);
159
168
 
@@ -199,11 +208,11 @@ describe('ToolsService', () => {
199
208
 
200
209
  it('should execute tool successfully with parameters', async () => {
201
210
  const mockRequest = createMockRequest();
202
- const response = await toolsService.processRequest(mockRequest);
211
+ const response = await toolsService.processRequest(mockRequest, mockToolFunction);
203
212
 
204
213
  expect(response.status).toBe(200);
205
214
  expect(mockTool.handler).toHaveBeenCalledWith(
206
- undefined, // functionContext
215
+ mockToolFunction, // functionContext
207
216
  { param1: 'test-value' },
208
217
  undefined
209
218
  );
@@ -213,8 +222,12 @@ describe('ToolsService', () => {
213
222
  // Create a mock ToolFunction instance
214
223
  const mockToolFunctionInstance = {
215
224
  someProperty: 'test-value',
216
- someMethod: jest.fn()
217
- };
225
+ someMethod: jest.fn(),
226
+ ready: jest.fn().mockResolvedValue(true),
227
+ perform: jest.fn(),
228
+ validateBearerToken: jest.fn().mockReturnValue(true),
229
+ request: {} as any
230
+ } as any;
218
231
 
219
232
  const mockRequest = createMockRequest();
220
233
  const response = await toolsService.processRequest(mockRequest, mockToolFunctionInstance);
@@ -307,11 +320,11 @@ describe('ToolsService', () => {
307
320
  })
308
321
  });
309
322
 
310
- const response = await toolsService.processRequest(requestWithAuth);
323
+ const response = await toolsService.processRequest(requestWithAuth, mockToolFunction);
311
324
 
312
325
  expect(response.status).toBe(200);
313
326
  expect(mockTool.handler).toHaveBeenCalledWith(
314
- undefined, // functionContext
327
+ mockToolFunction, // functionContext
315
328
  { param1: 'test-value' },
316
329
  authData
317
330
  );
@@ -323,11 +336,11 @@ describe('ToolsService', () => {
323
336
  body: JSON.stringify({ param1: 'test-value' })
324
337
  });
325
338
 
326
- const response = await toolsService.processRequest(requestWithoutWrapper);
339
+ const response = await toolsService.processRequest(requestWithoutWrapper, mockToolFunction);
327
340
 
328
341
  expect(response.status).toBe(200);
329
342
  expect(mockTool.handler).toHaveBeenCalledWith(
330
- undefined, // functionContext
343
+ mockToolFunction, // functionContext
331
344
  { param1: 'test-value' },
332
345
  undefined
333
346
  );
@@ -338,7 +351,7 @@ describe('ToolsService', () => {
338
351
  jest.mocked(mockTool.handler).mockRejectedValueOnce(new Error(errorMessage));
339
352
 
340
353
  const mockRequest = createMockRequest();
341
- const response = await toolsService.processRequest(mockRequest);
354
+ const response = await toolsService.processRequest(mockRequest, mockToolFunction);
342
355
 
343
356
  expect(response.status).toBe(500);
344
357
  expect(logger.error).toHaveBeenCalledWith(
@@ -351,7 +364,7 @@ describe('ToolsService', () => {
351
364
  jest.mocked(mockTool.handler).mockRejectedValueOnce({});
352
365
 
353
366
  const mockRequest = createMockRequest();
354
- const response = await toolsService.processRequest(mockRequest);
367
+ const response = await toolsService.processRequest(mockRequest, mockToolFunction);
355
368
 
356
369
  expect(response.status).toBe(500);
357
370
  });
@@ -373,10 +386,10 @@ describe('ToolsService', () => {
373
386
  body: JSON.stringify({ data: { param1: 'test-value' } })
374
387
  });
375
388
 
376
- const response = await toolsService.processRequest(interactionRequest);
389
+ const response = await toolsService.processRequest(interactionRequest, mockToolFunction);
377
390
 
378
391
  expect(response.status).toBe(200);
379
- expect(mockInteraction.handler).toHaveBeenCalledWith(undefined, { param1: 'test-value' }, undefined);
392
+ expect(mockInteraction.handler).toHaveBeenCalledWith(mockToolFunction, { param1: 'test-value' }, undefined);
380
393
  });
381
394
 
382
395
  it('should handle interaction request body without data wrapper', async () => {
@@ -386,10 +399,10 @@ describe('ToolsService', () => {
386
399
  body: JSON.stringify({ param1: 'test-value' })
387
400
  });
388
401
 
389
- const response = await toolsService.processRequest(interactionRequest);
402
+ const response = await toolsService.processRequest(interactionRequest, mockToolFunction);
390
403
 
391
404
  expect(response.status).toBe(200);
392
- expect(mockInteraction.handler).toHaveBeenCalledWith(undefined, { param1: 'test-value' }, undefined);
405
+ expect(mockInteraction.handler).toHaveBeenCalledWith(mockToolFunction, { param1: 'test-value' }, undefined);
393
406
  });
394
407
 
395
408
  it('should execute interaction with OptiID auth data when provided', async () => {
@@ -410,11 +423,11 @@ describe('ToolsService', () => {
410
423
  })
411
424
  });
412
425
 
413
- const response = await toolsService.processRequest(interactionRequest);
426
+ const response = await toolsService.processRequest(interactionRequest, mockToolFunction);
414
427
 
415
428
  expect(response.status).toBe(200);
416
429
  expect(mockInteraction.handler).toHaveBeenCalledWith(
417
- undefined, // functionContext
430
+ mockToolFunction, // functionContext
418
431
  { param1: 'test-value' },
419
432
  authData
420
433
  );
@@ -438,11 +451,11 @@ describe('ToolsService', () => {
438
451
  })
439
452
  });
440
453
 
441
- const response = await toolsService.processRequest(interactionRequest);
454
+ const response = await toolsService.processRequest(interactionRequest, mockToolFunction);
442
455
 
443
456
  expect(response.status).toBe(200);
444
457
  expect(mockInteraction.handler).toHaveBeenCalledWith(
445
- undefined, // functionContext
458
+ mockToolFunction, // functionContext
446
459
  {
447
460
  param1: 'test-value',
448
461
  auth: authData
@@ -460,7 +473,7 @@ describe('ToolsService', () => {
460
473
  bodyJSON: { data: { param1: 'test-value' } }
461
474
  });
462
475
 
463
- const response = await toolsService.processRequest(interactionRequest);
476
+ const response = await toolsService.processRequest(interactionRequest, mockToolFunction);
464
477
 
465
478
  expect(response.status).toBe(500);
466
479
  expect(logger.error).toHaveBeenCalledWith(
@@ -473,7 +486,7 @@ describe('ToolsService', () => {
473
486
  describe('error cases', () => {
474
487
  it('should return 404 when no matching tool or interaction is found', async () => {
475
488
  const unknownRequest = createMockRequest({ path: '/unknown-endpoint' });
476
- const response = await toolsService.processRequest(unknownRequest);
489
+ const response = await toolsService.processRequest(unknownRequest, mockToolFunction);
477
490
 
478
491
  expect(response.status).toBe(404);
479
492
  });
@@ -496,7 +509,7 @@ describe('ToolsService', () => {
496
509
  path: '/optid-auth-tool'
497
510
  });
498
511
 
499
- const response = await toolsService.processRequest(authRequest);
512
+ const response = await toolsService.processRequest(authRequest, mockToolFunction);
500
513
 
501
514
  expect(response.status).toBe(200);
502
515
  });
@@ -517,10 +530,10 @@ describe('ToolsService', () => {
517
530
  body: null
518
531
  });
519
532
 
520
- const response = await toolsService.processRequest(requestWithNullBody);
533
+ const response = await toolsService.processRequest(requestWithNullBody, mockToolFunction);
521
534
 
522
535
  expect(response.status).toBe(200);
523
- expect(mockTool.handler).toHaveBeenCalledWith(undefined, null, undefined);
536
+ expect(mockTool.handler).toHaveBeenCalledWith(mockToolFunction, null, undefined);
524
537
  });
525
538
 
526
539
  it('should handle request with undefined bodyJSON', async () => {
@@ -537,10 +550,10 @@ describe('ToolsService', () => {
537
550
  body: undefined
538
551
  });
539
552
 
540
- const response = await toolsService.processRequest(requestWithUndefinedBody);
553
+ const response = await toolsService.processRequest(requestWithUndefinedBody, mockToolFunction);
541
554
 
542
555
  expect(response.status).toBe(200);
543
- expect(mockTool.handler).toHaveBeenCalledWith(undefined, undefined, undefined);
556
+ expect(mockTool.handler).toHaveBeenCalledWith(mockToolFunction, undefined, undefined);
544
557
  });
545
558
 
546
559
  it('should extract auth data from bodyJSON when body exists', async () => {
@@ -568,11 +581,11 @@ describe('ToolsService', () => {
568
581
  })
569
582
  });
570
583
 
571
- const response = await toolsService.processRequest(requestWithAuth);
584
+ const response = await toolsService.processRequest(requestWithAuth, mockToolFunction);
572
585
 
573
586
  expect(response.status).toBe(200);
574
587
  expect(mockTool.handler).toHaveBeenCalledWith(
575
- undefined, // functionContext
588
+ mockToolFunction, // functionContext
576
589
  { param1: 'test-value' },
577
590
  authData
578
591
  );
@@ -597,11 +610,11 @@ describe('ToolsService', () => {
597
610
  })
598
611
  });
599
612
 
600
- const response = await toolsService.processRequest(requestWithoutAuth);
613
+ const response = await toolsService.processRequest(requestWithoutAuth, mockToolFunction);
601
614
 
602
615
  expect(response.status).toBe(200);
603
616
  expect(mockTool.handler).toHaveBeenCalledWith(
604
- undefined, // functionContext
617
+ mockToolFunction, // functionContext
605
618
  { param1: 'test-value' },
606
619
  undefined
607
620
  );
@@ -629,11 +642,11 @@ describe('ToolsService', () => {
629
642
  body: ''
630
643
  });
631
644
 
632
- const response = await toolsService.processRequest(requestWithAuthButNoBody);
645
+ const response = await toolsService.processRequest(requestWithAuthButNoBody, mockToolFunction);
633
646
 
634
647
  expect(response.status).toBe(200);
635
648
  expect(mockTool.handler).toHaveBeenCalledWith(
636
- undefined, // functionContext
649
+ mockToolFunction, // functionContext
637
650
  { param1: 'test-value' },
638
651
  authData
639
652
  );
@@ -2,6 +2,7 @@
2
2
  import { AuthRequirement, Parameter } from '../types/Models';
3
3
  import * as App from '@zaiusinc/app-sdk';
4
4
  import { logger } from '@zaiusinc/app-sdk';
5
+ import { ToolFunction } from '../function/ToolFunction';
5
6
 
6
7
 
7
8
 
@@ -22,7 +23,7 @@ export class Interaction<TAuthData> {
22
23
  public constructor(
23
24
  public name: string,
24
25
  public endpoint: string,
25
- public handler: (functionContext: any, data: unknown, authData?: TAuthData) => Promise<InteractionResult>
26
+ public handler: (functionContext: ToolFunction, data: unknown, authData?: TAuthData) => Promise<InteractionResult>
26
27
  ) {}
27
28
  }
28
29
 
@@ -49,7 +50,7 @@ export class Tool<TAuthData> {
49
50
  public description: string,
50
51
  public parameters: Parameter[],
51
52
  public endpoint: string,
52
- public handler: (functionContext: any, params: unknown, authData?: TAuthData) => Promise<unknown>,
53
+ public handler: (functionContext: ToolFunction, params: unknown, authData?: TAuthData) => Promise<unknown>,
53
54
  public authRequirements?: AuthRequirement[]
54
55
  ) {}
55
56
 
@@ -104,7 +105,7 @@ export class ToolsService {
104
105
  public registerTool<TAuthData>(
105
106
  name: string,
106
107
  description: string,
107
- handler: (functionContext: any, params: unknown, authData?: TAuthData) => Promise<unknown>,
108
+ handler: (functionContext: ToolFunction, params: unknown, authData?: TAuthData) => Promise<unknown>,
108
109
  parameters: Parameter[],
109
110
  endpoint: string,
110
111
  authRequirements?: AuthRequirement[]
@@ -121,14 +122,15 @@ export class ToolsService {
121
122
  */
122
123
  public registerInteraction<TAuthData>(
123
124
  name: string,
124
- handler: (functionContext: any, data: unknown, authData?: TAuthData) => Promise<InteractionResult>,
125
+ handler: (functionContext: ToolFunction, data: unknown, authData?: TAuthData) => Promise<InteractionResult>,
125
126
  endpoint: string
126
127
  ): void {
127
128
  const func = new Interaction<TAuthData>(name, endpoint, handler);
128
129
  this.interactions.set(endpoint, func);
129
130
  }
130
131
 
131
- public async processRequest(req: App.Request, functionContext?: any): Promise<App.Response> {
132
+ public async processRequest(req: App.Request,
133
+ functionContext: ToolFunction): Promise<App.Response> {
132
134
  if (req.path === '/discovery') {
133
135
  return new App.Response(200, { functions: Array.from(this.functions.values()).map((f) => f.toJSON()) });
134
136
  } else {