@optimizely-opal/opal-tool-ocp-sdk 0.0.0-OCP-1487.9 → 0.0.0-OCP-1487.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.
- package/README.md +29 -70
- package/dist/decorator/Decorator.d.ts +0 -6
- package/dist/decorator/Decorator.d.ts.map +1 -1
- package/dist/decorator/Decorator.js +2 -32
- package/dist/decorator/Decorator.js.map +1 -1
- package/dist/decorator/Decorator.test.js +11 -205
- package/dist/decorator/Decorator.test.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/service/Service.d.ts +2 -20
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js +4 -41
- package/dist/service/Service.js.map +1 -1
- package/dist/service/Service.test.js +1 -92
- package/dist/service/Service.test.js.map +1 -1
- package/package.json +1 -1
- package/src/decorator/Decorator.test.ts +10 -305
- package/src/decorator/Decorator.ts +2 -44
- package/src/index.ts +0 -1
- package/src/service/Service.test.ts +1 -170
- package/src/service/Service.ts +4 -46
- package/dist/utils/ImportUtils.d.ts +0 -15
- package/dist/utils/ImportUtils.d.ts.map +0 -1
- package/dist/utils/ImportUtils.js +0 -77
- package/dist/utils/ImportUtils.js.map +0 -1
- package/src/utils/ImportUtils.ts +0 -45
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A TypeScript SDK for building Opal tools in Optimizely Connect Platform. This SD
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- 🎯 **Decorator-based Tool Registration** - Use `@tool` and `@interaction` decorators to easily register functions
|
|
10
|
-
- 🌐 **Global and Regular
|
|
10
|
+
- 🌐 **Global and Regular Function Modes** - SDK can be used in either global or organization-scoped mode
|
|
11
11
|
- 🔧 **Type-safe Development** - Full TypeScript support with comprehensive type definitions
|
|
12
12
|
- 🏗️ **Abstract Base Classes** - Extend `ToolFunction` or `GlobalToolFunction` for standardized request processing
|
|
13
13
|
- 🔐 **Authentication Support** - OptiID authentication
|
|
@@ -29,14 +29,14 @@ yarn add @optimizely-opal/opal-tool-ocp-sdk
|
|
|
29
29
|
|
|
30
30
|
## Quick Start
|
|
31
31
|
|
|
32
|
-
The SDK supports two
|
|
32
|
+
The SDK supports two function modes:
|
|
33
33
|
|
|
34
|
-
- **Regular Functions** (`ToolFunction`) - Organization-scoped
|
|
35
|
-
- **Global Functions** (`GlobalToolFunction`) - Platform-wide
|
|
34
|
+
- **Regular Functions** (`ToolFunction`) - Organization-scoped functions that validate customer organization IDs
|
|
35
|
+
- **Global Functions** (`GlobalToolFunction`) - Platform-wide functions that work across all organizations
|
|
36
36
|
|
|
37
37
|
### Regular Tool Function
|
|
38
38
|
|
|
39
|
-
Create a tool function class by extending `ToolFunction` for organization-scoped
|
|
39
|
+
Create a tool function class by extending `ToolFunction` for organization-scoped functionality:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
import { ToolFunction, tool, interaction, ParameterType, InteractionResult, OptiIdAuthData } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
@@ -122,7 +122,7 @@ export class MyToolFunction extends ToolFunction {
|
|
|
122
122
|
|
|
123
123
|
### Global Tool Function
|
|
124
124
|
|
|
125
|
-
Create a global tool function by extending `GlobalToolFunction` for platform-wide
|
|
125
|
+
Create a global tool function by extending `GlobalToolFunction` for platform-wide functionality:
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
128
|
import { GlobalToolFunction, tool, interaction, ParameterType, InteractionResult, OptiIdAuthData } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
@@ -151,14 +151,14 @@ export class MyGlobalToolFunction extends GlobalToolFunction {
|
|
|
151
151
|
}
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
### Function
|
|
154
|
+
### Function Modes
|
|
155
155
|
|
|
156
|
-
The SDK
|
|
156
|
+
The SDK operates in one of two modes based on the base class you extend:
|
|
157
157
|
|
|
158
|
-
- **Regular
|
|
159
|
-
- **Global
|
|
158
|
+
- **Regular Function Mode** (`ToolFunction`): All tools are organization-scoped and validate organization IDs
|
|
159
|
+
- **Global Function Mode** (`GlobalToolFunction`): All tools are platform-wide.
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
The discovery endpoint returns all tools registered within that function mode.
|
|
162
162
|
|
|
163
163
|
Your function class inherits a `perform()` method from `ToolFunction` or `GlobalToolFunction` that serves as the main entry point for handling all incoming requests. When called, the SDK automatically:
|
|
164
164
|
|
|
@@ -177,27 +177,25 @@ Tools are functions that can be discovered and executed through the OCP platform
|
|
|
177
177
|
- Define parameters with types and validation
|
|
178
178
|
- Can require authentication
|
|
179
179
|
- Return structured responses
|
|
180
|
-
-
|
|
180
|
+
- Are automatically registered based on the function mode you choose
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
### Function Modes
|
|
183
183
|
|
|
184
|
-
Regular
|
|
184
|
+
#### Regular Functions (`ToolFunction`)
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
186
|
+
Regular functions are scoped to specific organizations and validate that requests come from the same organization:
|
|
187
|
+
|
|
188
|
+
- Validate OptiID organization ID matches the function's organization context
|
|
189
|
+
- All tools within the function are organization-scoped
|
|
190
190
|
- **Per-Organization Configuration**: Can implement organization-specific configuration, authentication credentials, and API keys since they're tied to a single organization
|
|
191
191
|
- **Per-Organization Authentication**: Can store and use organization-specific authentication tokens, connection strings, and other sensitive data securely
|
|
192
192
|
|
|
193
|
-
#### Global
|
|
193
|
+
#### Global Functions (`GlobalToolFunction`)
|
|
194
194
|
|
|
195
|
-
Global
|
|
195
|
+
Global functions work across all organizations without organization validation:
|
|
196
196
|
|
|
197
|
-
- Accept OptiID authentication
|
|
198
|
-
-
|
|
199
|
-
- **Automatic Registration**: Tools defined in classes extending `GlobalToolFunction`
|
|
200
|
-
- **Explicit Registration**: Tools imported using `importAsGlobal()`
|
|
197
|
+
- Accept OptiID authentication
|
|
198
|
+
- All tools within the function are platform-wide
|
|
201
199
|
- **No Per-Organization Configuration**: Cannot implement per-organization configuration since they work across all organizations
|
|
202
200
|
- **No Per-Organization Authentication**: Cannot store organization-specific credentials or authentication data
|
|
203
201
|
- **Global Discovery**: Have a global discovery URL that can be used by any organization without requiring them to install the app first
|
|
@@ -293,41 +291,6 @@ async handlerMethod(
|
|
|
293
291
|
- **params**: The input parameters for tools, or interaction data for webhooks
|
|
294
292
|
- **authData**: Available when OptiID user authentication is configured and successful
|
|
295
293
|
|
|
296
|
-
### Import Utilities
|
|
297
|
-
|
|
298
|
-
The SDK provides utilities for importing tools with specific registration contexts:
|
|
299
|
-
|
|
300
|
-
#### `importAsGlobal(modulePath: string, baseUrl?: string)`
|
|
301
|
-
|
|
302
|
-
Imports a module and registers all decorated tools as global tools.
|
|
303
|
-
|
|
304
|
-
```typescript
|
|
305
|
-
import { importAsGlobal } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
306
|
-
|
|
307
|
-
// Import tools as global
|
|
308
|
-
await importAsGlobal('./global-tools');
|
|
309
|
-
await importAsGlobal('../global-tools', import.meta.url);
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Parameters:**
|
|
313
|
-
- `modulePath`: Path to the module to import (relative or absolute)
|
|
314
|
-
- `baseUrl`: Base URL for resolving relative paths (optional, use `import.meta.url` for relative to current file)
|
|
315
|
-
|
|
316
|
-
#### `importAsRegular(modulePath: string, baseUrl?: string)`
|
|
317
|
-
|
|
318
|
-
Imports a module and registers all decorated tools as regular tools.
|
|
319
|
-
|
|
320
|
-
```typescript
|
|
321
|
-
import { importAsRegular } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
322
|
-
|
|
323
|
-
// Import tools as regular
|
|
324
|
-
await importAsRegular('./tools');
|
|
325
|
-
await importAsRegular('../tools', import.meta.url);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
**Parameters:**
|
|
329
|
-
- `modulePath`: Path to the module to import (relative or absolute)
|
|
330
|
-
- `baseUrl`: Base URL for resolving relative paths (optional, use `import.meta.url` for relative to current file)
|
|
331
294
|
|
|
332
295
|
### Decorators
|
|
333
296
|
|
|
@@ -376,13 +339,13 @@ Extend this class for regular tools that validate organization IDs. The `perform
|
|
|
376
339
|
Abstract base class for global OCP functions:
|
|
377
340
|
|
|
378
341
|
```typescript
|
|
379
|
-
export abstract class GlobalToolFunction extends
|
|
342
|
+
export abstract class GlobalToolFunction extends GlobalFunction {
|
|
380
343
|
protected ready(): Promise<boolean>;
|
|
381
344
|
public async perform(): Promise<Response>;
|
|
382
345
|
}
|
|
383
346
|
```
|
|
384
347
|
|
|
385
|
-
Extend this class for
|
|
348
|
+
Extend this class for tools that work across organizations. The `perform` method routes requests to registered tools but skips organization validation for tools.
|
|
386
349
|
|
|
387
350
|
### Models
|
|
388
351
|
|
|
@@ -401,14 +364,14 @@ The SDK automatically provides two important endpoints:
|
|
|
401
364
|
|
|
402
365
|
### Discovery Endpoint (`/discovery`)
|
|
403
366
|
|
|
404
|
-
Returns registered tools in the proper OCP format for platform integration. The discovery endpoint
|
|
367
|
+
Returns all registered tools in the proper OCP format for platform integration. The discovery endpoint returns all tools registered within the function, regardless of their individual configuration:
|
|
405
368
|
|
|
406
|
-
- **Regular Functions** (`ToolFunction`):
|
|
407
|
-
- **Global Functions** (`GlobalToolFunction`):
|
|
369
|
+
- **Regular Functions** (`ToolFunction`): Returns all tools with organization-scoped behavior
|
|
370
|
+
- **Global Functions** (`GlobalToolFunction`): Returns all tools with platform-wide behavior
|
|
408
371
|
|
|
409
|
-
|
|
372
|
+
All tools within a function operate in the same mode - there is no mixing of global and organization-scoped tools within a single function.
|
|
410
373
|
|
|
411
|
-
Example response for a regular and global function:
|
|
374
|
+
Example response for a regular function and global function:
|
|
412
375
|
|
|
413
376
|
```json
|
|
414
377
|
{
|
|
@@ -562,10 +525,6 @@ src/
|
|
|
562
525
|
│ ├── index.ts
|
|
563
526
|
│ ├── TaskTool.ts
|
|
564
527
|
│ └── NotificationTool.ts
|
|
565
|
-
├── global-tools/
|
|
566
|
-
│ ├── index.ts
|
|
567
|
-
│ ├── UtilityTool.ts
|
|
568
|
-
│ └── AnalyticsTool.ts
|
|
569
528
|
├── MyToolFunction.ts
|
|
570
529
|
└── MyGlobalToolFunction.ts
|
|
571
530
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Decorator.d.ts","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG5E;;GAEG;AACH,
|
|
1
|
+
{"version":3,"file":"Decorator.d.ts","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG5E;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,IACrB,QAAQ,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAkClF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,IACnC,QAAQ,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAqBlF"}
|
|
@@ -4,34 +4,6 @@ exports.tool = tool;
|
|
|
4
4
|
exports.interaction = interaction;
|
|
5
5
|
const Models_1 = require("../types/Models");
|
|
6
6
|
const Service_1 = require("../service/Service");
|
|
7
|
-
/**
|
|
8
|
-
* Helper function to check if a class extends GlobalToolFunction
|
|
9
|
-
*/
|
|
10
|
-
function isGlobalToolFunction(constructor) {
|
|
11
|
-
// Walk up the prototype chain to check for GlobalToolFunction
|
|
12
|
-
let currentConstructor = constructor;
|
|
13
|
-
while (currentConstructor) {
|
|
14
|
-
if (currentConstructor.name === 'GlobalToolFunction') {
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
currentConstructor = Object.getPrototypeOf(currentConstructor);
|
|
18
|
-
}
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Determine if tool should be registered as global based on definition context or import context
|
|
23
|
-
*/
|
|
24
|
-
function shouldRegisterAsGlobal(targetConstructor) {
|
|
25
|
-
// First check if there's an active import context
|
|
26
|
-
if (globalThis.__IMPORT_CONTEXT === 'global') {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
if (globalThis.__IMPORT_CONTEXT === 'regular') {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
// Fallback to checking where the tool is defined
|
|
33
|
-
return isGlobalToolFunction(targetConstructor);
|
|
34
|
-
}
|
|
35
7
|
/**
|
|
36
8
|
* Decorator for registering tool functions
|
|
37
9
|
* Immediately registers the tool with the global ToolsService
|
|
@@ -53,10 +25,8 @@ function tool(config) {
|
|
|
53
25
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
54
26
|
return originalMethod.call(instance, params, authData);
|
|
55
27
|
};
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// Register tool with global flag based on where it's defined or imported
|
|
59
|
-
Service_1.toolsService.registerTool(config.name, config.description, boundHandler, parameters, config.endpoint, authRequirements, isGlobal);
|
|
28
|
+
// Immediately register with global ToolsService
|
|
29
|
+
Service_1.toolsService.registerTool(config.name, config.description, boundHandler, parameters, config.endpoint, authRequirements);
|
|
60
30
|
};
|
|
61
31
|
}
|
|
62
32
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Decorator.js","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"Decorator.js","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":";;AA8CA,oBAmCC;AAOD,kCAsBC;AA9GD,4CAA4E;AAC5E,gDAAkD;AAwClD;;;;GAIG;AACH,SAAgB,IAAI,CAAC,MAAkB;IACrC,OAAO,UAAS,MAAW,EAAE,YAAoB,EAAE,UAA8B;QAC/E,mDAAmD;QACnD,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,IAAI,kBAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CACzD,CAAC;QAEF,gEAAgE;QAChE,MAAM,gBAAgB,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACjE,IAAI,wBAAe,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAC3D,CAAC;QAEF,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC;QAExC,MAAM,YAAY,GAAG,UAAS,eAAoB,EAAE,MAAW,EAAE,QAAa;YAC5E,0EAA0E;YAC1E,uDAAuD;YACvD,MAAM,QAAQ,GAAG,CAAC,eAAe,IAAI,eAAe,YAAY,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;gBACnF,6DAA6D;gBAC7D,eAAe,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,6DAA6D;YAC7D,OAAO,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzD,CAAC,CAAC;QAEF,gDAAgD;QAChD,sBAAY,CAAC,YAAY,CACvB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,WAAW,EAClB,YAAY,EACZ,UAAU,EACV,MAAM,CAAC,QAAQ,EACf,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,MAAyB;IACnD,OAAO,UAAS,MAAW,EAAE,YAAoB,EAAE,UAA8B;QAC/E,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC;QAExC,MAAM,YAAY,GAAG,UAAS,eAAoB,EAAE,IAAS,EAAE,QAAc;YAC3E,0EAA0E;YAC1E,uDAAuD;YACvD,MAAM,QAAQ,GAAG,CAAC,eAAe,IAAI,eAAe,YAAY,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;gBACnF,6DAA6D;gBAC7D,eAAe,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,6DAA6D;YAC7D,OAAO,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvD,CAAC,CAAC;QAEF,gDAAgD;QAChD,sBAAY,CAAC,mBAAmB,CAC9B,MAAM,CAAC,IAAI,EACX,YAAY,EACZ,MAAM,CAAC,QAAQ,CAChB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -16,9 +16,6 @@ jest.mock('../service/Service', () => ({
|
|
|
16
16
|
registerInteraction: jest.fn()
|
|
17
17
|
}
|
|
18
18
|
}));
|
|
19
|
-
// Mock base class for testing auto-detection
|
|
20
|
-
class GlobalToolFunction {
|
|
21
|
-
}
|
|
22
19
|
describe('Decorators', () => {
|
|
23
20
|
beforeEach(() => {
|
|
24
21
|
jest.clearAllMocks();
|
|
@@ -39,7 +36,7 @@ describe('Decorators', () => {
|
|
|
39
36
|
__decorate([
|
|
40
37
|
(0, Decorator_1.tool)(config)
|
|
41
38
|
], TestClass.prototype, "testMethod", null);
|
|
42
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('testTool', 'A test tool', expect.any(Function), [], '/test-tool', []
|
|
39
|
+
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('testTool', 'A test tool', expect.any(Function), [], '/test-tool', []);
|
|
43
40
|
// Ensure TestClass is considered "used" by TypeScript
|
|
44
41
|
expect(TestClass).toBeDefined();
|
|
45
42
|
});
|
|
@@ -71,7 +68,7 @@ describe('Decorators', () => {
|
|
|
71
68
|
description: 'An input parameter',
|
|
72
69
|
required: true
|
|
73
70
|
})
|
|
74
|
-
]), '/tool-with-params', []
|
|
71
|
+
]), '/tool-with-params', []);
|
|
75
72
|
// Ensure TestClass is considered "used" by TypeScript
|
|
76
73
|
expect(TestClass).toBeDefined();
|
|
77
74
|
});
|
|
@@ -102,7 +99,7 @@ describe('Decorators', () => {
|
|
|
102
99
|
scopeBundle: 'calendar',
|
|
103
100
|
required: true
|
|
104
101
|
})
|
|
105
|
-
])
|
|
102
|
+
]));
|
|
106
103
|
// Ensure TestClass is considered "used" by TypeScript
|
|
107
104
|
expect(TestClass).toBeDefined();
|
|
108
105
|
});
|
|
@@ -172,7 +169,7 @@ describe('Decorators', () => {
|
|
|
172
169
|
scopeBundle: 'drive',
|
|
173
170
|
required: false
|
|
174
171
|
})
|
|
175
|
-
])
|
|
172
|
+
]));
|
|
176
173
|
// Ensure TestClass is considered "used" by TypeScript
|
|
177
174
|
expect(TestClass).toBeDefined();
|
|
178
175
|
});
|
|
@@ -191,7 +188,7 @@ describe('Decorators', () => {
|
|
|
191
188
|
__decorate([
|
|
192
189
|
(0, Decorator_1.tool)(config)
|
|
193
190
|
], TestClass.prototype, "emptyParamsTool", null);
|
|
194
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('emptyParamsTool', 'Tool with empty parameters', expect.any(Function), [], '/empty-params', []
|
|
191
|
+
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('emptyParamsTool', 'Tool with empty parameters', expect.any(Function), [], '/empty-params', []);
|
|
195
192
|
expect(TestClass).toBeDefined();
|
|
196
193
|
});
|
|
197
194
|
it('should handle empty auth requirements array', () => {
|
|
@@ -210,7 +207,7 @@ describe('Decorators', () => {
|
|
|
210
207
|
__decorate([
|
|
211
208
|
(0, Decorator_1.tool)(config)
|
|
212
209
|
], TestClass.prototype, "noAuthTool", null);
|
|
213
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('noAuthTool', 'Tool with no auth requirements', expect.any(Function), [], '/no-auth', []
|
|
210
|
+
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('noAuthTool', 'Tool with no auth requirements', expect.any(Function), [], '/no-auth', []);
|
|
214
211
|
expect(TestClass).toBeDefined();
|
|
215
212
|
});
|
|
216
213
|
it('should register the actual method as the handler', () => {
|
|
@@ -265,7 +262,7 @@ describe('Decorators', () => {
|
|
|
265
262
|
expect.objectContaining({ name: 'boolParam', type: Models_1.ParameterType.Boolean }),
|
|
266
263
|
expect.objectContaining({ name: 'listParam', type: Models_1.ParameterType.List }),
|
|
267
264
|
expect.objectContaining({ name: 'dictParam', type: Models_1.ParameterType.Dictionary })
|
|
268
|
-
]), '/multi-type', []
|
|
265
|
+
]), '/multi-type', []);
|
|
269
266
|
});
|
|
270
267
|
});
|
|
271
268
|
describe('@interaction decorator', () => {
|
|
@@ -361,7 +358,7 @@ describe('Decorators', () => {
|
|
|
361
358
|
description: 'String param',
|
|
362
359
|
required: true
|
|
363
360
|
})
|
|
364
|
-
]), '/mixed-tool', []
|
|
361
|
+
]), '/mixed-tool', []);
|
|
365
362
|
expect(Service_1.toolsService.registerInteraction).toHaveBeenCalledWith('mixedInteraction', expect.any(Function), '/mixed-interaction');
|
|
366
363
|
});
|
|
367
364
|
});
|
|
@@ -394,7 +391,7 @@ describe('Decorators', () => {
|
|
|
394
391
|
scopeBundle: 'calendar',
|
|
395
392
|
required: true // Should default to true
|
|
396
393
|
})
|
|
397
|
-
])
|
|
394
|
+
]));
|
|
398
395
|
});
|
|
399
396
|
it('should handle undefined parameters and authRequirements arrays', () => {
|
|
400
397
|
const config = {
|
|
@@ -413,8 +410,8 @@ describe('Decorators', () => {
|
|
|
413
410
|
], TestClass.prototype, "undefinedArraysTool", null);
|
|
414
411
|
expect(TestClass).toBeDefined();
|
|
415
412
|
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('undefinedArraysTool', 'Tool with undefined arrays', expect.any(Function), [], // Should be empty array when parameters is undefined
|
|
416
|
-
'/undefined-arrays', []
|
|
417
|
-
|
|
413
|
+
'/undefined-arrays', [] // Should be empty array when authRequirements is undefined
|
|
414
|
+
);
|
|
418
415
|
});
|
|
419
416
|
});
|
|
420
417
|
describe('handler instance context', () => {
|
|
@@ -527,196 +524,5 @@ describe('Decorators', () => {
|
|
|
527
524
|
expect(TestClass).toBeDefined();
|
|
528
525
|
});
|
|
529
526
|
});
|
|
530
|
-
describe('global tool registration', () => {
|
|
531
|
-
it('should auto-detect global tools when class extends GlobalToolFunction', () => {
|
|
532
|
-
const config = {
|
|
533
|
-
name: 'autoGlobalTool',
|
|
534
|
-
description: 'An auto-detected global tool',
|
|
535
|
-
parameters: [],
|
|
536
|
-
endpoint: '/auto-global-tool'
|
|
537
|
-
};
|
|
538
|
-
class TestGlobalClass extends GlobalToolFunction {
|
|
539
|
-
async testTool() {
|
|
540
|
-
return { result: 'global-tool-result' };
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
__decorate([
|
|
544
|
-
(0, Decorator_1.tool)(config)
|
|
545
|
-
], TestGlobalClass.prototype, "testTool", null);
|
|
546
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('autoGlobalTool', 'An auto-detected global tool', expect.any(Function), [], '/auto-global-tool', [], true);
|
|
547
|
-
expect(TestGlobalClass).toBeDefined();
|
|
548
|
-
});
|
|
549
|
-
it('should register regular tools when class does not extend GlobalToolFunction', () => {
|
|
550
|
-
const config = {
|
|
551
|
-
name: 'regularTool',
|
|
552
|
-
description: 'A regular tool',
|
|
553
|
-
parameters: [],
|
|
554
|
-
endpoint: '/regular-tool'
|
|
555
|
-
};
|
|
556
|
-
class TestRegularClass {
|
|
557
|
-
async testTool() {
|
|
558
|
-
return { result: 'regular-tool-result' };
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
__decorate([
|
|
562
|
-
(0, Decorator_1.tool)(config)
|
|
563
|
-
], TestRegularClass.prototype, "testTool", null);
|
|
564
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('regularTool', 'A regular tool', expect.any(Function), [], '/regular-tool', [], false);
|
|
565
|
-
expect(TestRegularClass).toBeDefined();
|
|
566
|
-
});
|
|
567
|
-
it('should register tools as global when import context is set', () => {
|
|
568
|
-
// Set global import context
|
|
569
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
570
|
-
const config = {
|
|
571
|
-
name: 'importedGlobalTool',
|
|
572
|
-
description: 'A tool imported as global',
|
|
573
|
-
parameters: [],
|
|
574
|
-
endpoint: '/imported-global-tool'
|
|
575
|
-
};
|
|
576
|
-
class TestImportedClass {
|
|
577
|
-
async testTool() {
|
|
578
|
-
return { result: 'imported-global-tool-result' };
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
__decorate([
|
|
582
|
-
(0, Decorator_1.tool)(config)
|
|
583
|
-
], TestImportedClass.prototype, "testTool", null);
|
|
584
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('importedGlobalTool', 'A tool imported as global', expect.any(Function), [], '/imported-global-tool', [], true);
|
|
585
|
-
// Clean up
|
|
586
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
587
|
-
expect(TestImportedClass).toBeDefined();
|
|
588
|
-
});
|
|
589
|
-
it('should register tools as regular when import context is set to regular', () => {
|
|
590
|
-
// Set regular import context
|
|
591
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
592
|
-
const config = {
|
|
593
|
-
name: 'importedRegularTool',
|
|
594
|
-
description: 'A tool imported as regular',
|
|
595
|
-
parameters: [],
|
|
596
|
-
endpoint: '/imported-regular-tool'
|
|
597
|
-
};
|
|
598
|
-
class TestImportedClass {
|
|
599
|
-
async testTool() {
|
|
600
|
-
return { result: 'imported-regular-tool-result' };
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
__decorate([
|
|
604
|
-
(0, Decorator_1.tool)(config)
|
|
605
|
-
], TestImportedClass.prototype, "testTool", null);
|
|
606
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('importedRegularTool', 'A tool imported as regular', expect.any(Function), [], '/imported-regular-tool', [], false);
|
|
607
|
-
// Clean up
|
|
608
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
609
|
-
expect(TestImportedClass).toBeDefined();
|
|
610
|
-
});
|
|
611
|
-
it('should handle mixed imports - both regular and global tools together', () => {
|
|
612
|
-
// Test importing regular tools first
|
|
613
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
614
|
-
const regularConfig = {
|
|
615
|
-
name: 'mixedRegularTool',
|
|
616
|
-
description: 'A regular tool in mixed scenario',
|
|
617
|
-
parameters: [],
|
|
618
|
-
endpoint: '/mixed-regular-tool'
|
|
619
|
-
};
|
|
620
|
-
class RegularToolClass {
|
|
621
|
-
async regularTool() {
|
|
622
|
-
return { result: 'mixed-regular-result' };
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
__decorate([
|
|
626
|
-
(0, Decorator_1.tool)(regularConfig)
|
|
627
|
-
], RegularToolClass.prototype, "regularTool", null);
|
|
628
|
-
// Switch to global context
|
|
629
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
630
|
-
const globalConfig = {
|
|
631
|
-
name: 'mixedGlobalTool',
|
|
632
|
-
description: 'A global tool in mixed scenario',
|
|
633
|
-
parameters: [],
|
|
634
|
-
endpoint: '/mixed-global-tool'
|
|
635
|
-
};
|
|
636
|
-
class GlobalToolClass {
|
|
637
|
-
async globalTool() {
|
|
638
|
-
return { result: 'mixed-global-result' };
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
__decorate([
|
|
642
|
-
(0, Decorator_1.tool)(globalConfig)
|
|
643
|
-
], GlobalToolClass.prototype, "globalTool", null);
|
|
644
|
-
// Clear context
|
|
645
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
646
|
-
// Verify regular tool was registered as regular
|
|
647
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('mixedRegularTool', 'A regular tool in mixed scenario', expect.any(Function), [], '/mixed-regular-tool', [], false);
|
|
648
|
-
// Verify global tool was registered as global
|
|
649
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenCalledWith('mixedGlobalTool', 'A global tool in mixed scenario', expect.any(Function), [], '/mixed-global-tool', [], true);
|
|
650
|
-
expect(RegularToolClass).toBeDefined();
|
|
651
|
-
expect(GlobalToolClass).toBeDefined();
|
|
652
|
-
});
|
|
653
|
-
it('should handle context switching correctly within same test', () => {
|
|
654
|
-
let callCount = 0;
|
|
655
|
-
const originalRegisterTool = jest.mocked(Service_1.toolsService.registerTool);
|
|
656
|
-
// Track call order and contexts
|
|
657
|
-
originalRegisterTool.mockImplementation(() => {
|
|
658
|
-
callCount++;
|
|
659
|
-
// Store the isGlobal flag from each call for verification
|
|
660
|
-
});
|
|
661
|
-
// First: Import as regular
|
|
662
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
663
|
-
class FirstClass {
|
|
664
|
-
async tool1() {
|
|
665
|
-
return { result: 'test1' };
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
__decorate([
|
|
669
|
-
(0, Decorator_1.tool)({
|
|
670
|
-
name: 'contextTest1',
|
|
671
|
-
description: 'First context test',
|
|
672
|
-
parameters: [],
|
|
673
|
-
endpoint: '/context-test-1'
|
|
674
|
-
})
|
|
675
|
-
], FirstClass.prototype, "tool1", null);
|
|
676
|
-
// Second: Switch to global
|
|
677
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
678
|
-
class SecondClass {
|
|
679
|
-
async tool2() {
|
|
680
|
-
return { result: 'test2' };
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
__decorate([
|
|
684
|
-
(0, Decorator_1.tool)({
|
|
685
|
-
name: 'contextTest2',
|
|
686
|
-
description: 'Second context test',
|
|
687
|
-
parameters: [],
|
|
688
|
-
endpoint: '/context-test-2'
|
|
689
|
-
})
|
|
690
|
-
], SecondClass.prototype, "tool2", null);
|
|
691
|
-
// Third: Clear context (should fallback to class inheritance)
|
|
692
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
693
|
-
class ThirdClass {
|
|
694
|
-
async tool3() {
|
|
695
|
-
return { result: 'test3' };
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
__decorate([
|
|
699
|
-
(0, Decorator_1.tool)({
|
|
700
|
-
name: 'contextTest3',
|
|
701
|
-
description: 'Third context test',
|
|
702
|
-
parameters: [],
|
|
703
|
-
endpoint: '/context-test-3'
|
|
704
|
-
})
|
|
705
|
-
], ThirdClass.prototype, "tool3", null);
|
|
706
|
-
// Verify the sequence of calls
|
|
707
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenNthCalledWith(callCount - 2, // First call
|
|
708
|
-
'contextTest1', 'First context test', expect.any(Function), [], '/context-test-1', [], false // Should be regular
|
|
709
|
-
);
|
|
710
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenNthCalledWith(callCount - 1, // Second call
|
|
711
|
-
'contextTest2', 'Second context test', expect.any(Function), [], '/context-test-2', [], true // Should be global
|
|
712
|
-
);
|
|
713
|
-
expect(Service_1.toolsService.registerTool).toHaveBeenNthCalledWith(callCount, // Third call
|
|
714
|
-
'contextTest3', 'Third context test', expect.any(Function), [], '/context-test-3', [], false // Should be regular (fallback to class check, ThirdClass doesn't extend GlobalToolFunction)
|
|
715
|
-
);
|
|
716
|
-
expect(FirstClass).toBeDefined();
|
|
717
|
-
expect(SecondClass).toBeDefined();
|
|
718
|
-
expect(ThirdClass).toBeDefined();
|
|
719
|
-
});
|
|
720
|
-
});
|
|
721
527
|
});
|
|
722
528
|
//# sourceMappingURL=Decorator.test.js.map
|