@optimizely-opal/opal-tool-ocp-sdk 1.0.0-beta.9 โ 1.1.0-beta.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.
- package/README.md +99 -200
- package/dist/function/GlobalToolFunction.d.ts +4 -1
- package/dist/function/GlobalToolFunction.d.ts.map +1 -1
- package/dist/function/GlobalToolFunction.js +25 -19
- package/dist/function/GlobalToolFunction.js.map +1 -1
- package/dist/function/GlobalToolFunction.test.js +114 -193
- package/dist/function/GlobalToolFunction.test.js.map +1 -1
- package/dist/function/ToolFunction.d.ts +4 -1
- package/dist/function/ToolFunction.d.ts.map +1 -1
- package/dist/function/ToolFunction.js +20 -21
- package/dist/function/ToolFunction.js.map +1 -1
- package/dist/function/ToolFunction.test.js +73 -263
- package/dist/function/ToolFunction.test.js.map +1 -1
- package/dist/logging/ToolLogger.d.ts +11 -3
- package/dist/logging/ToolLogger.d.ts.map +1 -1
- package/dist/logging/ToolLogger.js +114 -13
- package/dist/logging/ToolLogger.js.map +1 -1
- package/dist/logging/ToolLogger.test.js +177 -71
- package/dist/logging/ToolLogger.test.js.map +1 -1
- package/dist/service/Service.d.ts +10 -9
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js +42 -74
- package/dist/service/Service.js.map +1 -1
- package/dist/service/Service.test.js +60 -95
- package/dist/service/Service.test.js.map +1 -1
- package/dist/utils/ErrorFormatter.d.ts +9 -0
- package/dist/utils/ErrorFormatter.d.ts.map +1 -0
- package/dist/utils/ErrorFormatter.js +25 -0
- package/dist/utils/ErrorFormatter.js.map +1 -0
- package/package.json +3 -3
- package/src/function/GlobalToolFunction.test.ts +113 -213
- package/src/function/GlobalToolFunction.ts +29 -29
- package/src/function/ToolFunction.test.ts +78 -285
- package/src/function/ToolFunction.ts +24 -30
- package/src/logging/ToolLogger.test.ts +225 -74
- package/src/logging/ToolLogger.ts +129 -15
- package/src/service/Service.test.ts +61 -113
- package/src/service/Service.ts +45 -79
- package/src/utils/ErrorFormatter.ts +31 -0
package/README.md
CHANGED
|
@@ -6,45 +6,61 @@ A TypeScript SDK for building Opal tools in Optimizely Connect Platform. This SD
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- ๐ฏ **Decorator-based Tool Registration** - Use `@tool`
|
|
9
|
+
- ๐ฏ **Decorator-based Tool Registration** - Use `@tool` decorator to easily register functions
|
|
10
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
|
-
- ๐ **Authentication Support** - OptiID authentication
|
|
13
|
+
- ๐ **Authentication Support** - OptiID authentication (default), custom auth providers supported
|
|
14
14
|
- ๐ก๏ธ **Authorization Support** - OptiID token tool authorization
|
|
15
15
|
- ๐ **Parameter Validation** - Define and validate tool parameters with types
|
|
16
16
|
- โ
**Automatic Validation** - SDK automatically validates parameters and returns RFC 9457 compliant error responses
|
|
17
17
|
- ๐งช **Comprehensive Testing** - Fully tested with Jest
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
The SDK extends the functionality of OCP apps. You need to have an OCP app to use this SDK.
|
|
22
|
+
Learn how to get started with OCP app development [here](https://docs.developers.optimizely.com/optimizely-connect-platform/docs/developer-platform-overview-ocp2).
|
|
20
23
|
|
|
24
|
+
Start by adding the SDK to your existing OCP app. In your OCP app folder, execute:
|
|
21
25
|
```bash
|
|
22
|
-
|
|
26
|
+
yarn add @optimizely-opal/opal-tool-ocp-sdk
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
To add an Opal too registry to your OCP app,
|
|
30
|
+
add a [function](https://docs.developers.optimizely.com/optimizely-connect-platform/docs/functions-ocp2) to your app manifest and mark it as an Opal tool function:
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
**`app.yml`**
|
|
33
|
+
```yaml
|
|
34
|
+
functions:
|
|
35
|
+
opal_tool: # A unique key for your function.
|
|
36
|
+
entry_point: OpalToolFunction # The name of the class implementing your tool.
|
|
37
|
+
description: Opal tool function # A brief description of this function.
|
|
38
|
+
opal_tool: true
|
|
29
39
|
```
|
|
30
40
|
|
|
31
|
-
|
|
41
|
+
Next, create and implement function class - both file name and class must match the value of `entry_point` property from app manifest.
|
|
42
|
+
Function class must extend either `ToolFunction` or `GlobalToolFunction` class from `@optimizely-opal/opal-tool-ocp-sdk` (See 'Function modes' section below).
|
|
32
43
|
|
|
33
|
-
|
|
44
|
+
**`src/functions/OpalToolFunction`**
|
|
45
|
+
```typescript
|
|
46
|
+
import { ToolFunction } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
34
47
|
|
|
35
|
-
|
|
36
|
-
- **Global Functions** (`GlobalToolFunction`) - Platform-wide functions that work across all organizations
|
|
48
|
+
export class OpalToolFunction extends ToolFunction {
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
}
|
|
51
|
+
```
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
Next, implement tools methods and annotate them with `@tool` decorator. Each such method is a tool in your registry.
|
|
54
|
+
You can define mulitple tool methods in your app.
|
|
55
|
+
Tool methods can be defined either as tool class instance methods or in separate classes.
|
|
56
|
+
If tools are defined in separate classes, these classes need to be imported into the function class.
|
|
41
57
|
|
|
58
|
+
**`src/functions/OpalToolFunction`**
|
|
42
59
|
```typescript
|
|
43
|
-
import { ToolFunction
|
|
60
|
+
import { ToolFunction } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
44
61
|
|
|
45
|
-
export class
|
|
62
|
+
export class OpalToolFunction extends ToolFunction {
|
|
46
63
|
|
|
47
|
-
// Register a simple tool without authentication
|
|
48
64
|
@tool({
|
|
49
65
|
name: 'create_task',
|
|
50
66
|
description: 'Creates a new task in the system',
|
|
@@ -71,118 +87,42 @@ export class MyToolFunction extends ToolFunction {
|
|
|
71
87
|
priority: params.priority || 'medium'
|
|
72
88
|
};
|
|
73
89
|
}
|
|
74
|
-
|
|
75
|
-
// Register a tool with OptiID authentication
|
|
76
|
-
@tool({
|
|
77
|
-
name: 'secure_task',
|
|
78
|
-
description: 'Creates a secure task with OptiID authentication',
|
|
79
|
-
endpoint: '/secure-task',
|
|
80
|
-
parameters: [
|
|
81
|
-
{
|
|
82
|
-
name: 'title',
|
|
83
|
-
type: ParameterType.String,
|
|
84
|
-
description: 'The task title',
|
|
85
|
-
required: true
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
authRequirements: [
|
|
89
|
-
{
|
|
90
|
-
provider: 'OptiID',
|
|
91
|
-
scopeBundle: 'tasks',
|
|
92
|
-
required: true
|
|
93
|
-
}
|
|
94
|
-
]
|
|
95
|
-
})
|
|
96
|
-
async createSecureTask(params: { title: string }, authData?: OptiIdAuthData) {
|
|
97
|
-
if (!authData) {
|
|
98
|
-
throw new Error('OptiID authentication required');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const { customer_id, instance_id, access_token } = authData.credentials;
|
|
102
|
-
return {
|
|
103
|
-
id: '456',
|
|
104
|
-
title: params.title,
|
|
105
|
-
customer_id,
|
|
106
|
-
instance_id
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Register an interaction
|
|
111
|
-
@interaction({
|
|
112
|
-
name: 'task_webhook',
|
|
113
|
-
endpoint: '/webhook/task'
|
|
114
|
-
})
|
|
115
|
-
async handleTaskWebhook(data: any): Promise<InteractionResult> {
|
|
116
|
-
return new InteractionResult(
|
|
117
|
-
`Task ${data.taskId} was updated`,
|
|
118
|
-
`https://app.example.com/tasks/${data.taskId}`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
90
|
}
|
|
122
91
|
```
|
|
123
92
|
|
|
124
|
-
|
|
93
|
+
The format of `params` attribute matches the parameters defined in `@tool` decorator.
|
|
125
94
|
|
|
126
|
-
|
|
95
|
+
When the function is called by Opal, the SDK automatically:
|
|
127
96
|
|
|
128
|
-
|
|
129
|
-
|
|
97
|
+
- **Routes requests** to your registered tools based on endpoints
|
|
98
|
+
- **Handles authentication** and OptiID token validation before calling your methods
|
|
99
|
+
- **Provides discovery** at `/discovery` endpoint for OCP platform integration
|
|
100
|
+
- **Returns proper HTTP responses** with correct status codes and JSON formatting
|
|
130
101
|
|
|
131
|
-
|
|
102
|
+
Optionally, implement `ready` method to define when tool registry can be registered and called by Opal.
|
|
103
|
+
OCP will call this method to show tool readiness in the UI. Only functions marked as `ready` can be registered and called by Opal.
|
|
104
|
+
The value of `reason` property from the response will be displayed in OCP UI to inform users why the tool is not ready to be registered.
|
|
105
|
+
```typescript
|
|
106
|
+
protected override async ready(): Promise<ReadyResponse> {
|
|
107
|
+
// validation logic
|
|
108
|
+
if (!isValid) {
|
|
109
|
+
return { ready: false, reason: 'Configure the app first.' };
|
|
110
|
+
}
|
|
132
111
|
|
|
133
|
-
|
|
134
|
-
name: 'global_utility',
|
|
135
|
-
description: 'A utility tool available to all organizations',
|
|
136
|
-
endpoint: '/global-utility',
|
|
137
|
-
parameters: [
|
|
138
|
-
{
|
|
139
|
-
name: 'operation',
|
|
140
|
-
type: ParameterType.String,
|
|
141
|
-
description: 'The operation to perform',
|
|
142
|
-
required: true
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
})
|
|
146
|
-
async globalUtility(params: { operation: string }, authData?: OptiIdAuthData) {
|
|
147
|
-
return {
|
|
148
|
-
result: `Performed ${params.operation} globally`,
|
|
149
|
-
organizationId: authData?.credentials.customer_id || 'unknown'
|
|
150
|
-
};
|
|
112
|
+
return { ready: true };
|
|
151
113
|
}
|
|
152
|
-
}
|
|
153
114
|
```
|
|
154
115
|
|
|
155
|
-
### Function Modes
|
|
156
|
-
|
|
157
|
-
The SDK operates in one of two modes based on the base class you extend:
|
|
158
|
-
|
|
159
|
-
- **Regular Function Mode** (`ToolFunction`): All tools are organization-scoped and validate organization IDs
|
|
160
|
-
- **Global Function Mode** (`GlobalToolFunction`): All tools are platform-wide.
|
|
161
|
-
|
|
162
|
-
The discovery endpoint returns all tools registered within that function mode.
|
|
163
|
-
|
|
164
|
-
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:
|
|
165
|
-
|
|
166
|
-
- **Routes requests** to your registered tools and interactions based on endpoints
|
|
167
|
-
- **Handles authentication** and OptiID token validation before calling your methods
|
|
168
|
-
- **Provides discovery** at `/discovery` endpoint for OCP platform integration
|
|
169
|
-
- **Returns proper HTTP responses** with correct status codes and JSON formatting
|
|
170
|
-
|
|
171
116
|
## Core Concepts
|
|
172
117
|
|
|
173
118
|
### Tools
|
|
174
119
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
- Have a name, description, and endpoint
|
|
178
|
-
- Define parameters with types and validation
|
|
179
|
-
- Can require authentication
|
|
180
|
-
- Return structured responses
|
|
181
|
-
- Are automatically registered based on the function mode you choose
|
|
120
|
+
Each OCP app with an Opal too function is a tool registry in Opal. Tool registry constist of one or more tools.
|
|
121
|
+
Each tool have name, description and a list of input parameters.
|
|
182
122
|
|
|
183
123
|
### Function Modes
|
|
184
124
|
|
|
185
|
-
#### Regular Functions (`ToolFunction`)
|
|
125
|
+
#### Regular Functions (function extends `ToolFunction` class)
|
|
186
126
|
|
|
187
127
|
Regular functions are scoped to specific organizations and validate that requests come from the same organization:
|
|
188
128
|
|
|
@@ -191,7 +131,7 @@ Regular functions are scoped to specific organizations and validate that request
|
|
|
191
131
|
- **Per-Organization Configuration**: Can implement organization-specific configuration, authentication credentials, and API keys since they're tied to a single organization
|
|
192
132
|
- **Per-Organization Authentication**: Can store and use organization-specific authentication tokens, connection strings, and other sensitive data securely
|
|
193
133
|
|
|
194
|
-
#### Global Functions (`GlobalToolFunction`)
|
|
134
|
+
#### Global Functions (function extends `GlobalToolFunction` class)
|
|
195
135
|
|
|
196
136
|
Global functions work across all organizations without organization validation:
|
|
197
137
|
|
|
@@ -201,14 +141,6 @@ Global functions work across all organizations without organization validation:
|
|
|
201
141
|
- **No Per-Organization Authentication**: Cannot store organization-specific credentials or authentication data
|
|
202
142
|
- **Global Discovery**: Have a global discovery URL that can be used by any organization without requiring them to install the app first
|
|
203
143
|
|
|
204
|
-
### Interactions
|
|
205
|
-
|
|
206
|
-
Interactions are event handlers that process incoming data (like webhooks):
|
|
207
|
-
|
|
208
|
-
- Have a name and endpoint
|
|
209
|
-
- Process unstructured data
|
|
210
|
-
- Return interaction results with messages and optional links
|
|
211
|
-
|
|
212
144
|
### Parameters
|
|
213
145
|
|
|
214
146
|
Supported parameter types:
|
|
@@ -226,7 +158,9 @@ enum ParameterType {
|
|
|
226
158
|
|
|
227
159
|
### Parameter Validation
|
|
228
160
|
|
|
229
|
-
The SDK automatically validates all incoming parameters against the parameter definitions you specify for your tools.
|
|
161
|
+
The SDK automatically validates all incoming parameters against the parameter definitions you specify for your tools.
|
|
162
|
+
When Opal sends requests to your tools, the SDK performs validation before calling your handler methods and automatically returns an error message that Opal understands.
|
|
163
|
+
This allow Opal to auto-correct.
|
|
230
164
|
|
|
231
165
|
#### Automatic Validation Features
|
|
232
166
|
|
|
@@ -235,43 +169,13 @@ The SDK automatically validates all incoming parameters against the parameter de
|
|
|
235
169
|
- **Early Error Response**: Returns validation errors immediately without calling your handler if validation fails
|
|
236
170
|
- **RFC 9457 Compliance**: Error responses follow the RFC 9457 Problem Details for HTTP APIs specification
|
|
237
171
|
|
|
238
|
-
#### Validation Error Response Format
|
|
239
|
-
|
|
240
|
-
When parameter validation fails, the SDK returns a standardized error response with HTTP status 400 and `Content-Type: application/problem+json`:
|
|
241
|
-
|
|
242
|
-
```json
|
|
243
|
-
{
|
|
244
|
-
"title": "One or more validation errors occurred.",
|
|
245
|
-
"status": 400,
|
|
246
|
-
"detail": "See 'errors' field for details.",
|
|
247
|
-
"instance": "/your-tool-endpoint",
|
|
248
|
-
"errors": [
|
|
249
|
-
{
|
|
250
|
-
"field": "title",
|
|
251
|
-
"message": "Parameter 'title' must be a string, but received number"
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
"field": "priority",
|
|
255
|
-
"message": "Required parameter 'priority' is missing"
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**Benefits:**
|
|
262
|
-
|
|
263
|
-
- **Reduced Boilerplate**: No need to write parameter validation code in your handlers
|
|
264
|
-
- **Consistent Error Format**: All validation errors follow the same RFC 9457 standard format
|
|
265
|
-
- **Better Developer Experience**: Clear, actionable error messages for API consumers
|
|
266
|
-
- **Type Safety**: Validation ensures your handlers receive correctly typed parameters
|
|
267
|
-
|
|
268
172
|
### Authentication
|
|
269
173
|
|
|
270
174
|
The SDK supports authentication and authorization mechanisms:
|
|
271
175
|
|
|
272
|
-
#### OptiID Authentication
|
|
176
|
+
#### OptiID Authentication (Default)
|
|
273
177
|
|
|
274
|
-
OptiID provides user authentication with type safety.
|
|
178
|
+
OptiID provides user authentication with type safety. When a tool does not declare any `authRequirements`, the SDK automatically adds OptiID as the default authentication provider:
|
|
275
179
|
|
|
276
180
|
```typescript
|
|
277
181
|
interface AuthRequirementConfig {
|
|
@@ -317,6 +221,42 @@ export class MyToolFunction extends ToolFunction {
|
|
|
317
221
|
}
|
|
318
222
|
```
|
|
319
223
|
|
|
224
|
+
#### Custom Auth Providers
|
|
225
|
+
|
|
226
|
+
Tools can declare custom authentication providers instead of using the default OptiID. When a tool specifies its own `authRequirements`, the SDK respects that choice and skips its built-in authentication validation:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
@tool({
|
|
230
|
+
name: 'external_api_tool',
|
|
231
|
+
description: 'Tool that uses external OAuth2 authentication',
|
|
232
|
+
endpoint: '/external-api',
|
|
233
|
+
parameters: [
|
|
234
|
+
{ name: 'query', type: ParameterType.String, description: 'Search query', required: true }
|
|
235
|
+
],
|
|
236
|
+
authRequirements: [{ provider: 'google', scopeBundle: 'calendar', required: true }]
|
|
237
|
+
})
|
|
238
|
+
async externalApiTool(params: { query: string }, authData?: any) {
|
|
239
|
+
// SDK does NOT validate oauth2 credentials
|
|
240
|
+
// Your handler must validate the auth credentials
|
|
241
|
+
// Validate token with your external provider
|
|
242
|
+
const isValid = await this.validateOAuth2Token(authData.credentials.access_token);
|
|
243
|
+
if (!isValid) {
|
|
244
|
+
throw new ToolError('Invalid OAuth2 token', 401);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { results: await this.searchExternalApi(params.query) };
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Important Security Considerations:**
|
|
252
|
+
|
|
253
|
+
> **Warning**: Tools using non-OptiID authentication should NOT expose sensitive data from app settings (such as API keys, secrets, or organization-specific configuration).
|
|
254
|
+
>
|
|
255
|
+
> - **OptiID auth** guarantees the caller is authorized for the specific organization and the request is from a trusted Opal instance
|
|
256
|
+
> - **Non-OptiID auth** only guarantees the credentials are valid for that provider - it does NOT guarantee the caller is authorized for the organization or app
|
|
257
|
+
>
|
|
258
|
+
> Only credentials for the declared auth provider are validated. If your tool declares `google` auth requirement, the SDK will pass through whatever credentials Opal sends without SDK-level validation. Your handler is fully responsible for credential validation and access control.
|
|
259
|
+
|
|
320
260
|
## Error Handling
|
|
321
261
|
|
|
322
262
|
The SDK provides RFC 9457 Problem Details compliant error handling through the `ToolError` class. This allows you to throw errors with custom HTTP status codes and detailed error information.
|
|
@@ -434,16 +374,16 @@ This will return:
|
|
|
434
374
|
|
|
435
375
|
### Handler Function Signatures
|
|
436
376
|
|
|
437
|
-
All tool
|
|
377
|
+
All tool handler methods follow this signature pattern:
|
|
438
378
|
|
|
439
379
|
```typescript
|
|
440
380
|
async handlerMethod(
|
|
441
|
-
params: TParams, // Tool parameters
|
|
381
|
+
params: TParams, // Tool parameters
|
|
442
382
|
authData?: OptiIdAuthData // OptiID user authentication data (if authenticated)
|
|
443
383
|
): Promise<TResult>
|
|
444
384
|
```
|
|
445
385
|
|
|
446
|
-
- **params**: The input parameters for tools
|
|
386
|
+
- **params**: The input parameters for tools
|
|
447
387
|
- **authData**: Available when OptiID user authentication is configured and successful
|
|
448
388
|
|
|
449
389
|
|
|
@@ -463,17 +403,6 @@ interface ToolConfig {
|
|
|
463
403
|
}
|
|
464
404
|
```
|
|
465
405
|
|
|
466
|
-
#### `@interaction(config: InteractionConfig)`
|
|
467
|
-
|
|
468
|
-
Registers a method as an interaction handler.
|
|
469
|
-
|
|
470
|
-
```typescript
|
|
471
|
-
interface InteractionConfig {
|
|
472
|
-
name: string;
|
|
473
|
-
endpoint: string;
|
|
474
|
-
}
|
|
475
|
-
```
|
|
476
|
-
|
|
477
406
|
### Base Classes
|
|
478
407
|
|
|
479
408
|
#### `ToolFunction`
|
|
@@ -507,10 +436,8 @@ Extend this class for tools that work across organizations. The `perform` method
|
|
|
507
436
|
Key model classes with generic type support:
|
|
508
437
|
|
|
509
438
|
- `Tool<TAuthData>` - Represents a registered tool with typed auth data
|
|
510
|
-
- `Interaction<TAuthData>` - Represents an interaction handler with typed auth data
|
|
511
439
|
- `Parameter` - Defines tool parameters
|
|
512
440
|
- `AuthRequirement` - Defines authentication needs
|
|
513
|
-
- `InteractionResult` - Response from interactions
|
|
514
441
|
- `OptiIdAuthData` - OptiID specific authentication data
|
|
515
442
|
- `ReadyResponse` - Response type for the ready method containing status and optional reason
|
|
516
443
|
- `ToolError` - Custom error class for RFC 9457 Problem Details error responses with configurable HTTP status codes
|
|
@@ -639,7 +566,7 @@ yarn lint
|
|
|
639
566
|
### Function with Authentication
|
|
640
567
|
|
|
641
568
|
```typescript
|
|
642
|
-
import { ToolFunction, tool,
|
|
569
|
+
import { ToolFunction, tool, ParameterType, OptiIdAuthData } from '@optimizely-opal/opal-ocp-sdk';
|
|
643
570
|
|
|
644
571
|
export class AuthenticatedFunction extends ToolFunction {
|
|
645
572
|
|
|
@@ -659,24 +586,6 @@ export class AuthenticatedFunction extends ToolFunction {
|
|
|
659
586
|
return { success: true, customer_id };
|
|
660
587
|
}
|
|
661
588
|
|
|
662
|
-
// Interaction with authentication example
|
|
663
|
-
@interaction({
|
|
664
|
-
name: 'authenticated_webhook',
|
|
665
|
-
endpoint: '/secure-webhook'
|
|
666
|
-
})
|
|
667
|
-
async handleSecureWebhook(data: any, authData?: OptiIdAuthData): Promise<InteractionResult> {
|
|
668
|
-
if (!authData) {
|
|
669
|
-
return new InteractionResult('Authentication required for webhook processing');
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const { customer_id } = authData.credentials;
|
|
673
|
-
|
|
674
|
-
// Process webhook data with authentication context
|
|
675
|
-
return new InteractionResult(
|
|
676
|
-
`Webhook processed for customer ${customer_id}: ${data.eventType}`,
|
|
677
|
-
`https://app.example.com/events/${data.eventId}`
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
589
|
}
|
|
681
590
|
```
|
|
682
591
|
|
|
@@ -748,7 +657,7 @@ export class TaskTool {
|
|
|
748
657
|
|
|
749
658
|
**tools/NotificationTool.ts:**
|
|
750
659
|
```typescript
|
|
751
|
-
import { tool,
|
|
660
|
+
import { tool, ParameterType, OptiIdAuthData } from '@optimizely-opal/opal-ocp-sdk';
|
|
752
661
|
|
|
753
662
|
export class NotificationTool {
|
|
754
663
|
@tool({
|
|
@@ -779,16 +688,6 @@ export class NotificationTool {
|
|
|
779
688
|
};
|
|
780
689
|
}
|
|
781
690
|
|
|
782
|
-
@interaction({
|
|
783
|
-
name: 'notification_webhook',
|
|
784
|
-
endpoint: '/webhook/notification'
|
|
785
|
-
})
|
|
786
|
-
async handleNotificationWebhook(data: any): Promise<InteractionResult> {
|
|
787
|
-
return new InteractionResult(
|
|
788
|
-
`Notification ${data.notificationId} was delivered`,
|
|
789
|
-
`https://app.example.com/notifications/${data.notificationId}`
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
691
|
}
|
|
793
692
|
```
|
|
794
693
|
|
|
@@ -816,7 +715,7 @@ This approach provides several benefits:
|
|
|
816
715
|
|
|
817
716
|
## Decorator Behavior and Instance Context
|
|
818
717
|
|
|
819
|
-
The `@tool`
|
|
718
|
+
The `@tool` decorator provide intelligent instance context management that behaves differently depending on where the decorated methods are defined:
|
|
820
719
|
|
|
821
720
|
### ToolFunction Subclass Context
|
|
822
721
|
|
|
@@ -20,7 +20,10 @@ export declare abstract class GlobalToolFunction extends GlobalFunction {
|
|
|
20
20
|
perform(): Promise<Response>;
|
|
21
21
|
private handleRequest;
|
|
22
22
|
/**
|
|
23
|
-
* Authenticate the incoming request
|
|
23
|
+
* Authenticate the incoming request based on the endpoint
|
|
24
|
+
* - /discovery: No auth required
|
|
25
|
+
* - /overrides: Internal auth (header-based token)
|
|
26
|
+
* - Tools/interactions: Global auth if OptiID is required
|
|
24
27
|
*
|
|
25
28
|
* @throws {ToolError} If authentication fails
|
|
26
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalToolFunction.d.ts","sourceRoot":"","sources":["../../src/function/GlobalToolFunction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"GlobalToolFunction.d.ts","sourceRoot":"","sources":["../../src/function/GlobalToolFunction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAmB,MAAM,mBAAmB,CAAC;AAI9E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;;GAGG;AACH,8BAAsB,kBAAmB,SAAQ,cAAc;IAE7D;;;;;OAKG;IACH,SAAS,CAAC,KAAK,IAAI,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC;IAInD;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;YAmB3B,aAAa;IAkB3B;;;;;;;OAOG;YACW,gBAAgB;CAiB/B"}
|
|
@@ -5,7 +5,7 @@ const app_sdk_1 = require("@zaiusinc/app-sdk");
|
|
|
5
5
|
const AuthUtils_1 = require("../auth/AuthUtils");
|
|
6
6
|
const Service_1 = require("../service/Service");
|
|
7
7
|
const ToolLogger_1 = require("../logging/ToolLogger");
|
|
8
|
-
const
|
|
8
|
+
const ErrorFormatter_1 = require("../utils/ErrorFormatter");
|
|
9
9
|
/**
|
|
10
10
|
* Abstract base class for global tool-based function execution
|
|
11
11
|
* Provides a standard interface for processing requests through registered tools
|
|
@@ -40,21 +40,6 @@ class GlobalToolFunction extends app_sdk_1.GlobalFunction {
|
|
|
40
40
|
return response;
|
|
41
41
|
}
|
|
42
42
|
async handleRequest() {
|
|
43
|
-
try {
|
|
44
|
-
await this.authorizeRequest();
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
if (error instanceof ToolError_1.ToolError) {
|
|
48
|
-
return new app_sdk_1.Response(error.status, error.toProblemDetails(this.request.path), new app_sdk_1.Headers([['content-type', 'application/problem+json']]));
|
|
49
|
-
}
|
|
50
|
-
// Fallback for unexpected errors
|
|
51
|
-
return new app_sdk_1.Response(500, {
|
|
52
|
-
title: 'Internal Server Error',
|
|
53
|
-
status: 500,
|
|
54
|
-
detail: 'An unexpected error occurred during authentication',
|
|
55
|
-
instance: this.request.path
|
|
56
|
-
}, new app_sdk_1.Headers([['content-type', 'application/problem+json']]));
|
|
57
|
-
}
|
|
58
43
|
if (this.request.path === '/ready') {
|
|
59
44
|
const readyResult = await this.ready();
|
|
60
45
|
const readyResponse = typeof readyResult === 'boolean'
|
|
@@ -62,15 +47,36 @@ class GlobalToolFunction extends app_sdk_1.GlobalFunction {
|
|
|
62
47
|
: readyResult;
|
|
63
48
|
return new app_sdk_1.Response(200, readyResponse);
|
|
64
49
|
}
|
|
65
|
-
|
|
50
|
+
try {
|
|
51
|
+
await this.authorizeRequest();
|
|
52
|
+
return await Service_1.toolsService.processRequest(this.request, this);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return (0, ErrorFormatter_1.formatErrorResponse)(error, this.request.path);
|
|
56
|
+
}
|
|
66
57
|
}
|
|
67
58
|
/**
|
|
68
|
-
* Authenticate the incoming request
|
|
59
|
+
* Authenticate the incoming request based on the endpoint
|
|
60
|
+
* - /discovery: No auth required
|
|
61
|
+
* - /overrides: Internal auth (header-based token)
|
|
62
|
+
* - Tools/interactions: Global auth if OptiID is required
|
|
69
63
|
*
|
|
70
64
|
* @throws {ToolError} If authentication fails
|
|
71
65
|
*/
|
|
72
66
|
async authorizeRequest() {
|
|
73
|
-
|
|
67
|
+
// Discovery endpoint doesn't require auth
|
|
68
|
+
if (this.request.path === '/discovery') {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Use internal authentication for overrides endpoint (header-based token)
|
|
72
|
+
if (this.request.path === '/overrides') {
|
|
73
|
+
await (0, AuthUtils_1.authenticateInternalRequest)(this.request);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Tool/interaction endpoints - authenticate only if OptiID is required
|
|
77
|
+
if (Service_1.toolsService.requiresOptiIdAuth(this.request.path)) {
|
|
78
|
+
await (0, AuthUtils_1.authenticateGlobalRequest)(this.request);
|
|
79
|
+
}
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
exports.GlobalToolFunction = GlobalToolFunction;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalToolFunction.js","sourceRoot":"","sources":["../../src/function/GlobalToolFunction.ts"],"names":[],"mappings":";;;AAAA,+
|
|
1
|
+
{"version":3,"file":"GlobalToolFunction.js","sourceRoot":"","sources":["../../src/function/GlobalToolFunction.ts"],"names":[],"mappings":";;;AAAA,+CAA8E;AAC9E,iDAA4G;AAC5G,gDAAkD;AAClD,sDAAmD;AAEnD,4DAA8D;AAE9D;;;GAGG;AACH,MAAsB,kBAAmB,SAAQ,wBAAc;IAE7D;;;;;OAKG;IACO,KAAK;QACb,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO;QAClB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,oEAAoE;QACpE,MAAM,QAAQ,GAAG,IAAA,2BAAe,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC;QAEhE,IAAA,yBAAe,EAAC;YACd,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE;YAChE,UAAU,EAAE,UAAU,IAAI,EAAE;SAC7B,CAAC,CAAC;QAEH,uBAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5C,uBAAU,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;QACvE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACvC,MAAM,aAAa,GAAG,OAAO,WAAW,KAAK,SAAS;gBACpD,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE;gBACxB,CAAC,CAAC,WAAW,CAAC;YAChB,OAAO,IAAI,kBAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAE9B,OAAO,MAAM,sBAAY,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,oCAAmB,EAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,gBAAgB;QAC5B,0CAA0C;QAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACvC,MAAM,IAAA,uCAA2B,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,uEAAuE;QACvE,IAAI,sBAAY,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,MAAM,IAAA,qCAAyB,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF;AA/ED,gDA+EC"}
|