@optimizely-opal/opal-tool-ocp-sdk 0.0.0-dev.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 (42) hide show
  1. package/README.md +437 -0
  2. package/dist/decorator/Decorator.d.ts +46 -0
  3. package/dist/decorator/Decorator.d.ts.map +1 -0
  4. package/dist/decorator/Decorator.js +31 -0
  5. package/dist/decorator/Decorator.js.map +1 -0
  6. package/dist/decorator/Decorator.test.d.ts +2 -0
  7. package/dist/decorator/Decorator.test.d.ts.map +1 -0
  8. package/dist/decorator/Decorator.test.js +418 -0
  9. package/dist/decorator/Decorator.test.js.map +1 -0
  10. package/dist/function/ToolFunction.d.ts +15 -0
  11. package/dist/function/ToolFunction.d.ts.map +1 -0
  12. package/dist/function/ToolFunction.js +25 -0
  13. package/dist/function/ToolFunction.js.map +1 -0
  14. package/dist/function/ToolFunction.test.d.ts +2 -0
  15. package/dist/function/ToolFunction.test.d.ts.map +1 -0
  16. package/dist/function/ToolFunction.test.js +189 -0
  17. package/dist/function/ToolFunction.test.js.map +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +25 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/service/Service.d.ts +78 -0
  23. package/dist/service/Service.d.ts.map +1 -0
  24. package/dist/service/Service.js +204 -0
  25. package/dist/service/Service.js.map +1 -0
  26. package/dist/service/Service.test.d.ts +2 -0
  27. package/dist/service/Service.test.d.ts.map +1 -0
  28. package/dist/service/Service.test.js +341 -0
  29. package/dist/service/Service.test.js.map +1 -0
  30. package/dist/types/Models.d.ts +126 -0
  31. package/dist/types/Models.d.ts.map +1 -0
  32. package/dist/types/Models.js +181 -0
  33. package/dist/types/Models.js.map +1 -0
  34. package/package.json +58 -0
  35. package/src/decorator/Decorator.test.ts +523 -0
  36. package/src/decorator/Decorator.ts +83 -0
  37. package/src/function/ToolFunction.test.ts +224 -0
  38. package/src/function/ToolFunction.ts +25 -0
  39. package/src/index.ts +4 -0
  40. package/src/service/Service.test.ts +550 -0
  41. package/src/service/Service.ts +182 -0
  42. package/src/types/Models.ts +163 -0
@@ -0,0 +1,182 @@
1
+ /* eslint-disable max-classes-per-file */
2
+ import { AuthRequirement, Parameter } from '../types/Models';
3
+ import * as App from '@zaiusinc/app-sdk';
4
+ import { logger } from '@zaiusinc/app-sdk';
5
+
6
+
7
+
8
+ /**
9
+ * Result type for interaction handlers
10
+ */
11
+ export class InteractionResult {
12
+ public constructor(
13
+ public message: string,
14
+ public link?: string
15
+ ) {}
16
+ }
17
+
18
+ /**
19
+ * Interaction definition for an Opal interaction
20
+ */
21
+ export class Interaction<TAuthData> {
22
+ public constructor(
23
+ public name: string,
24
+ public endpoint: string,
25
+ public handler: (data: unknown, authData?: TAuthData) => Promise<InteractionResult>
26
+ ) {}
27
+ }
28
+
29
+ /**
30
+ * Tool definition for an Opal tool
31
+ */
32
+ export class Tool<TAuthData> {
33
+ /**
34
+ * HTTP method for the endpoint (default: POST)
35
+ */
36
+ public httpMethod: string = 'POST';
37
+
38
+ /**
39
+ * Create a new function definition
40
+ * @param name Function name
41
+ * @param description Function description
42
+ * @param parameters Function parameters
43
+ * @param endpoint API endpoint
44
+ * @param handler Function implementing the tool
45
+ * @param authRequirements Authentication requirements (optional)
46
+ */
47
+ public constructor(
48
+ public name: string,
49
+ public description: string,
50
+ public parameters: Parameter[],
51
+ public endpoint: string,
52
+ public handler: (params: unknown, authData?: TAuthData) => Promise<unknown>,
53
+ public authRequirements?: AuthRequirement[]
54
+ ) {}
55
+
56
+ /**
57
+ * Convert to JSON for the discovery endpoint
58
+ */
59
+ public toJSON(): Record<string, unknown> {
60
+ const result: Record<string, unknown> = {
61
+ name: this.name,
62
+ description: this.description,
63
+ parameters: this.parameters.map((p) => p.toJSON()),
64
+ endpoint: this.endpoint,
65
+ http_method: this.httpMethod
66
+ };
67
+
68
+ if (this.authRequirements && this.authRequirements.length > 0) {
69
+ result.auth_requirements = this.authRequirements.map((auth) => auth.toJSON());
70
+ }
71
+
72
+ return result;
73
+ }
74
+ }
75
+
76
+ export class ToolsService {
77
+ private functions: Map<string, Tool<any>> = new Map();
78
+ private interactions: Map<string, Interaction<any>> = new Map();
79
+
80
+ /**
81
+ * Extract Bearer token from Authorization header
82
+ * @param headers Request headers (Map-like object or Headers object with get method)
83
+ * @returns Bearer token string or undefined
84
+ */
85
+ public extractBearerToken(headers: App.Headers): string | undefined {
86
+ let bearerToken: string | undefined;
87
+
88
+ const authHeader = headers ? headers.get('authorization') : undefined;
89
+ if (authHeader && authHeader.startsWith('Bearer ')) {
90
+ bearerToken = authHeader.substring(7).trim();
91
+ }
92
+ return bearerToken;
93
+ }
94
+
95
+ /**
96
+ * Register a tool function with generic auth data
97
+ * @param name Tool name
98
+ * @param description Tool description
99
+ * @param handler Function implementing the tool
100
+ * @param parameters List of parameters for the tool
101
+ * @param endpoint API endpoint for the tool
102
+ * @param authRequirements Authentication requirements (optional)
103
+ */
104
+ public registerTool<TAuthData>(
105
+ name: string,
106
+ description: string,
107
+ handler: (params: unknown, authData?: TAuthData) => Promise<unknown>,
108
+ parameters: Parameter[],
109
+ endpoint: string,
110
+ authRequirements?: AuthRequirement[]
111
+ ): void {
112
+ const func = new Tool<TAuthData>(name, description, parameters, endpoint, handler, authRequirements);
113
+ this.functions.set(endpoint, func);
114
+ }
115
+
116
+ /**
117
+ * Register a tool interaction with generic auth data
118
+ * @param name Tool name
119
+ * @param handler Function implementing the tool
120
+ * @param endpoint API endpoint for the tool
121
+ */
122
+ public registerInteraction<TAuthData>(
123
+ name: string,
124
+ handler: (data: unknown, authData?: TAuthData) => Promise<InteractionResult>,
125
+ endpoint: string
126
+ ): void {
127
+ const func = new Interaction<TAuthData>(name, endpoint, handler);
128
+ this.interactions.set(endpoint, func);
129
+ }
130
+
131
+ public async processRequest(req: App.Request): Promise<App.Response> {
132
+ if (req.path === '/discovery') {
133
+ return new App.Response(200, { functions: Array.from(this.functions.values()).map((f) => f.toJSON()) });
134
+ } else {
135
+ const func = this.functions.get(req.path);
136
+ if (func) {
137
+ try {
138
+ let params;
139
+ if (req.bodyJSON && req.bodyJSON.parameters) {
140
+ params = req.bodyJSON.parameters;
141
+ } else {
142
+ params = req.bodyJSON;
143
+ }
144
+
145
+ // Extract auth data from body JSON
146
+ const authData = req.bodyJSON ? req.bodyJSON.auth : undefined;
147
+
148
+ const result = await func.handler(params, authData);
149
+ return new App.Response(200, result);
150
+ } catch (error: any) {
151
+ logger.error(`Error in function ${func.name}:`, error);
152
+ return new App.Response(500, { error: error.message || 'Unknown error' });
153
+ }
154
+ }
155
+
156
+ const interaction = this.interactions.get(req.path);
157
+ if (interaction) {
158
+ try {
159
+ let params;
160
+ if (req.bodyJSON && req.bodyJSON.data) {
161
+ params = req.bodyJSON.data;
162
+ } else {
163
+ params = req.bodyJSON;
164
+ }
165
+
166
+ // Extract auth data from body JSON
167
+ const authData = req.bodyJSON ? req.bodyJSON.auth : undefined;
168
+
169
+ const result = await interaction.handler(params, authData);
170
+ return new App.Response(200, result);
171
+ } catch (error: any) {
172
+ logger.error(`Error in function ${interaction.name}:`, error);
173
+ return new App.Response(500, { error: error.message || 'Unknown error' });
174
+ }
175
+ }
176
+
177
+ return new App.Response(404, 'Function not found');
178
+ }
179
+ }
180
+ }
181
+
182
+ export const toolsService = new ToolsService();
@@ -0,0 +1,163 @@
1
+ /* eslint-disable max-classes-per-file */
2
+ /**
3
+ * Types of parameters supported by Opal tools
4
+ */
5
+ export enum ParameterType {
6
+ String = 'string',
7
+ Integer = 'integer',
8
+ Number = 'number',
9
+ Boolean = 'boolean',
10
+ List = 'list',
11
+ Dictionary = 'object'
12
+ }
13
+
14
+ /**
15
+ * Parameter definition for an Opal tool
16
+ */
17
+ export class Parameter {
18
+ /**
19
+ * Create a new parameter definition
20
+ * @param name Parameter name
21
+ * @param type Parameter type
22
+ * @param description Parameter description
23
+ * @param required Whether the parameter is required
24
+ */
25
+ public constructor(
26
+ public name: string,
27
+ public type: ParameterType,
28
+ public description: string,
29
+ public required: boolean
30
+ ) {}
31
+
32
+ /**
33
+ * Convert to JSON for the discovery endpoint
34
+ */
35
+ public toJSON() {
36
+ return {
37
+ name: this.name,
38
+ type: this.type,
39
+ description: this.description,
40
+ required: this.required
41
+ };
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Credentials structure
47
+ */
48
+ export class OptiIdAuthDataCredentials {
49
+
50
+ public constructor(
51
+ public customerId: string,
52
+ public instanceId: string,
53
+ public accessToken: string,
54
+ public productSku: string
55
+ ) {}
56
+ }
57
+
58
+
59
+ /**
60
+ * Auth data structure
61
+ */
62
+ export class OptiIdAuthData {
63
+
64
+ public constructor(
65
+ public provider: string,
66
+ public credentials: OptiIdAuthDataCredentials
67
+ ) {}
68
+ }
69
+
70
+ /**
71
+ * Authentication requirements for an Opal tool
72
+ */
73
+ export class AuthRequirement {
74
+ /**
75
+ * Create a new authentication requirement
76
+ * @param provider Auth provider (e.g., "optiId")
77
+ * @param scopeBundle Scope bundle (e.g., "calendar", "drive")
78
+ * @param required Whether authentication is required
79
+ */
80
+ public constructor(
81
+ public provider: string,
82
+ public scopeBundle: string,
83
+ public required: boolean = true
84
+ ) {}
85
+
86
+ /**
87
+ * Convert to JSON for the discovery endpoint
88
+ */
89
+ public toJSON() {
90
+ return {
91
+ provider: this.provider,
92
+ scope_bundle: this.scopeBundle,
93
+ required: this.required
94
+ };
95
+ }
96
+ }
97
+
98
+ export class IslandField {
99
+
100
+ public constructor(
101
+ public name: string,
102
+ public label: string,
103
+ public type: 'string' | 'boolean' | 'json',
104
+ public value: string | boolean | object = '',
105
+ public hidden: boolean = false,
106
+ public options: string[] = []
107
+ ) {}
108
+
109
+ public toJSON() {
110
+ return {
111
+ name: this.name,
112
+ label: this.label,
113
+ type: this.type,
114
+ hidden: this.hidden,
115
+ options: this.options,
116
+ value: this.value
117
+ };
118
+ }
119
+ }
120
+
121
+ export class IslandAction {
122
+
123
+ public constructor(
124
+ public name: string,
125
+ public label: string,
126
+ public type: string,
127
+ public endpoint: string,
128
+ public operation: string = 'create'
129
+ ) {}
130
+
131
+ public toJSON() {
132
+ return {
133
+ name: this.name,
134
+ label: this.label,
135
+ type: this.type,
136
+ endpoint: this.endpoint,
137
+ operation: this.operation
138
+ };
139
+ }
140
+ }
141
+
142
+ export class IslandConfig {
143
+
144
+ public constructor(
145
+ public fields: IslandField[],
146
+ public actions: IslandAction[]
147
+ ) {}
148
+ }
149
+
150
+ export class IslandResponse {
151
+
152
+ public constructor(
153
+ public type: 'island',
154
+ public config: {
155
+ islands: IslandConfig[];
156
+ }
157
+ ) {}
158
+
159
+ public static create(islands: IslandConfig[]): IslandResponse {
160
+ return new IslandResponse('island', { islands });
161
+ }
162
+ }
163
+