@optimizely-opal/opal-tool-ocp-sdk 0.0.0-beta.1 โ†’ 0.0.0-beta.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.
Files changed (46) hide show
  1. package/README.md +106 -51
  2. package/dist/auth/TokenVerifier.d.ts +31 -0
  3. package/dist/auth/TokenVerifier.d.ts.map +1 -0
  4. package/dist/auth/TokenVerifier.js +127 -0
  5. package/dist/auth/TokenVerifier.js.map +1 -0
  6. package/dist/auth/TokenVerifier.test.d.ts +2 -0
  7. package/dist/auth/TokenVerifier.test.d.ts.map +1 -0
  8. package/dist/auth/TokenVerifier.test.js +114 -0
  9. package/dist/auth/TokenVerifier.test.js.map +1 -0
  10. package/dist/decorator/Decorator.d.ts +4 -2
  11. package/dist/decorator/Decorator.d.ts.map +1 -1
  12. package/dist/decorator/Decorator.js +26 -4
  13. package/dist/decorator/Decorator.js.map +1 -1
  14. package/dist/decorator/Decorator.test.js +110 -0
  15. package/dist/decorator/Decorator.test.js.map +1 -1
  16. package/dist/function/ToolFunction.d.ts +14 -1
  17. package/dist/function/ToolFunction.d.ts.map +1 -1
  18. package/dist/function/ToolFunction.js +59 -3
  19. package/dist/function/ToolFunction.js.map +1 -1
  20. package/dist/function/ToolFunction.test.js +229 -104
  21. package/dist/function/ToolFunction.test.js.map +1 -1
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/service/Service.d.ts +14 -13
  27. package/dist/service/Service.d.ts.map +1 -1
  28. package/dist/service/Service.js +25 -19
  29. package/dist/service/Service.js.map +1 -1
  30. package/dist/service/Service.test.js +122 -36
  31. package/dist/service/Service.test.js.map +1 -1
  32. package/dist/types/Models.d.ts +5 -5
  33. package/dist/types/Models.d.ts.map +1 -1
  34. package/dist/types/Models.js +9 -9
  35. package/dist/types/Models.js.map +1 -1
  36. package/package.json +10 -3
  37. package/src/auth/TokenVerifier.test.ts +152 -0
  38. package/src/auth/TokenVerifier.ts +145 -0
  39. package/src/decorator/Decorator.test.ts +126 -0
  40. package/src/decorator/Decorator.ts +32 -4
  41. package/src/function/ToolFunction.test.ts +259 -109
  42. package/src/function/ToolFunction.ts +66 -5
  43. package/src/index.ts +1 -0
  44. package/src/service/Service.test.ts +139 -28
  45. package/src/service/Service.ts +31 -24
  46. package/src/types/Models.ts +4 -4
package/README.md CHANGED
@@ -10,7 +10,7 @@ A TypeScript SDK for building Opal tools in Optimizely Connect Platform. This SD
10
10
  - ๐Ÿ”ง **Type-safe Development** - Full TypeScript support with comprehensive type definitions
11
11
  - ๐Ÿ—๏ธ **Abstract Base Classes** - Extend `ToolFunction` for standardized request processing
12
12
  - ๐Ÿ” **Authentication Support** - OptiID authentication
13
- - ๐Ÿ›ก๏ธ **Authorization Support** - Bearer token tool authorization
13
+ - ๐Ÿ›ก๏ธ **Authorization Support** - OptiID token tool authorization
14
14
  - ๐Ÿ“ **Parameter Validation** - Define and validate tool parameters with types
15
15
  - ๐Ÿงช **Comprehensive Testing** - Fully tested with Jest
16
16
 
@@ -34,11 +34,6 @@ Create a tool function class by extending `ToolFunction` and registering your to
34
34
  import { ToolFunction, tool, interaction, ParameterType, InteractionResult, OptiIdAuthData } from '@optimizely-opal/opal-tool-ocp-sdk';
35
35
 
36
36
  export class MyToolFunction extends ToolFunction {
37
- // Implement required bearer token validation method
38
- validateBearerToken(token: string): boolean {
39
- const expectedToken = process.env.OPAL_TOOL_TOKEN;
40
- return token === expectedToken;
41
- }
42
37
 
43
38
  // Register a simple tool without authentication
44
39
  @tool({
@@ -120,7 +115,7 @@ export class MyToolFunction extends ToolFunction {
120
115
  Your function class inherits a `perform()` method from `ToolFunction` that serves as the main entry point for handling all incoming requests. When called, the SDK automatically:
121
116
 
122
117
  - **Routes requests** to your registered tools and interactions based on endpoints
123
- - **Handles authentication** and bearer token validation before calling your methods
118
+ - **Handles authentication** and OptiID token validation before calling your methods
124
119
  - **Provides discovery** at `/discovery` endpoint for OCP platform integration
125
120
  - **Returns proper HTTP responses** with correct status codes and JSON formatting
126
121
 
@@ -174,27 +169,18 @@ interface AuthRequirementConfig {
174
169
  }
175
170
  ```
176
171
 
177
- #### Bearer Token Support
172
+ #### OptiID Token Authorization
178
173
 
179
- The SDK automatically extracts Bearer tokens from the `authorization` header for tool authorization. When users register tools in Opal, they can specify a Bearer token that Opal will include in requests to validate the tool's identity.
174
+ The SDK automatically handles OptiID token validation for tool authorization. OptiID tokens provide both user authentication and authorization for tools, ensuring that only authenticated users with proper permissions can access your tools.
180
175
 
181
176
  **Token Validation:**
182
- - Bearer tokens are extracted from the `authorization: Bearer <token>` header
183
- - Empty strings and `undefined` tokens are treated as missing (no validation performed)
184
- - Implement the abstract `validateBearerToken(token: string): boolean` method to define your validation logic
177
+ - The SDK extracts and validates OptiID tokens from the request body
178
+ - Validation includes verifying that requests come from the same organization
179
+ - If validation fails, returns HTTP 403 Unauthorized before reaching your handler methods
180
+ - No additional configuration needed - validation is handled automatically
185
181
 
186
182
  ```typescript
187
183
  export class MyToolFunction extends ToolFunction {
188
- // Implement the required bearer token validation method
189
- validateBearerToken(token: string): boolean {
190
- // If you don't need bearer token validation, simply return true
191
- // return true;
192
-
193
- // For actual validation, compare against expected token
194
- const expectedToken = process.env.OPAL_TOOL_TOKEN;
195
- return token === expectedToken;
196
- }
197
-
198
184
  @tool({
199
185
  name: 'secure_tool',
200
186
  description: 'Tool that validates requests from Opal',
@@ -218,14 +204,6 @@ export class MyToolFunction extends ToolFunction {
218
204
  }
219
205
  ```
220
206
 
221
- **Bearer Token Usage:**
222
- - Set by users when registering tools in Opal
223
- - Used to authorize tool requests from Opal instances
224
- - Validates that requests are coming from trusted Opal sources
225
- - Requires implementing the abstract `validateBearerToken(token: string): boolean` method
226
- - If validation fails, returns HTTP 403 Forbidden before reaching your handler methods
227
-
228
-
229
207
  ## API Reference
230
208
 
231
209
  ### Handler Function Signatures
@@ -242,8 +220,6 @@ async handlerMethod(
242
220
  - **params**: The input parameters for tools, or interaction data for webhooks
243
221
  - **authData**: Available when OptiID user authentication is configured and successful
244
222
 
245
- **Note**: Bearer token validation is handled automatically by the base class. If a bearer token is present and fails validation, the request is rejected before reaching your handler methods.
246
-
247
223
  ### Decorators
248
224
 
249
225
  #### `@tool(config: ToolConfig)`
@@ -279,12 +255,12 @@ Abstract base class for OCP functions:
279
255
 
280
256
  ```typescript
281
257
  export abstract class ToolFunction extends Function {
258
+ protected ready(): Promise<boolean>;
282
259
  public async perform(): Promise<Response>;
283
- protected abstract validateBearerToken(token: string): boolean;
284
260
  }
285
261
  ```
286
262
 
287
- Extend this class and implement your OCP function. The `perform` method automatically routes requests to registered tools and handles bearer token validation. You must implement the `validateBearerToken` method to define how bearer tokens should be validated for your tools.
263
+ Extend this class and implement your OCP function. The `perform` method automatically routes requests to registered tools.
288
264
 
289
265
  ### Models
290
266
 
@@ -297,9 +273,13 @@ Key model classes with generic type support:
297
273
  - `InteractionResult` - Response from interactions
298
274
  - `OptiIdAuthData` - OptiID specific authentication data
299
275
 
300
- ## Discovery Endpoint
276
+ ## Discovery and Ready Endpoints
277
+
278
+ The SDK automatically provides two important endpoints:
301
279
 
302
- The SDK automatically provides a discovery endpoint at `/discovery` that returns all registered tools in the proper OCP format:
280
+ ### Discovery Endpoint (`/discovery`)
281
+
282
+ Returns all registered tools in the proper OCP format for platform integration:
303
283
 
304
284
  ```json
305
285
  {
@@ -349,6 +329,21 @@ The SDK automatically provides a discovery endpoint at `/discovery` that returns
349
329
  }
350
330
  ```
351
331
 
332
+ ### Ready Endpoint (`/ready`)
333
+
334
+ Returns the current readiness status of your function:
335
+
336
+ ```json
337
+ {
338
+ "ready": true
339
+ }
340
+ ```
341
+
342
+ This endpoint calls your function's `ready()` method and returns:
343
+ - `{ready: true}` when the function is ready to process requests
344
+ - `{ready: false}` when the function is not ready (missing configuration, external services unavailable, etc.)
345
+ - HTTP 200 status code regardless of ready state (the ready status is in the response body)
346
+
352
347
  ## Development
353
348
 
354
349
  ### Prerequisites
@@ -389,15 +384,6 @@ yarn lint
389
384
  import { ToolFunction, tool, interaction, ParameterType, OptiIdAuthData, InteractionResult } from '@optimizely-opal/opal-ocp-sdk';
390
385
 
391
386
  export class AuthenticatedFunction extends ToolFunction {
392
- // Implement required bearer token validation
393
- validateBearerToken(token: string): boolean {
394
- // If you don't need bearer token validation, simply return true
395
- // return true;
396
-
397
- // For actual validation, compare against expected token
398
- const expectedToken = process.env.OPAL_TOOL_TOKEN;
399
- return token === expectedToken;
400
- }
401
387
 
402
388
  // OptiID authentication example
403
389
  @tool({
@@ -559,12 +545,6 @@ import { ToolFunction } from '@optimizely-opal/opal-ocp-sdk';
559
545
  import * from './tools';
560
546
 
561
547
  export class MyToolFunction extends ToolFunction {
562
-
563
- // Implement required bearer token validation method
564
- validateBearerToken(token: string): boolean {
565
- const expectedToken = process.env.OPAL_TOOL_TOKEN;
566
- return token === expectedToken;
567
- }
568
548
  }
569
549
  ```
570
550
 
@@ -574,3 +554,78 @@ This approach provides several benefits:
574
554
  - **Reusability**: Tools can be shared across different ToolFunction classes
575
555
  - **Team collaboration**: Different developers can work on different tool files
576
556
  - **Testing**: Each tool class can be unit tested independently
557
+
558
+ ## Decorator Behavior and Instance Context
559
+
560
+ The `@tool` and `@interaction` decorators provide intelligent instance context management that behaves differently depending on where the decorated methods are defined:
561
+
562
+ ### ToolFunction Subclass Context
563
+
564
+ When decorators are used in a class that extends `ToolFunction`, the decorators can reuse the existing ToolFunction instance when called through the `perform()` method:
565
+
566
+ ```typescript
567
+ export class MyToolFunction extends ToolFunction {
568
+ private secretKey = process.env.SECRET_KEY;
569
+
570
+ @tool({
571
+ name: 'process_data',
572
+ description: 'Processes data using instance context',
573
+ endpoint: '/process-data',
574
+ parameters: [
575
+ { name: 'data', type: ParameterType.String, description: 'Data to process', required: true }
576
+ ]
577
+ })
578
+ async processData(params: { data: string }) {
579
+ // โœ… Can access instance properties and methods
580
+ // โœ… Can access this.request (inherited from ToolFunction)
581
+ // โœ… Shares state with other methods in the same request
582
+
583
+ const userAgent = this.request.headers.get('user-agent');
584
+ return {
585
+ processedData: this.encryptData(params.data),
586
+ userAgent,
587
+ timestamp: Date.now()
588
+ };
589
+ }
590
+
591
+ private encryptData(data: string): string {
592
+ // Uses instance property
593
+ return `encrypted_${data}_${this.secretKey}`;
594
+ }
595
+ }
596
+ ```
597
+
598
+ ### Standalone Class Context
599
+
600
+ When decorators are used in classes that don't extend `ToolFunction`, the decorators create new instances for each handler call:
601
+
602
+ ```typescript
603
+ export class StandaloneToolService {
604
+ private config = { apiKey: 'standalone-key' };
605
+
606
+ @tool({
607
+ name: 'standalone_operation',
608
+ description: 'Standalone operation without ToolFunction',
609
+ endpoint: '/standalone',
610
+ parameters: [
611
+ { name: 'input', type: ParameterType.String, description: 'Input data', required: true }
612
+ ]
613
+ })
614
+ async standaloneOperation(params: { input: string }) {
615
+ // โœ… Can access instance properties and methods
616
+ // โŒ Cannot access this.request (not inherited from ToolFunction)
617
+ // โŒ No shared state with ToolFunction lifecycle
618
+
619
+ return {
620
+ result: `${this.helperMethod()}: ${params.input}`,
621
+ source: 'standalone'
622
+ };
623
+ }
624
+
625
+ private helperMethod() {
626
+ return this.config.apiKey;
627
+ }
628
+ }
629
+ ```
630
+
631
+ This behavior ensures that your tools can be both flexible (working in any class) and powerful (leveraging ToolFunction features when available).
@@ -0,0 +1,31 @@
1
+ export declare class TokenVerifier {
2
+ private static instance;
3
+ private jwksUri?;
4
+ private issuer?;
5
+ private jwks?;
6
+ private initialized;
7
+ /**
8
+ * Verify the provided Optimizely JWT token string
9
+ * @param token JWT token string to verify
10
+ * @returns boolean true if verification successful, false otherwise
11
+ * @throws Error if token is null, empty, or verifier is not properly configured
12
+ */
13
+ verify(token: string | undefined): Promise<boolean>;
14
+ private static getInstance;
15
+ /**
16
+ * Get singleton instance of TokenVerifier and ensure it's initialized
17
+ * @returns Promise<TokenVerifier> - initialized singleton instance
18
+ */
19
+ static getInitializedInstance(): Promise<TokenVerifier>;
20
+ /**
21
+ * Initialize the TokenVerifier with discovery document from well-known endpoint
22
+ */
23
+ private initialize;
24
+ /**
25
+ * Fetch discovery document from well-known endpoint
26
+ */
27
+ private fetchDiscoveryDocument;
28
+ private verifyToken;
29
+ }
30
+ export declare const getTokenVerifier: () => Promise<TokenVerifier>;
31
+ //# sourceMappingURL=TokenVerifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenVerifier.d.ts","sourceRoot":"","sources":["../../src/auth/TokenVerifier.ts"],"names":[],"mappings":"AAkCA,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IACrD,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,IAAI,CAAC,CAAwC;IACrD,OAAO,CAAC,WAAW,CAAkB;IAErC;;;;;OAKG;IACU,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQhE,OAAO,CAAC,MAAM,CAAC,WAAW;IAO1B;;;OAGG;WACiB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC;IAQpE;;OAEG;YACW,UAAU;IAyBxB;;OAEG;YACW,sBAAsB;YAetB,WAAW;CAsB1B;AAED,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,aAAa,CAA2C,CAAC"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTokenVerifier = exports.TokenVerifier = void 0;
4
+ const jose_1 = require("jose");
5
+ const app_sdk_1 = require("@zaiusinc/app-sdk");
6
+ /**
7
+ * Default JWKS cache expiration time in milliseconds (1 hour)
8
+ */
9
+ const DEFAULT_JWKS_EXPIRES_IN = 60 * 60 * 1000;
10
+ /**
11
+ * Default clock skew tolerance in seconds
12
+ */
13
+ const DEFAULT_LEEWAY = 30;
14
+ /**
15
+ * Expected JWT audience for token validation
16
+ */
17
+ const AUDIENCE = 'api://default';
18
+ /**
19
+ * Prep Base URL for Optimizely OAuth2 endpoints
20
+ */
21
+ const PREP_BASE_URL = 'https://prep.login.optimizely.com/oauth2/default';
22
+ /**
23
+ * Prod Base URL for Optimizely OAuth2 endpoints
24
+ */
25
+ const PROD_BASE_URL = 'https://login.optimizely.com/oauth2/default';
26
+ class TokenVerifier {
27
+ static instance = null;
28
+ jwksUri;
29
+ issuer;
30
+ jwks;
31
+ initialized = false;
32
+ /**
33
+ * Verify the provided Optimizely JWT token string
34
+ * @param token JWT token string to verify
35
+ * @returns boolean true if verification successful, false otherwise
36
+ * @throws Error if token is null, empty, or verifier is not properly configured
37
+ */
38
+ async verify(token) {
39
+ if (!token || token.trim().length === 0) {
40
+ throw new Error('Token cannot be null or empty');
41
+ }
42
+ return this.verifyToken(token);
43
+ }
44
+ static getInstance() {
45
+ if (!TokenVerifier.instance) {
46
+ TokenVerifier.instance = new TokenVerifier();
47
+ }
48
+ return TokenVerifier.instance;
49
+ }
50
+ /**
51
+ * Get singleton instance of TokenVerifier and ensure it's initialized
52
+ * @returns Promise<TokenVerifier> - initialized singleton instance
53
+ */
54
+ static async getInitializedInstance() {
55
+ const instance = TokenVerifier.getInstance();
56
+ if (!instance.initialized) {
57
+ await instance.initialize();
58
+ }
59
+ return instance;
60
+ }
61
+ /**
62
+ * Initialize the TokenVerifier with discovery document from well-known endpoint
63
+ */
64
+ async initialize() {
65
+ if (this.initialized) {
66
+ return;
67
+ }
68
+ try {
69
+ // Use prep URL when environment variable is set to 'staging', otherwise use prod
70
+ const environment = process.env.environment || 'production';
71
+ const baseUrl = environment === 'staging' ? PREP_BASE_URL : PROD_BASE_URL;
72
+ const discoveryDocument = await this.fetchDiscoveryDocument(baseUrl);
73
+ this.issuer = discoveryDocument.issuer;
74
+ this.jwksUri = discoveryDocument.jwks_uri;
75
+ this.jwks = (0, jose_1.createRemoteJWKSet)(new URL(this.jwksUri), {
76
+ cacheMaxAge: DEFAULT_JWKS_EXPIRES_IN,
77
+ cooldownDuration: DEFAULT_JWKS_EXPIRES_IN
78
+ });
79
+ this.initialized = true;
80
+ app_sdk_1.logger.info(`TokenVerifier initialized with issuer: ${this.issuer} (environment: ${environment})`);
81
+ }
82
+ catch (error) {
83
+ app_sdk_1.logger.error('Failed to initialize TokenVerifier', error);
84
+ // Re-throw the original error to preserve specific error messages for tests
85
+ throw error;
86
+ }
87
+ }
88
+ /**
89
+ * Fetch discovery document from well-known endpoint
90
+ */
91
+ async fetchDiscoveryDocument(baseUrl) {
92
+ const wellKnownUrl = `${baseUrl}/.well-known/oauth-authorization-server`;
93
+ const response = await fetch(wellKnownUrl);
94
+ if (!response.ok) {
95
+ throw new Error(`Failed to fetch discovery document: ${response.status} ${response.statusText}`);
96
+ }
97
+ const discoveryDocument = await response.json();
98
+ if (!discoveryDocument.issuer || !discoveryDocument.jwks_uri) {
99
+ throw new Error('Invalid discovery document: missing issuer or jwks_uri');
100
+ }
101
+ return discoveryDocument;
102
+ }
103
+ async verifyToken(token) {
104
+ if (!this.initialized) {
105
+ throw new Error('TokenVerifier not initialized. Call initialize() first.');
106
+ }
107
+ if (!this.jwks || !this.issuer) {
108
+ throw new Error('TokenVerifier not properly configured.');
109
+ }
110
+ try {
111
+ await (0, jose_1.jwtVerify)(token, this.jwks, {
112
+ issuer: this.issuer,
113
+ audience: AUDIENCE,
114
+ clockTolerance: DEFAULT_LEEWAY,
115
+ });
116
+ return true;
117
+ }
118
+ catch (error) {
119
+ app_sdk_1.logger.error('Token verification failed:', error);
120
+ return false;
121
+ }
122
+ }
123
+ }
124
+ exports.TokenVerifier = TokenVerifier;
125
+ const getTokenVerifier = async () => TokenVerifier.getInitializedInstance();
126
+ exports.getTokenVerifier = getTokenVerifier;
127
+ //# sourceMappingURL=TokenVerifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenVerifier.js","sourceRoot":"","sources":["../../src/auth/TokenVerifier.ts"],"names":[],"mappings":";;;AAAA,+BAAqD;AACrD,+CAA2C;AAE3C;;GAEG;AACH,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE/C;;GAEG;AACH,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B;;GAEG;AACH,MAAM,QAAQ,GAAG,eAAe,CAAC;AAEjC;;GAEG;AACH,MAAM,aAAa,GAAG,kDAAkD,CAAC;AAEzE;;GAEG;AACH,MAAM,aAAa,GAAG,6CAA6C,CAAC;AAQpE,MAAa,aAAa;IAChB,MAAM,CAAC,QAAQ,GAAyB,IAAI,CAAC;IAC7C,OAAO,CAAU;IACjB,MAAM,CAAU;IAChB,IAAI,CAAyC;IAC7C,WAAW,GAAY,KAAK,CAAC;IAErC;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAAC,KAAyB;QAC3C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAEO,MAAM,CAAC,WAAW;QACxB,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC5B,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO,aAAa,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,KAAK,CAAC,sBAAsB;QACxC,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC1B,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC9B,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,iFAAiF;YACjF,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,YAAY,CAAC;YAC5D,MAAM,OAAO,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;YAC1E,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC;YACvC,IAAI,CAAC,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC;YAC1C,IAAI,CAAC,IAAI,GAAG,IAAA,yBAAkB,EAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;gBACpD,WAAW,EAAE,uBAAuB;gBACpC,gBAAgB,EAAE,uBAAuB;aAC1C,CAAC,CAAC;YACH,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,gBAAM,CAAC,IAAI,CAAC,0CAA0C,IAAI,CAAC,MAAM,kBAAkB,WAAW,GAAG,CAAC,CAAC;QACrG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gBAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC1D,4EAA4E;YAC5E,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,sBAAsB,CAAC,OAAe;QAClD,MAAM,YAAY,GAAG,GAAG,OAAO,yCAAyC,CAAC;QAEzE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACnG,CAAC;QACD,MAAM,iBAAiB,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAuB,CAAC;QACrE,IAAI,CAAC,iBAAiB,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,KAAa;QACrC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAA,gBAAS,EAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE;gBAChC,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,QAAQ;gBAClB,cAAc,EAAE,cAAc;aAC/B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gBAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;YAClD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;;AA1GH,sCA4GC;AAEM,MAAM,gBAAgB,GAAG,KAAK,IAA4B,EAAE,CAAC,aAAa,CAAC,sBAAsB,EAAE,CAAC;AAA9F,QAAA,gBAAgB,oBAA8E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=TokenVerifier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenVerifier.test.d.ts","sourceRoot":"","sources":["../../src/auth/TokenVerifier.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const TokenVerifier_1 = require("./TokenVerifier");
4
+ // Test constants
5
+ const TEST_ISSUER = 'https://prep.login.optimizely.com/oauth2/default';
6
+ const TEST_JWKS_URI = 'https://prep.login.optimizely.com/oauth2/v1/keys';
7
+ // Mock fetch globally
8
+ global.fetch = jest.fn();
9
+ describe('TokenVerifier', () => {
10
+ beforeEach(() => {
11
+ // Reset fetch mock
12
+ global.fetch.mockReset();
13
+ // Reset singleton instance for each test
14
+ TokenVerifier_1.TokenVerifier.instance = null;
15
+ });
16
+ describe('getInitializedInstance', () => {
17
+ it('should initialize successfully', async () => {
18
+ // Mock fetch for OAuth2 authorization server discovery
19
+ global.fetch.mockResolvedValue({
20
+ ok: true,
21
+ json: jest.fn().mockResolvedValue({
22
+ issuer: TEST_ISSUER,
23
+ jwks_uri: TEST_JWKS_URI
24
+ })
25
+ });
26
+ const tokenVerifier = await TokenVerifier_1.TokenVerifier.getInitializedInstance();
27
+ expect(tokenVerifier).toBeInstanceOf(TokenVerifier_1.TokenVerifier);
28
+ });
29
+ it('should throw error when discovery document is invalid', async () => {
30
+ global.fetch.mockResolvedValue({
31
+ ok: true,
32
+ json: jest.fn().mockResolvedValue({
33
+ // Missing issuer and jwks_uri
34
+ })
35
+ });
36
+ await expect(TokenVerifier_1.TokenVerifier.getInitializedInstance()).rejects.toThrow('Invalid discovery document: missing issuer or jwks_uri');
37
+ });
38
+ it('should throw error when discovery endpoint is unreachable', async () => {
39
+ global.fetch.mockResolvedValue({
40
+ ok: false,
41
+ status: 404,
42
+ statusText: 'Not Found'
43
+ });
44
+ await expect(TokenVerifier_1.TokenVerifier.getInitializedInstance()).rejects.toThrow('Failed to fetch discovery document: 404 Not Found');
45
+ });
46
+ });
47
+ describe('token verification', () => {
48
+ let tokenVerifier;
49
+ beforeEach(async () => {
50
+ // Mock successful initialization
51
+ global.fetch.mockResolvedValue({
52
+ ok: true,
53
+ json: jest.fn().mockResolvedValue({
54
+ issuer: TEST_ISSUER,
55
+ jwks_uri: TEST_JWKS_URI
56
+ })
57
+ });
58
+ tokenVerifier = await TokenVerifier_1.TokenVerifier.getInitializedInstance();
59
+ });
60
+ it('should throw error for empty token', async () => {
61
+ await expect(tokenVerifier.verify('')).rejects.toThrow('Token cannot be null or empty');
62
+ });
63
+ it('should throw error for undefined token', async () => {
64
+ await expect(tokenVerifier.verify(undefined)).rejects.toThrow('Token cannot be null or empty');
65
+ });
66
+ it('should throw error for whitespace-only token', async () => {
67
+ await expect(tokenVerifier.verify(' ')).rejects.toThrow('Token cannot be null or empty');
68
+ });
69
+ it('should return false for invalid token format', async () => {
70
+ const result = await tokenVerifier.verify('invalid.jwt.token');
71
+ expect(result).toBe(false);
72
+ });
73
+ });
74
+ describe('singleton pattern', () => {
75
+ it('should return same instance when called multiple times', async () => {
76
+ // Mock successful initialization
77
+ global.fetch.mockResolvedValue({
78
+ ok: true,
79
+ json: jest.fn().mockResolvedValue({
80
+ issuer: TEST_ISSUER,
81
+ jwks_uri: TEST_JWKS_URI
82
+ })
83
+ });
84
+ const instance1 = await TokenVerifier_1.TokenVerifier.getInitializedInstance();
85
+ const instance2 = await TokenVerifier_1.TokenVerifier.getInitializedInstance();
86
+ expect(instance1).toBe(instance2);
87
+ });
88
+ it('should call correct prod OAuth2 authorization server discovery URL', async () => {
89
+ const fetchSpy = jest.spyOn(global, 'fetch').mockResolvedValue({
90
+ ok: true,
91
+ json: jest.fn().mockResolvedValue({
92
+ issuer: TEST_ISSUER,
93
+ jwks_uri: TEST_JWKS_URI
94
+ })
95
+ });
96
+ await TokenVerifier_1.TokenVerifier.getInitializedInstance();
97
+ expect(fetchSpy).toHaveBeenCalledWith('https://login.optimizely.com/oauth2/default/.well-known/oauth-authorization-server');
98
+ });
99
+ it('should call correct prep OAuth2 authorization server discovery URL', async () => {
100
+ // Set environment variable to staging
101
+ process.env.environment = 'staging';
102
+ const fetchSpy = jest.spyOn(global, 'fetch').mockResolvedValue({
103
+ ok: true,
104
+ json: jest.fn().mockResolvedValue({
105
+ issuer: TEST_ISSUER,
106
+ jwks_uri: TEST_JWKS_URI
107
+ })
108
+ });
109
+ await TokenVerifier_1.TokenVerifier.getInitializedInstance();
110
+ expect(fetchSpy).toHaveBeenCalledWith('https://prep.login.optimizely.com/oauth2/default/.well-known/oauth-authorization-server');
111
+ });
112
+ });
113
+ });
114
+ //# sourceMappingURL=TokenVerifier.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenVerifier.test.js","sourceRoot":"","sources":["../../src/auth/TokenVerifier.test.ts"],"names":[],"mappings":"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"}
@@ -36,11 +36,13 @@ export interface InteractionConfig {
36
36
  /**
37
37
  * Decorator for registering tool functions
38
38
  * Immediately registers the tool with the global ToolsService
39
+ * The handler will have access to 'this' context when called
39
40
  */
40
- export declare function tool(config: ToolConfig): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
41
+ export declare function tool(config: ToolConfig): (target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
41
42
  /**
42
43
  * Decorator for registering interaction functions
43
44
  * Immediately registers the interaction with the global ToolsService
45
+ * The handler will have access to 'this' context when called
44
46
  */
45
- export declare function interaction(config: InteractionConfig): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
47
+ export declare function interaction(config: InteractionConfig): (target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
46
48
  //# sourceMappingURL=Decorator.d.ts.map
@@ -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,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;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,IACrB,SAAS,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAqBnF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,IACnC,SAAS,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAQnF"}
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"}
@@ -7,25 +7,47 @@ const Service_1 = require("../service/Service");
7
7
  /**
8
8
  * Decorator for registering tool functions
9
9
  * Immediately registers the tool with the global ToolsService
10
+ * The handler will have access to 'this' context when called
10
11
  */
11
12
  function tool(config) {
12
- return function (_target, _propertyKey, descriptor) {
13
+ return function (target, _propertyKey, descriptor) {
13
14
  // Convert parameter configs to Parameter instances
14
15
  const parameters = (config.parameters || []).map((p) => new Models_1.Parameter(p.name, p.type, p.description, p.required));
15
16
  // Convert auth requirement configs to AuthRequirement instances
16
17
  const authRequirements = (config.authRequirements || []).map((a) => new Models_1.AuthRequirement(a.provider, a.scopeBundle, a.required));
18
+ const originalMethod = descriptor.value;
19
+ const boundHandler = function (functionContext, params, authData) {
20
+ // Check if we're being called from within a ToolFunction instance context
21
+ // If so, use that instance; otherwise create a new one
22
+ const instance = (functionContext && functionContext instanceof target.constructor) ?
23
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
24
+ functionContext : new target.constructor();
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
26
+ return originalMethod.call(instance, params, authData);
27
+ };
17
28
  // Immediately register with global ToolsService
18
- Service_1.toolsService.registerTool(config.name, config.description, descriptor.value, parameters, config.endpoint, authRequirements);
29
+ Service_1.toolsService.registerTool(config.name, config.description, boundHandler, parameters, config.endpoint, authRequirements);
19
30
  };
20
31
  }
21
32
  /**
22
33
  * Decorator for registering interaction functions
23
34
  * Immediately registers the interaction with the global ToolsService
35
+ * The handler will have access to 'this' context when called
24
36
  */
25
37
  function interaction(config) {
26
- return function (_target, _propertyKey, descriptor) {
38
+ return function (target, _propertyKey, descriptor) {
39
+ const originalMethod = descriptor.value;
40
+ const boundHandler = function (functionContext, data, authData) {
41
+ // Check if we're being called from within a ToolFunction instance context
42
+ // If so, use that instance; otherwise create a new one
43
+ const instance = (functionContext && functionContext instanceof target.constructor) ?
44
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
45
+ functionContext : new target.constructor();
46
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
47
+ return originalMethod.call(instance, data, authData);
48
+ };
27
49
  // Immediately register with global ToolsService
28
- Service_1.toolsService.registerInteraction(config.name, descriptor.value, config.endpoint);
50
+ Service_1.toolsService.registerInteraction(config.name, boundHandler, config.endpoint);
29
51
  };
30
52
  }
31
53
  //# sourceMappingURL=Decorator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Decorator.js","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":";;AA6CA,oBAsBC;AAMD,kCASC;AAlFD,4CAA4E;AAC5E,gDAAkD;AAwClD;;;GAGG;AACH,SAAgB,IAAI,CAAC,MAAkB;IACrC,OAAO,UAAS,OAAY,EAAE,YAAoB,EAAE,UAA8B;QAChF,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,gDAAgD;QAChD,sBAAY,CAAC,YAAY,CACvB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,WAAW,EAClB,UAAU,CAAC,KAAK,EAChB,UAAU,EACV,MAAM,CAAC,QAAQ,EACf,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,MAAyB;IACnD,OAAO,UAAS,OAAY,EAAE,YAAoB,EAAE,UAA8B;QAChF,gDAAgD;QAChD,sBAAY,CAAC,mBAAmB,CAC9B,MAAM,CAAC,IAAI,EACX,UAAU,CAAC,KAAK,EAChB,MAAM,CAAC,QAAQ,CAChB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
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"}