@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.
- package/README.md +22 -2
- package/dist/decorator/Decorator.test.js.map +1 -1
- package/dist/function/ToolFunction.d.ts +7 -0
- package/dist/function/ToolFunction.d.ts.map +1 -1
- package/dist/function/ToolFunction.js +14 -0
- package/dist/function/ToolFunction.js.map +1 -1
- package/dist/function/ToolFunction.test.js +122 -0
- package/dist/function/ToolFunction.test.js.map +1 -1
- package/dist/service/Service.d.ts +8 -7
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js.map +1 -1
- package/dist/service/Service.test.js +45 -33
- package/dist/service/Service.test.js.map +1 -1
- package/package.json +3 -3
- package/src/decorator/Decorator.test.ts +4 -4
- package/src/function/ToolFunction.test.ts +143 -0
- package/src/function/ToolFunction.ts +16 -1
- package/src/service/Service.test.ts +47 -34
- package/src/service/Service.ts +7 -5
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
649
|
+
mockToolFunction, // functionContext
|
|
637
650
|
{ param1: 'test-value' },
|
|
638
651
|
authData
|
|
639
652
|
);
|
package/src/service/Service.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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 {
|