@optimizely-opal/opal-tool-ocp-sdk 0.0.0-devmg.13 → 1.0.0-OCP-1441.1

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 (62) hide show
  1. package/README.md +108 -15
  2. package/dist/auth/AuthUtils.d.ts +26 -0
  3. package/dist/auth/AuthUtils.d.ts.map +1 -0
  4. package/dist/auth/AuthUtils.js +109 -0
  5. package/dist/auth/AuthUtils.js.map +1 -0
  6. package/dist/auth/AuthUtils.test.d.ts +2 -0
  7. package/dist/auth/AuthUtils.test.d.ts.map +1 -0
  8. package/dist/auth/AuthUtils.test.js +601 -0
  9. package/dist/auth/AuthUtils.test.js.map +1 -0
  10. package/dist/auth/TokenVerifier.d.ts.map +1 -1
  11. package/dist/auth/TokenVerifier.js +0 -1
  12. package/dist/auth/TokenVerifier.js.map +1 -1
  13. package/dist/auth/TokenVerifier.test.js +9 -0
  14. package/dist/auth/TokenVerifier.test.js.map +1 -1
  15. package/dist/function/GlobalToolFunction.d.ts +27 -0
  16. package/dist/function/GlobalToolFunction.d.ts.map +1 -0
  17. package/dist/function/GlobalToolFunction.js +53 -0
  18. package/dist/function/GlobalToolFunction.js.map +1 -0
  19. package/dist/function/GlobalToolFunction.test.d.ts +2 -0
  20. package/dist/function/GlobalToolFunction.test.d.ts.map +1 -0
  21. package/dist/function/GlobalToolFunction.test.js +425 -0
  22. package/dist/function/GlobalToolFunction.test.js.map +1 -0
  23. package/dist/function/ToolFunction.d.ts +1 -2
  24. package/dist/function/ToolFunction.d.ts.map +1 -1
  25. package/dist/function/ToolFunction.js +2 -35
  26. package/dist/function/ToolFunction.js.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/service/Service.d.ts +8 -7
  32. package/dist/service/Service.d.ts.map +1 -1
  33. package/dist/service/Service.js +13 -0
  34. package/dist/service/Service.js.map +1 -1
  35. package/dist/service/Service.test.js +86 -4
  36. package/dist/service/Service.test.js.map +1 -1
  37. package/dist/validation/ParameterValidator.d.ts +42 -0
  38. package/dist/validation/ParameterValidator.d.ts.map +1 -0
  39. package/dist/validation/ParameterValidator.js +122 -0
  40. package/dist/validation/ParameterValidator.js.map +1 -0
  41. package/dist/validation/ParameterValidator.test.d.ts +2 -0
  42. package/dist/validation/ParameterValidator.test.d.ts.map +1 -0
  43. package/dist/validation/ParameterValidator.test.js +282 -0
  44. package/dist/validation/ParameterValidator.test.js.map +1 -0
  45. package/package.json +3 -4
  46. package/src/auth/AuthUtils.test.ts +729 -0
  47. package/src/auth/AuthUtils.ts +117 -0
  48. package/src/auth/TokenVerifier.test.ts +11 -0
  49. package/src/auth/TokenVerifier.ts +0 -1
  50. package/src/function/GlobalToolFunction.test.ts +505 -0
  51. package/src/function/GlobalToolFunction.ts +56 -0
  52. package/src/function/ToolFunction.ts +3 -41
  53. package/src/index.ts +1 -0
  54. package/src/service/Service.test.ts +126 -12
  55. package/src/service/Service.ts +47 -9
  56. package/src/validation/ParameterValidator.test.ts +341 -0
  57. package/src/validation/ParameterValidator.ts +153 -0
  58. package/dist/function/ToolFunction.test.d.ts +0 -2
  59. package/dist/function/ToolFunction.test.d.ts.map +0 -1
  60. package/dist/function/ToolFunction.test.js +0 -314
  61. package/dist/function/ToolFunction.test.js.map +0 -1
  62. package/src/function/ToolFunction.test.ts +0 -374
@@ -1,374 +0,0 @@
1
- import { ToolFunction } from './ToolFunction';
2
- import { toolsService } from '../service/Service';
3
- import { Response, getAppContext } from '@zaiusinc/app-sdk';
4
- import { getTokenVerifier } from '../auth/TokenVerifier';
5
-
6
- // Mock the dependencies
7
- jest.mock('../service/Service', () => ({
8
- toolsService: {
9
- processRequest: jest.fn(),
10
- },
11
- }));
12
-
13
- jest.mock('../auth/TokenVerifier', () => ({
14
- getTokenVerifier: jest.fn(),
15
- }));
16
-
17
- jest.mock('@zaiusinc/app-sdk', () => ({
18
- Function: class {
19
- protected request: any;
20
- public constructor(_name?: string) {
21
- this.request = {};
22
- }
23
- },
24
- Request: jest.fn().mockImplementation(() => ({})),
25
- Response: jest.fn().mockImplementation((status, data) => ({
26
- status,
27
- data,
28
- bodyJSON: data,
29
- bodyAsU8Array: new Uint8Array()
30
- })),
31
- amendLogContext: jest.fn(),
32
- getAppContext: jest.fn(),
33
- logger: {
34
- info: jest.fn(),
35
- error: jest.fn(),
36
- warn: jest.fn(),
37
- debug: jest.fn(),
38
- },
39
- }));
40
-
41
- // Create a concrete implementation for testing
42
- class TestToolFunction extends ToolFunction {
43
- private mockReady: jest.MockedFunction<() => Promise<boolean>>;
44
-
45
- public constructor(request?: any) {
46
- super(request || {});
47
- (this as any).request = request;
48
- this.mockReady = jest.fn().mockResolvedValue(true);
49
- }
50
-
51
- // Override the ready method with mock implementation for testing
52
- protected ready(): Promise<boolean> {
53
- return this.mockReady();
54
- }
55
-
56
- public getRequest() {
57
- return (this as any).request;
58
- }
59
-
60
- public getMockReady() {
61
- return this.mockReady;
62
- }
63
- }
64
-
65
- describe('ToolFunction', () => {
66
- let mockRequest: any;
67
- let mockResponse: Response;
68
- let toolFunction: TestToolFunction;
69
- let mockProcessRequest: jest.MockedFunction<typeof toolsService.processRequest>;
70
- let mockGetTokenVerifier: jest.MockedFunction<typeof getTokenVerifier>;
71
- let mockGetAppContext: jest.MockedFunction<typeof getAppContext>;
72
- let mockTokenVerifier: jest.Mocked<{
73
- verify: (token: string) => Promise<any>;
74
- }>;
75
-
76
- beforeEach(() => {
77
- jest.clearAllMocks();
78
-
79
- // Create mock token verifier
80
- mockTokenVerifier = {
81
- verify: jest.fn(),
82
- };
83
-
84
- // Setup the mocks
85
- mockProcessRequest = jest.mocked(toolsService.processRequest);
86
- mockGetTokenVerifier = jest.mocked(getTokenVerifier);
87
- mockGetAppContext = jest.mocked(getAppContext);
88
-
89
- mockGetTokenVerifier.mockResolvedValue(mockTokenVerifier as any);
90
- mockGetAppContext.mockReturnValue({
91
- account: {
92
- organizationId: 'app-org-123'
93
- }
94
- } as any);
95
-
96
- // Create mock request with bodyJSON structure
97
- mockRequest = {
98
- headers: new Map(),
99
- method: 'POST',
100
- path: '/test',
101
- bodyJSON: {
102
- parameters: {
103
- task_id: 'task-123',
104
- content_id: 'content-456'
105
- },
106
- auth: {
107
- provider: 'OptiID',
108
- credentials: {
109
- token_type: 'Bearer',
110
- access_token: 'valid-access-token',
111
- org_sso_id: 'org-sso-123',
112
- user_id: 'user-456',
113
- instance_id: 'instance-789',
114
- customer_id: 'app-org-123',
115
- product_sku: 'OPAL'
116
- }
117
- },
118
- environment: {
119
- execution_mode: 'headless'
120
- }
121
- }
122
- };
123
-
124
- mockResponse = {} as Response;
125
- toolFunction = new TestToolFunction(mockRequest);
126
- });
127
-
128
- // Helper function to create a ready request with valid auth
129
- const createReadyRequestWithAuth = () => ({
130
- headers: new Map(),
131
- method: 'GET',
132
- path: '/ready',
133
- bodyJSON: {
134
- auth: {
135
- provider: 'OptiID',
136
- credentials: {
137
- access_token: 'valid-token',
138
- customer_id: 'app-org-123'
139
- }
140
- }
141
- }
142
- });
143
-
144
- // Helper function to setup authorization mocks to pass
145
- const setupAuthMocks = () => {
146
- mockTokenVerifier.verify.mockResolvedValue(true);
147
- mockGetAppContext.mockReturnValue({
148
- account: {
149
- organizationId: 'app-org-123'
150
- }
151
- } as any);
152
- };
153
-
154
- describe('/ready endpoint', () => {
155
- beforeEach(() => {
156
- setupAuthMocks();
157
- });
158
-
159
- it('should return ready: true when ready method returns true', async () => {
160
- // Arrange
161
- const readyRequest = createReadyRequestWithAuth();
162
-
163
- toolFunction = new TestToolFunction(readyRequest);
164
- toolFunction.getMockReady().mockResolvedValue(true);
165
-
166
- // Act
167
- const result = await toolFunction.perform();
168
-
169
- // Assert
170
- expect(toolFunction.getMockReady()).toHaveBeenCalledTimes(1);
171
- expect(result).toEqual(new Response(200, { ready: true }));
172
- expect(mockProcessRequest).not.toHaveBeenCalled(); // Should not call service
173
- });
174
-
175
- it('should return ready: false when ready method returns false', async () => {
176
- // Arrange
177
- const readyRequest = createReadyRequestWithAuth();
178
-
179
- toolFunction = new TestToolFunction(readyRequest);
180
- toolFunction.getMockReady().mockResolvedValue(false);
181
-
182
- // Act
183
- const result = await toolFunction.perform();
184
-
185
- // Assert
186
- expect(toolFunction.getMockReady()).toHaveBeenCalledTimes(1);
187
- expect(result).toEqual(new Response(200, { ready: false }));
188
- expect(mockProcessRequest).not.toHaveBeenCalled(); // Should not call service
189
- });
190
-
191
- it('should handle ready method throwing an error', async () => {
192
- // Arrange
193
- const readyRequest = createReadyRequestWithAuth();
194
-
195
- toolFunction = new TestToolFunction(readyRequest);
196
- toolFunction.getMockReady().mockRejectedValue(new Error('Ready check failed'));
197
-
198
- // Act & Assert
199
- await expect(toolFunction.perform()).rejects.toThrow('Ready check failed');
200
- expect(toolFunction.getMockReady()).toHaveBeenCalledTimes(1);
201
- expect(mockProcessRequest).not.toHaveBeenCalled(); // Should not call service
202
- });
203
-
204
- it('should use default ready implementation when not overridden', async () => {
205
- // Create a class that doesn't override ready method
206
- class DefaultReadyToolFunction extends ToolFunction {
207
- public constructor(request?: any) {
208
- super(request || {});
209
- (this as any).request = request;
210
- }
211
-
212
- public getRequest() {
213
- return (this as any).request;
214
- }
215
- }
216
-
217
- // Arrange
218
- const readyRequest = createReadyRequestWithAuth();
219
- const defaultToolFunction = new DefaultReadyToolFunction(readyRequest);
220
-
221
- // Act
222
- const result = await defaultToolFunction.perform();
223
-
224
- // Assert - Default implementation should return true
225
- expect(result).toEqual(new Response(200, { ready: true }));
226
- expect(mockProcessRequest).not.toHaveBeenCalled(); // Should not call service
227
- });
228
- });
229
-
230
- describe('perform', () => {
231
- it('should execute successfully with valid token and matching organization', async () => {
232
- // Setup mock token verifier to return true for valid token
233
- mockTokenVerifier.verify.mockResolvedValue(true);
234
- mockProcessRequest.mockResolvedValue(mockResponse);
235
-
236
- const result = await toolFunction.perform();
237
-
238
- expect(result).toBe(mockResponse);
239
- expect(mockGetTokenVerifier).toHaveBeenCalled();
240
- expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-access-token');
241
- expect(mockGetAppContext).toHaveBeenCalled();
242
- expect(mockProcessRequest).toHaveBeenCalledWith(mockRequest, toolFunction);
243
- });
244
-
245
- it('should return 403 response with invalid token', async () => {
246
- // Setup mock token verifier to return false
247
- mockTokenVerifier.verify.mockResolvedValue(false);
248
-
249
- const result = await toolFunction.perform();
250
-
251
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
252
- expect(mockGetTokenVerifier).toHaveBeenCalled();
253
- expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-access-token');
254
- expect(mockProcessRequest).not.toHaveBeenCalled();
255
- });
256
-
257
- it('should return 403 response when organization ID does not match', async () => {
258
- // Update mock request with different customer_id
259
- const requestWithDifferentOrgId = {
260
- ...mockRequest,
261
- bodyJSON: {
262
- ...mockRequest.bodyJSON,
263
- auth: {
264
- ...mockRequest.bodyJSON.auth,
265
- credentials: {
266
- ...mockRequest.bodyJSON.auth.credentials,
267
- customer_id: 'different-org-123'
268
- }
269
- }
270
- }
271
- };
272
-
273
- const toolFunctionWithDifferentOrgId = new TestToolFunction(requestWithDifferentOrgId);
274
-
275
- const result = await toolFunctionWithDifferentOrgId.perform();
276
-
277
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
278
- expect(mockGetAppContext).toHaveBeenCalled();
279
- expect(mockProcessRequest).not.toHaveBeenCalled();
280
- });
281
-
282
- it('should return 403 response when access token is missing', async () => {
283
- // Create request without access token
284
- const requestWithoutToken = {
285
- ...mockRequest,
286
- bodyJSON: {
287
- ...mockRequest.bodyJSON,
288
- auth: {
289
- ...mockRequest.bodyJSON.auth,
290
- credentials: {
291
- ...mockRequest.bodyJSON.auth.credentials,
292
- access_token: undefined
293
- }
294
- }
295
- }
296
- };
297
-
298
- const toolFunctionWithoutToken = new TestToolFunction(requestWithoutToken);
299
-
300
- const result = await toolFunctionWithoutToken.perform();
301
-
302
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
303
- expect(mockGetTokenVerifier).not.toHaveBeenCalled();
304
- expect(mockProcessRequest).not.toHaveBeenCalled();
305
- });
306
-
307
- it('should return 403 response when organisation id is missing', async () => {
308
- // Create request without customer_id
309
- const requestWithoutCustomerId = {
310
- ...mockRequest,
311
- bodyJSON: {
312
- ...mockRequest.bodyJSON,
313
- auth: {
314
- ...mockRequest.bodyJSON.auth,
315
- credentials: {
316
- ...mockRequest.bodyJSON.auth.credentials,
317
- customer_id: undefined
318
- }
319
- }
320
- }
321
- };
322
-
323
- const toolFunctionWithoutCustomerId = new TestToolFunction(requestWithoutCustomerId);
324
-
325
- const result = await toolFunctionWithoutCustomerId.perform();
326
-
327
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
328
- expect(mockGetTokenVerifier).not.toHaveBeenCalled();
329
- expect(mockProcessRequest).not.toHaveBeenCalled();
330
- });
331
-
332
- it('should return 403 response when auth structure is missing', async () => {
333
- // Create request without auth structure
334
- const requestWithoutAuth = {
335
- ...mockRequest,
336
- bodyJSON: {
337
- parameters: mockRequest.bodyJSON.parameters,
338
- environment: mockRequest.bodyJSON.environment
339
- }
340
- };
341
-
342
- const toolFunctionWithoutAuth = new TestToolFunction(requestWithoutAuth);
343
-
344
- const result = await toolFunctionWithoutAuth.perform();
345
-
346
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
347
- expect(mockGetTokenVerifier).not.toHaveBeenCalled();
348
- expect(mockProcessRequest).not.toHaveBeenCalled();
349
- });
350
-
351
- it('should return 403 response when token verifier initialization fails', async () => {
352
- // Setup mock to fail during token verifier initialization
353
- mockGetTokenVerifier.mockRejectedValue(new Error('Failed to initialize token verifier'));
354
-
355
- const result = await toolFunction.perform();
356
-
357
- expect(result).toEqual(new Response(403, { error: 'Forbidden' }));
358
- expect(mockGetTokenVerifier).toHaveBeenCalled();
359
- expect(mockProcessRequest).not.toHaveBeenCalled();
360
- });
361
- });
362
-
363
- describe('inheritance', () => {
364
- it('should be an instance of Function', () => {
365
- // Assert
366
- expect(toolFunction).toBeInstanceOf(ToolFunction);
367
- });
368
-
369
- it('should have access to the request property', () => {
370
- // Assert
371
- expect(toolFunction.getRequest()).toBe(mockRequest);
372
- });
373
- });
374
- });