@optimizely-opal/opal-tools-sdk 0.1.2-dev → 0.1.3-dev

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 CHANGED
@@ -9,6 +9,7 @@ This SDK simplifies the creation of tools services compatible with the Opal Tool
9
9
  - Parameter validation and type checking
10
10
  - Authentication helpers
11
11
  - Express integration
12
+ - Island components for interactive UI responses
12
13
 
13
14
  ## Installation
14
15
 
@@ -19,7 +20,7 @@ npm install @optimizely-opal/opal-tools-sdk
19
20
  ## Usage
20
21
 
21
22
  ```typescript
22
- import { ToolsService, tool } from '@optimizely-opal/opal-tools-sdk';
23
+ import { ToolsService, tool, IslandResponse, IslandConfig } from '@optimizely-opal/opal-tools-sdk';
23
24
  import express from 'express';
24
25
 
25
26
  const app = express();
@@ -121,6 +122,151 @@ async function getEmail(parameters: EmailParameters, authData?: any) {
121
122
  }
122
123
  ```
123
124
 
125
+ ## Authentication
126
+
127
+ The SDK provides authentication support for tools that require user credentials:
128
+
129
+ ```typescript
130
+ import { ToolsService, tool, requiresAuth, AuthData } from '@optimizely-opal/opal-tools-sdk';
131
+ import express from 'express';
132
+
133
+ interface CalendarParameters {
134
+ date: string;
135
+ timezone?: string;
136
+ }
137
+
138
+ const app = express();
139
+ const toolsService = new ToolsService(app);
140
+
141
+ @requiresAuth({ provider: 'google', scopeBundle: 'calendar', required: true })
142
+ @tool({
143
+ name: 'get_calendar_events',
144
+ description: 'Gets calendar events for a date'
145
+ })
146
+ async function getCalendarEvents(parameters: CalendarParameters, authData?: AuthData) {
147
+ // The authData parameter contains authentication information
148
+ if (authData) {
149
+ const token = authData.credentials.access_token;
150
+ // Use the token to make authenticated requests
151
+ }
152
+
153
+ return { events: ['Meeting at 10:00', 'Lunch at 12:00'] };
154
+ }
155
+ ```
156
+
157
+ ## Island Components
158
+
159
+ The SDK includes Island components for creating interactive UI responses:
160
+
161
+ ```typescript
162
+ import {
163
+ ToolsService,
164
+ tool,
165
+ IslandResponse,
166
+ IslandConfig
167
+ } from '@optimizely-opal/opal-tools-sdk';
168
+ import express from 'express';
169
+
170
+ interface WeatherParameters {
171
+ location: string;
172
+ units?: string;
173
+ }
174
+
175
+ const app = express();
176
+ const toolsService = new ToolsService(app);
177
+
178
+ @tool({
179
+ name: 'get_weather',
180
+ description: 'Gets current weather for a location'
181
+ })
182
+ async function getWeather(parameters: WeatherParameters) {
183
+ // Get weather data (implementation details omitted)
184
+ const weatherData = { temperature: 22, condition: 'sunny', humidity: 65 };
185
+
186
+ // Create an interactive island for weather settings
187
+ const island = new IslandConfig(
188
+ [
189
+ new IslandConfig.Field(
190
+ 'location',
191
+ 'Location',
192
+ 'string',
193
+ parameters.location
194
+ ),
195
+ new IslandConfig.Field(
196
+ 'units',
197
+ 'Temperature Units',
198
+ 'string',
199
+ parameters.units || 'metric',
200
+ false,
201
+ ['metric', 'imperial', 'kelvin']
202
+ ),
203
+ new IslandConfig.Field(
204
+ 'current_temp',
205
+ 'Current Temperature',
206
+ 'string',
207
+ `${weatherData.temperature}°${parameters.units === 'metric' ? 'C' : 'F'}`
208
+ )
209
+ ],
210
+ [
211
+ new IslandConfig.Action(
212
+ 'refresh_weather',
213
+ 'Refresh Weather',
214
+ 'button',
215
+ '/tools/get_weather',
216
+ 'update'
217
+ )
218
+ ]
219
+ );
220
+
221
+ return IslandResponse.create([island]);
222
+ }
223
+ ```
224
+
225
+ ### Island Components
226
+
227
+ #### IslandConfig.Field
228
+ Fields represent data inputs in the UI:
229
+ - `name`: Programmatic field identifier
230
+ - `label`: Human-readable label
231
+ - `type`: Field type (`'string'`, `'boolean'`, `'json'`)
232
+ - `value`: Current field value (optional)
233
+ - `hidden`: Whether to hide from user (optional, default: false)
234
+ - `options`: Available options for selection (optional)
235
+
236
+ #### IslandConfig.Action
237
+ Actions represent buttons or operations:
238
+ - `name`: Programmatic action identifier
239
+ - `label`: Human-readable button label
240
+ - `type`: UI element type (typically `'button'`)
241
+ - `endpoint`: API endpoint to call
242
+ - `operation`: Operation type (default: `'create'`)
243
+
244
+ #### IslandConfig
245
+ Contains the complete island configuration:
246
+ - `fields`: Array of IslandConfig.Field objects
247
+ - `actions`: Array of IslandConfig.Action objects
248
+
249
+ #### IslandResponse
250
+ The response wrapper for islands:
251
+ - Use `IslandResponse.create([islands])` to create responses
252
+ - Supports multiple islands per response
253
+
254
+ ## Type Definitions
255
+
256
+ The SDK provides comprehensive TypeScript type definitions:
257
+
258
+ ### Authentication Types
259
+ - `AuthData`: Interface containing provider and credentials information
260
+ - `Credentials`: Interface with access_token, org_sso_id, customer_id, instance_id, and product_sku
261
+ - `Environment`: Interface specifying execution mode (`'headless'` or `'interactive'`)
262
+
263
+ ### Parameter Types
264
+ - `ParameterType`: Enum for supported parameter types
265
+ - `Parameter`: Class for tool parameter definitions
266
+ - `Function`: Class for complete tool function definitions
267
+
268
+ These types provide full IDE support and compile-time type checking for better development experience.
269
+
124
270
  ## Documentation
125
271
 
126
272
  See full documentation for more examples and configuration options.
package/dist/models.d.ts CHANGED
@@ -6,7 +6,7 @@ export declare enum ParameterType {
6
6
  Integer = "integer",
7
7
  Number = "number",
8
8
  Boolean = "boolean",
9
- List = "list",
9
+ List = "array",
10
10
  Dictionary = "object"
11
11
  }
12
12
  /**
@@ -85,3 +85,198 @@ export declare class Function {
85
85
  */
86
86
  toJSON(): any;
87
87
  }
88
+ /**
89
+ * Authentication credentials structure
90
+ */
91
+ export type Credentials = {
92
+ access_token: string;
93
+ org_sso_id?: string;
94
+ customer_id: string;
95
+ instance_id: string;
96
+ product_sku: string;
97
+ };
98
+ /**
99
+ * Authentication data for an Opal tool
100
+ */
101
+ export type AuthData = {
102
+ provider: string;
103
+ credentials: Credentials;
104
+ };
105
+ /**
106
+ * Execution environment for an Opal tool
107
+ */
108
+ export type Environment = {
109
+ execution_mode: "headless" | "interactive";
110
+ };
111
+ /**
112
+ * Island field definition for interactive UI components
113
+ */
114
+ export declare class IslandField {
115
+ name: string;
116
+ label: string;
117
+ type: "string" | "boolean" | "json";
118
+ value: string;
119
+ hidden: boolean;
120
+ options: string[];
121
+ /**
122
+ * Create a new island field
123
+ * @param name Programmatic field identifier
124
+ * @param label Human-readable label
125
+ * @param type Field type
126
+ * @param value Current field value
127
+ * @param hidden Whether to hide from user
128
+ * @param options Available options for selection
129
+ */
130
+ constructor(name: string, label: string, type: "string" | "boolean" | "json", value?: string, hidden?: boolean, options?: string[]);
131
+ /**
132
+ * Convert to JSON for the discovery endpoint
133
+ */
134
+ toJSON(): {
135
+ name: string;
136
+ label: string;
137
+ type: "string" | "boolean" | "json";
138
+ value: string;
139
+ hidden: boolean;
140
+ options: string[];
141
+ };
142
+ }
143
+ /**
144
+ * Island action definition for interactive UI components
145
+ */
146
+ export declare class IslandAction {
147
+ name: string;
148
+ label: string;
149
+ type: string;
150
+ endpoint: string;
151
+ operation: string;
152
+ /**
153
+ * Create a new island action
154
+ * @param name Programmatic action identifier
155
+ * @param label Human-readable button label
156
+ * @param type UI element type
157
+ * @param endpoint API endpoint to call
158
+ * @param operation Operation type
159
+ */
160
+ constructor(name: string, label: string, type: string, endpoint: string, operation?: string);
161
+ /**
162
+ * Convert to JSON for the discovery endpoint
163
+ */
164
+ toJSON(): {
165
+ name: string;
166
+ label: string;
167
+ type: string;
168
+ endpoint: string;
169
+ operation: string;
170
+ };
171
+ }
172
+ /**
173
+ * Island configuration for interactive UI components
174
+ */
175
+ export declare class IslandConfig {
176
+ fields: IslandField[];
177
+ actions: IslandAction[];
178
+ static Field: typeof IslandField;
179
+ static Action: typeof IslandAction;
180
+ /**
181
+ * Create a new island configuration
182
+ * @param fields List of island fields
183
+ * @param actions List of island actions
184
+ */
185
+ constructor(fields: IslandField[], actions: IslandAction[]);
186
+ /**
187
+ * Convert to JSON for the discovery endpoint
188
+ */
189
+ toJSON(): {
190
+ fields: {
191
+ name: string;
192
+ label: string;
193
+ type: "string" | "boolean" | "json";
194
+ value: string;
195
+ hidden: boolean;
196
+ options: string[];
197
+ }[];
198
+ actions: {
199
+ name: string;
200
+ label: string;
201
+ type: string;
202
+ endpoint: string;
203
+ operation: string;
204
+ }[];
205
+ };
206
+ }
207
+ /**
208
+ * Island response configuration
209
+ */
210
+ export declare class IslandResponseConfig {
211
+ islands: IslandConfig[];
212
+ /**
213
+ * Create a new island response configuration
214
+ * @param islands List of island configurations
215
+ */
216
+ constructor(islands: IslandConfig[]);
217
+ /**
218
+ * Convert to JSON for the discovery endpoint
219
+ */
220
+ toJSON(): {
221
+ islands: {
222
+ fields: {
223
+ name: string;
224
+ label: string;
225
+ type: "string" | "boolean" | "json";
226
+ value: string;
227
+ hidden: boolean;
228
+ options: string[];
229
+ }[];
230
+ actions: {
231
+ name: string;
232
+ label: string;
233
+ type: string;
234
+ endpoint: string;
235
+ operation: string;
236
+ }[];
237
+ }[];
238
+ };
239
+ }
240
+ /**
241
+ * Island response wrapper for interactive UI components
242
+ */
243
+ export declare class IslandResponse {
244
+ config: IslandResponseConfig;
245
+ static ResponseConfig: typeof IslandResponseConfig;
246
+ type: "island";
247
+ /**
248
+ * Create a new island response
249
+ * @param config Response configuration
250
+ */
251
+ constructor(config: IslandResponseConfig);
252
+ /**
253
+ * Create an island response with a list of islands
254
+ * @param islands List of island configurations
255
+ * @returns New IslandResponse instance
256
+ */
257
+ static create(islands: IslandConfig[]): IslandResponse;
258
+ /**
259
+ * Convert to JSON for the discovery endpoint
260
+ */
261
+ toJSON(): {
262
+ config: {
263
+ islands: {
264
+ fields: {
265
+ name: string;
266
+ label: string;
267
+ type: "string" | "boolean" | "json";
268
+ value: string;
269
+ hidden: boolean;
270
+ options: string[];
271
+ }[];
272
+ actions: {
273
+ name: string;
274
+ label: string;
275
+ type: string;
276
+ endpoint: string;
277
+ operation: string;
278
+ }[];
279
+ }[];
280
+ };
281
+ };
282
+ }
package/dist/models.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Function = exports.AuthRequirement = exports.Parameter = exports.ParameterType = void 0;
3
+ exports.IslandResponse = exports.IslandResponseConfig = exports.IslandConfig = exports.IslandAction = exports.IslandField = exports.Function = exports.AuthRequirement = exports.Parameter = exports.ParameterType = void 0;
4
4
  /**
5
5
  * Types of parameters supported by Opal tools
6
6
  */
@@ -10,7 +10,7 @@ var ParameterType;
10
10
  ParameterType["Integer"] = "integer";
11
11
  ParameterType["Number"] = "number";
12
12
  ParameterType["Boolean"] = "boolean";
13
- ParameterType["List"] = "list";
13
+ ParameterType["List"] = "array";
14
14
  ParameterType["Dictionary"] = "object";
15
15
  })(ParameterType || (exports.ParameterType = ParameterType = {}));
16
16
  /**
@@ -111,3 +111,150 @@ class Function {
111
111
  }
112
112
  }
113
113
  exports.Function = Function;
114
+ /**
115
+ * Island field definition for interactive UI components
116
+ */
117
+ class IslandField {
118
+ /**
119
+ * Create a new island field
120
+ * @param name Programmatic field identifier
121
+ * @param label Human-readable label
122
+ * @param type Field type
123
+ * @param value Current field value
124
+ * @param hidden Whether to hide from user
125
+ * @param options Available options for selection
126
+ */
127
+ constructor(name, label, type, value = "", hidden = false, options = []) {
128
+ this.name = name;
129
+ this.label = label;
130
+ this.type = type;
131
+ this.value = value;
132
+ this.hidden = hidden;
133
+ this.options = options;
134
+ }
135
+ /**
136
+ * Convert to JSON for the discovery endpoint
137
+ */
138
+ toJSON() {
139
+ return {
140
+ name: this.name,
141
+ label: this.label,
142
+ type: this.type,
143
+ value: this.value,
144
+ hidden: this.hidden,
145
+ options: this.options,
146
+ };
147
+ }
148
+ }
149
+ exports.IslandField = IslandField;
150
+ /**
151
+ * Island action definition for interactive UI components
152
+ */
153
+ class IslandAction {
154
+ /**
155
+ * Create a new island action
156
+ * @param name Programmatic action identifier
157
+ * @param label Human-readable button label
158
+ * @param type UI element type
159
+ * @param endpoint API endpoint to call
160
+ * @param operation Operation type
161
+ */
162
+ constructor(name, label, type, endpoint, operation = "create") {
163
+ this.name = name;
164
+ this.label = label;
165
+ this.type = type;
166
+ this.endpoint = endpoint;
167
+ this.operation = operation;
168
+ }
169
+ /**
170
+ * Convert to JSON for the discovery endpoint
171
+ */
172
+ toJSON() {
173
+ return {
174
+ name: this.name,
175
+ label: this.label,
176
+ type: this.type,
177
+ endpoint: this.endpoint,
178
+ operation: this.operation,
179
+ };
180
+ }
181
+ }
182
+ exports.IslandAction = IslandAction;
183
+ /**
184
+ * Island configuration for interactive UI components
185
+ */
186
+ class IslandConfig {
187
+ /**
188
+ * Create a new island configuration
189
+ * @param fields List of island fields
190
+ * @param actions List of island actions
191
+ */
192
+ constructor(fields, actions) {
193
+ this.fields = fields;
194
+ this.actions = actions;
195
+ }
196
+ /**
197
+ * Convert to JSON for the discovery endpoint
198
+ */
199
+ toJSON() {
200
+ return {
201
+ fields: this.fields.map((field) => field.toJSON()),
202
+ actions: this.actions.map((action) => action.toJSON()),
203
+ };
204
+ }
205
+ }
206
+ exports.IslandConfig = IslandConfig;
207
+ IslandConfig.Field = IslandField;
208
+ IslandConfig.Action = IslandAction;
209
+ /**
210
+ * Island response configuration
211
+ */
212
+ class IslandResponseConfig {
213
+ /**
214
+ * Create a new island response configuration
215
+ * @param islands List of island configurations
216
+ */
217
+ constructor(islands) {
218
+ this.islands = islands;
219
+ }
220
+ /**
221
+ * Convert to JSON for the discovery endpoint
222
+ */
223
+ toJSON() {
224
+ return {
225
+ islands: this.islands.map((island) => island.toJSON()),
226
+ };
227
+ }
228
+ }
229
+ exports.IslandResponseConfig = IslandResponseConfig;
230
+ /**
231
+ * Island response wrapper for interactive UI components
232
+ */
233
+ class IslandResponse {
234
+ /**
235
+ * Create a new island response
236
+ * @param config Response configuration
237
+ */
238
+ constructor(config) {
239
+ this.config = config;
240
+ this.type = "island";
241
+ }
242
+ /**
243
+ * Create an island response with a list of islands
244
+ * @param islands List of island configurations
245
+ * @returns New IslandResponse instance
246
+ */
247
+ static create(islands) {
248
+ return new IslandResponse(new IslandResponseConfig(islands));
249
+ }
250
+ /**
251
+ * Convert to JSON for the discovery endpoint
252
+ */
253
+ toJSON() {
254
+ return {
255
+ config: this.config.toJSON(),
256
+ };
257
+ }
258
+ }
259
+ exports.IslandResponse = IslandResponse;
260
+ IslandResponse.ResponseConfig = IslandResponseConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimizely-opal/opal-tools-sdk",
3
- "version": "0.1.2-dev",
3
+ "version": "0.1.3-dev",
4
4
  "description": "SDK for creating Opal-compatible tools services",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/decorators.ts CHANGED
@@ -36,7 +36,7 @@ function mapTypeToParameterType(type: any): ParameterType {
36
36
  } else if (type === Object || type.name === 'Object') {
37
37
  return ParameterType.Dictionary;
38
38
  }
39
-
39
+
40
40
  // Default to string
41
41
  return ParameterType.String;
42
42
  }
@@ -47,14 +47,14 @@ function mapTypeToParameterType(type: any): ParameterType {
47
47
  */
48
48
  function extractParameters(paramType: any): Parameter[] {
49
49
  const parameters: Parameter[] = [];
50
-
50
+
51
51
  // This is very basic and doesn't handle complex types
52
52
  // For production use, this would need to be more sophisticated
53
53
  for (const key in paramType) {
54
54
  if (paramType.hasOwnProperty(key)) {
55
55
  const type = typeof paramType[key] === 'undefined' ? String : paramType[key].constructor;
56
56
  const required = true; // In a real implementation, we'd detect optional parameters
57
-
57
+
58
58
  parameters.push(new Parameter(
59
59
  key,
60
60
  mapTypeToParameterType(type),
@@ -63,7 +63,7 @@ function extractParameters(paramType: any): Parameter[] {
63
63
  ));
64
64
  }
65
65
  }
66
-
66
+
67
67
  return parameters;
68
68
  }
69
69
 
@@ -72,10 +72,10 @@ function extractParameters(paramType: any): Parameter[] {
72
72
  * @param options Tool options including:
73
73
  * - name: Name of the tool
74
74
  * - description: Description of the tool
75
- * - authRequirements: (Optional) Authentication requirements
75
+ * - authRequirements: (Optional) Authentication requirements
76
76
  * Format: { provider: "oauth_provider", scopeBundle: "permissions_scope", required: true }
77
77
  * Example: { provider: "google", scopeBundle: "calendar", required: true }
78
- *
78
+ *
79
79
  * Note: If your tool requires authentication, define your handler function with two parameters:
80
80
  * ```
81
81
  * async function myTool(parameters: ParameterInterface, authData?: any): Promise<any> {
@@ -87,10 +87,10 @@ export function tool(options: ToolOptions) {
87
87
  return function(target: any, propertyKey?: string, descriptor?: PropertyDescriptor) {
88
88
  const isMethod = propertyKey && descriptor;
89
89
  const handler = isMethod ? descriptor.value : target;
90
-
90
+
91
91
  // Generate endpoint from name - ensure hyphens instead of underscores
92
92
  const endpoint = `/tools/${options.name.replace(/_/g, '-')}`;
93
-
93
+
94
94
  // Convert parameter definitions to Parameter objects
95
95
  const parameters: Parameter[] = [];
96
96
  if (options.parameters && options.parameters.length > 0) {
@@ -104,7 +104,7 @@ export function tool(options: ToolOptions) {
104
104
  ));
105
105
  }
106
106
  }
107
-
107
+
108
108
  // Create auth requirements if specified
109
109
  let authRequirements: AuthRequirement[] | undefined;
110
110
  if (options.authRequirements) {
@@ -116,7 +116,7 @@ export function tool(options: ToolOptions) {
116
116
  )
117
117
  ];
118
118
  }
119
-
119
+
120
120
  // Register the tool with all services
121
121
  for (const service of registry.services) {
122
122
  service.registerTool(
@@ -128,7 +128,7 @@ export function tool(options: ToolOptions) {
128
128
  authRequirements
129
129
  );
130
130
  }
131
-
131
+
132
132
  return isMethod ? descriptor : target;
133
133
  };
134
134
  }
package/src/models.ts CHANGED
@@ -6,7 +6,7 @@ export enum ParameterType {
6
6
  Integer = 'integer',
7
7
  Number = 'number',
8
8
  Boolean = 'boolean',
9
- List = 'list',
9
+ List = 'array',
10
10
  Dictionary = 'object'
11
11
  }
12
12
 
@@ -113,3 +113,181 @@ export class Function {
113
113
  return result;
114
114
  }
115
115
  }
116
+
117
+ /**
118
+ * Authentication credentials structure
119
+ */
120
+ export type Credentials ={
121
+ access_token: string;
122
+ org_sso_id?: string;
123
+ customer_id: string;
124
+ instance_id: string;
125
+ product_sku: string;
126
+ }
127
+
128
+ /**
129
+ * Authentication data for an Opal tool
130
+ */
131
+ export type AuthData = {
132
+ provider: string;
133
+ credentials: Credentials;
134
+ }
135
+
136
+ /**
137
+ * Execution environment for an Opal tool
138
+ */
139
+ export type Environment = {
140
+ execution_mode: "headless" | "interactive";
141
+ }
142
+
143
+ /**
144
+ * Island field definition for interactive UI components
145
+ */
146
+ export class IslandField {
147
+ /**
148
+ * Create a new island field
149
+ * @param name Programmatic field identifier
150
+ * @param label Human-readable label
151
+ * @param type Field type
152
+ * @param value Current field value
153
+ * @param hidden Whether to hide from user
154
+ * @param options Available options for selection
155
+ */
156
+ constructor(
157
+ public name: string,
158
+ public label: string,
159
+ public type: "string" | "boolean" | "json",
160
+ public value: string = "",
161
+ public hidden: boolean = false,
162
+ public options: string[] = []
163
+ ) {}
164
+
165
+ /**
166
+ * Convert to JSON for the discovery endpoint
167
+ */
168
+ toJSON() {
169
+ return {
170
+ name: this.name,
171
+ label: this.label,
172
+ type: this.type,
173
+ value: this.value,
174
+ hidden: this.hidden,
175
+ options: this.options,
176
+ };
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Island action definition for interactive UI components
182
+ */
183
+ export class IslandAction {
184
+ /**
185
+ * Create a new island action
186
+ * @param name Programmatic action identifier
187
+ * @param label Human-readable button label
188
+ * @param type UI element type
189
+ * @param endpoint API endpoint to call
190
+ * @param operation Operation type
191
+ */
192
+ constructor(
193
+ public name: string,
194
+ public label: string,
195
+ public type: string,
196
+ public endpoint: string,
197
+ public operation: string = "create"
198
+ ) {}
199
+
200
+ /**
201
+ * Convert to JSON for the discovery endpoint
202
+ */
203
+ toJSON() {
204
+ return {
205
+ name: this.name,
206
+ label: this.label,
207
+ type: this.type,
208
+ endpoint: this.endpoint,
209
+ operation: this.operation,
210
+ };
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Island configuration for interactive UI components
216
+ */
217
+ export class IslandConfig {
218
+ static Field = IslandField;
219
+ static Action = IslandAction;
220
+
221
+ /**
222
+ * Create a new island configuration
223
+ * @param fields List of island fields
224
+ * @param actions List of island actions
225
+ */
226
+ constructor(
227
+ public fields: IslandField[],
228
+ public actions: IslandAction[]
229
+ ) {}
230
+
231
+ /**
232
+ * Convert to JSON for the discovery endpoint
233
+ */
234
+ toJSON() {
235
+ return {
236
+ fields: this.fields.map((field) => field.toJSON()),
237
+ actions: this.actions.map((action) => action.toJSON()),
238
+ };
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Island response configuration
244
+ */
245
+ export class IslandResponseConfig {
246
+ /**
247
+ * Create a new island response configuration
248
+ * @param islands List of island configurations
249
+ */
250
+ constructor(public islands: IslandConfig[]) {}
251
+
252
+ /**
253
+ * Convert to JSON for the discovery endpoint
254
+ */
255
+ toJSON() {
256
+ return {
257
+ islands: this.islands.map((island) => island.toJSON()),
258
+ };
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Island response wrapper for interactive UI components
264
+ */
265
+ export class IslandResponse {
266
+ static ResponseConfig = IslandResponseConfig;
267
+
268
+ public type: "island" = "island";
269
+
270
+ /**
271
+ * Create a new island response
272
+ * @param config Response configuration
273
+ */
274
+ constructor(public config: IslandResponseConfig) {}
275
+
276
+ /**
277
+ * Create an island response with a list of islands
278
+ * @param islands List of island configurations
279
+ * @returns New IslandResponse instance
280
+ */
281
+ static create(islands: IslandConfig[]): IslandResponse {
282
+ return new IslandResponse(new IslandResponseConfig(islands));
283
+ }
284
+
285
+ /**
286
+ * Convert to JSON for the discovery endpoint
287
+ */
288
+ toJSON() {
289
+ return {
290
+ config: this.config.toJSON(),
291
+ };
292
+ }
293
+ }