@ioka-technologies/asyncapi-ts-client-template 0.0.8 → 0.0.11

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.
@@ -0,0 +1,95 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="headers.ts">
7
+ {`import { AuthCredentials, AuthError } from './types';
8
+
9
+ /**
10
+ * Generate authentication headers based on credentials
11
+ */
12
+ export function generateAuthHeaders(auth: AuthCredentials): Record<string, string> {
13
+ const headers: Record<string, string> = {};
14
+
15
+ if (auth.jwt) {
16
+ headers['Authorization'] = \`Bearer \${auth.jwt}\`;
17
+ } else if (auth.basic) {
18
+ const credentials = btoa(\`\${auth.basic.username}:\${auth.basic.password}\`);
19
+ headers['Authorization'] = \`Basic \${credentials}\`;
20
+ } else if (auth.apikey) {
21
+ if (auth.apikey.location === 'header') {
22
+ headers[auth.apikey.name] = auth.apikey.key;
23
+ }
24
+ // Query parameters are handled in the transport layer
25
+ }
26
+
27
+ return headers;
28
+ }
29
+
30
+ /**
31
+ * Generate query parameters for API key authentication
32
+ */
33
+ export function generateAuthQueryParams(auth: AuthCredentials): Record<string, string> {
34
+ const params: Record<string, string> = {};
35
+
36
+ if (auth.apikey && auth.apikey.location === 'query') {
37
+ params[auth.apikey.name] = auth.apikey.key;
38
+ }
39
+
40
+ return params;
41
+ }
42
+
43
+ /**
44
+ * Validate auth credentials
45
+ */
46
+ export function validateAuthCredentials(auth: AuthCredentials): void {
47
+ if (auth.jwt) {
48
+ if (typeof auth.jwt !== 'string' || auth.jwt.trim() === '') {
49
+ throw new AuthError('JWT token must be a non-empty string', 'jwt');
50
+ }
51
+ }
52
+
53
+ if (auth.basic) {
54
+ if (!auth.basic.username || !auth.basic.password) {
55
+ throw new AuthError('Basic auth requires both username and password', 'basic');
56
+ }
57
+ if (typeof auth.basic.username !== 'string' || typeof auth.basic.password !== 'string') {
58
+ throw new AuthError('Basic auth username and password must be strings', 'basic');
59
+ }
60
+ }
61
+
62
+ if (auth.apikey) {
63
+ if (!auth.apikey.key || !auth.apikey.name) {
64
+ throw new AuthError('API key auth requires both key and name', 'apikey');
65
+ }
66
+ if (typeof auth.apikey.key !== 'string' || typeof auth.apikey.name !== 'string') {
67
+ throw new AuthError('API key and name must be strings', 'apikey');
68
+ }
69
+ if (!['header', 'query'].includes(auth.apikey.location)) {
70
+ throw new AuthError('API key location must be either "header" or "query"', 'apikey');
71
+ }
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check if auth credentials are provided
77
+ */
78
+ export function hasAuthCredentials(auth?: AuthCredentials): boolean {
79
+ if (!auth) return false;
80
+ return !!(auth.jwt || auth.basic || auth.apikey);
81
+ }
82
+
83
+ /**
84
+ * Get auth type from credentials
85
+ */
86
+ export function getAuthType(auth: AuthCredentials): string | null {
87
+ if (auth.jwt) return 'jwt';
88
+ if (auth.basic) return 'basic';
89
+ if (auth.apikey) return 'apikey';
90
+ return null;
91
+ }
92
+ `}
93
+ </File>
94
+ );
95
+ };
@@ -0,0 +1,15 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="index.ts">
7
+ {`// Auth types and interfaces
8
+ export * from './types';
9
+
10
+ // Auth header utilities
11
+ export * from './headers';
12
+ `}
13
+ </File>
14
+ );
15
+ };
@@ -0,0 +1,74 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="types.ts">
7
+ {`/**
8
+ * Authentication credentials for different auth types
9
+ */
10
+ export interface AuthCredentials {
11
+ /** JWT Bearer token */
12
+ jwt?: string;
13
+
14
+ /** Basic authentication credentials */
15
+ basic?: {
16
+ username: string;
17
+ password: string;
18
+ };
19
+
20
+ /** API Key authentication */
21
+ apikey?: {
22
+ key: string;
23
+ location: 'header' | 'query';
24
+ name: string;
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Auth-related error types
30
+ */
31
+ export class AuthError extends Error {
32
+ constructor(message: string, public authType?: string) {
33
+ super(message);
34
+ this.name = 'AuthError';
35
+ }
36
+ }
37
+
38
+ export class TokenExpiredError extends AuthError {
39
+ constructor(message: string = 'Token has expired') {
40
+ super(message, 'jwt');
41
+ this.name = 'TokenExpiredError';
42
+ }
43
+ }
44
+
45
+ export class UnauthorizedError extends AuthError {
46
+ constructor(message: string = 'Unauthorized access') {
47
+ super(message);
48
+ this.name = 'UnauthorizedError';
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Auth event callbacks for monitoring and token refresh
54
+ */
55
+ export interface AuthEventCallbacks {
56
+ /** Called when a 401 Unauthorized response is received */
57
+ onAuthError?: () => Promise<boolean>;
58
+
59
+ /** Called when token needs to be refreshed */
60
+ onTokenRefresh?: (oldToken: string) => Promise<string>;
61
+ }
62
+
63
+ /**
64
+ * Security requirement analysis result
65
+ */
66
+ export interface SecurityRequirement {
67
+ hasSecurityRequirements: boolean;
68
+ securitySchemes: any[];
69
+ requiresAuthentication: boolean;
70
+ }
71
+ `}
72
+ </File>
73
+ );
74
+ };
@@ -0,0 +1,18 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="index.ts">
7
+ {`// Retry types and interfaces
8
+ export * from './types';
9
+
10
+ // Retry presets
11
+ export * from './presets';
12
+
13
+ // Retry manager
14
+ export * from './manager';
15
+ `}
16
+ </File>
17
+ );
18
+ };
@@ -0,0 +1,150 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="manager.ts">
7
+ {`import { RetryConfig, RetryEventCallbacks, MaxRetriesExceededError } from './types';
8
+ import { getRetryConfig } from './presets';
9
+
10
+ /**
11
+ * Retry manager for handling exponential backoff and retry logic
12
+ */
13
+ export class RetryManager {
14
+ private config: RetryConfig;
15
+ private callbacks?: RetryEventCallbacks;
16
+
17
+ constructor(config: RetryConfig, callbacks?: RetryEventCallbacks) {
18
+ this.config = config;
19
+ this.callbacks = callbacks;
20
+ }
21
+
22
+ /**
23
+ * Execute an operation with retry logic
24
+ */
25
+ async executeWithRetry<T>(
26
+ operation: () => Promise<T>,
27
+ operationName: string
28
+ ): Promise<T> {
29
+ if (!this.config.enabled) {
30
+ return operation();
31
+ }
32
+
33
+ let lastError: Error;
34
+
35
+ for (let attempt = 1; attempt <= this.config.maxAttempts; attempt++) {
36
+ try {
37
+ return await operation();
38
+ } catch (error) {
39
+ lastError = error as Error;
40
+
41
+ // Check if error is retryable
42
+ if (!this.isRetryable(error) || attempt === this.config.maxAttempts) {
43
+ if (attempt === this.config.maxAttempts && this.callbacks?.onRetryExhausted) {
44
+ this.callbacks.onRetryExhausted(operationName, lastError);
45
+ }
46
+ throw error;
47
+ }
48
+
49
+ // Calculate delay with exponential backoff and jitter
50
+ const delay = this.calculateDelay(attempt);
51
+
52
+ // Call retry callback
53
+ if (this.callbacks?.onRetry) {
54
+ this.callbacks.onRetry(attempt, lastError, delay);
55
+ }
56
+
57
+ // Wait before retrying
58
+ await this.sleep(delay);
59
+ }
60
+ }
61
+
62
+ // This should never be reached, but TypeScript requires it
63
+ throw new MaxRetriesExceededError(this.config.maxAttempts, lastError!);
64
+ }
65
+
66
+ /**
67
+ * Check if an error is retryable based on configuration
68
+ */
69
+ private isRetryable(error: any): boolean {
70
+ // Check HTTP status codes
71
+ if (error.status && this.config.retryableStatusCodes.includes(error.status)) {
72
+ return true;
73
+ }
74
+
75
+ // Check error codes
76
+ if (error.code && this.config.retryableErrors.includes(error.code)) {
77
+ return true;
78
+ }
79
+
80
+ // Check error names
81
+ if (error.name && this.config.retryableErrors.includes(error.name)) {
82
+ return true;
83
+ }
84
+
85
+ // Check error messages for common network errors
86
+ if (error.message) {
87
+ const message = error.message.toLowerCase();
88
+ for (const retryableError of this.config.retryableErrors) {
89
+ if (message.includes(retryableError.toLowerCase())) {
90
+ return true;
91
+ }
92
+ }
93
+ }
94
+
95
+ return false;
96
+ }
97
+
98
+ /**
99
+ * Calculate delay with exponential backoff and optional jitter
100
+ */
101
+ private calculateDelay(attempt: number): number {
102
+ let delay = this.config.baseDelay * Math.pow(this.config.backoffMultiplier, attempt - 1);
103
+
104
+ // Apply maximum delay cap
105
+ delay = Math.min(delay, this.config.maxDelay);
106
+
107
+ // Add jitter to prevent thundering herd
108
+ if (this.config.jitter) {
109
+ delay = delay * (0.5 + Math.random() * 0.5);
110
+ }
111
+
112
+ return Math.floor(delay);
113
+ }
114
+
115
+ /**
116
+ * Sleep for specified milliseconds
117
+ */
118
+ private sleep(ms: number): Promise<void> {
119
+ return new Promise(resolve => setTimeout(resolve, ms));
120
+ }
121
+
122
+ /**
123
+ * Get current retry configuration
124
+ */
125
+ getConfig(): RetryConfig {
126
+ return { ...this.config };
127
+ }
128
+
129
+ /**
130
+ * Update retry configuration
131
+ */
132
+ updateConfig(config: Partial<RetryConfig>): void {
133
+ this.config = { ...this.config, ...config };
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Create a retry manager from config or preset
139
+ */
140
+ export function createRetryManager(
141
+ config: RetryConfig | string,
142
+ callbacks?: RetryEventCallbacks
143
+ ): RetryManager {
144
+ const retryConfig = getRetryConfig(config as any);
145
+ return new RetryManager(retryConfig, callbacks);
146
+ }
147
+ `}
148
+ </File>
149
+ );
150
+ };
@@ -0,0 +1,81 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="presets.ts">
7
+ {`import { RetryConfig, RetryPreset } from './types';
8
+
9
+ /**
10
+ * Predefined retry configuration presets
11
+ */
12
+ export const RETRY_PRESETS: Record<RetryPreset, RetryConfig> = {
13
+ none: {
14
+ enabled: false,
15
+ maxAttempts: 1,
16
+ baseDelay: 0,
17
+ maxDelay: 0,
18
+ backoffMultiplier: 1,
19
+ jitter: false,
20
+ retryableStatusCodes: [],
21
+ retryableErrors: []
22
+ },
23
+
24
+ conservative: {
25
+ enabled: true,
26
+ maxAttempts: 3,
27
+ baseDelay: 1000, // 1 second
28
+ maxDelay: 10000, // 10 seconds max
29
+ backoffMultiplier: 2,
30
+ jitter: true,
31
+ retryableStatusCodes: [500, 502, 503, 504],
32
+ retryableErrors: ['NETWORK_ERROR', 'TIMEOUT', 'ECONNRESET', 'ENOTFOUND']
33
+ },
34
+
35
+ balanced: {
36
+ enabled: true,
37
+ maxAttempts: 5,
38
+ baseDelay: 500, // 500ms
39
+ maxDelay: 30000, // 30 seconds max
40
+ backoffMultiplier: 2,
41
+ jitter: true,
42
+ retryableStatusCodes: [429, 500, 502, 503, 504],
43
+ retryableErrors: ['NETWORK_ERROR', 'TIMEOUT', 'CONNECTION_ERROR', 'ECONNRESET', 'ENOTFOUND', 'ETIMEDOUT']
44
+ },
45
+
46
+ aggressive: {
47
+ enabled: true,
48
+ maxAttempts: 10,
49
+ baseDelay: 100, // 100ms
50
+ maxDelay: 60000, // 1 minute max
51
+ backoffMultiplier: 1.5,
52
+ jitter: true,
53
+ retryableStatusCodes: [408, 429, 500, 502, 503, 504],
54
+ retryableErrors: ['NETWORK_ERROR', 'TIMEOUT', 'CONNECTION_ERROR', 'DNS_ERROR', 'ECONNRESET', 'ENOTFOUND', 'ETIMEDOUT', 'ECONNREFUSED']
55
+ }
56
+ };
57
+
58
+ /**
59
+ * Get retry configuration from preset or return custom config
60
+ */
61
+ export function getRetryConfig(config: RetryConfig | RetryPreset): RetryConfig {
62
+ if (typeof config === 'string') {
63
+ return RETRY_PRESETS[config];
64
+ }
65
+ return config;
66
+ }
67
+
68
+ /**
69
+ * Merge custom retry config with preset defaults
70
+ */
71
+ export function mergeRetryConfig(preset: RetryPreset, overrides: Partial<RetryConfig>): RetryConfig {
72
+ const baseConfig = RETRY_PRESETS[preset];
73
+ return {
74
+ ...baseConfig,
75
+ ...overrides
76
+ };
77
+ }
78
+ `}
79
+ </File>
80
+ );
81
+ };
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { File } from '@asyncapi/generator-react-sdk';
3
+
4
+ module.exports = function ({ asyncapi, params }) {
5
+ return (
6
+ <File name="types.ts">
7
+ {`/**
8
+ * Retry configuration interface
9
+ */
10
+ export interface RetryConfig {
11
+ enabled: boolean;
12
+ maxAttempts: number;
13
+ baseDelay: number; // Initial delay in ms
14
+ maxDelay: number; // Maximum delay in ms
15
+ backoffMultiplier: number; // Exponential backoff multiplier
16
+ jitter: boolean; // Add randomization to prevent thundering herd
17
+ retryableStatusCodes: number[]; // Which HTTP status codes to retry
18
+ retryableErrors: string[]; // Which error types to retry
19
+ }
20
+
21
+ /**
22
+ * Preset retry configurations
23
+ */
24
+ export type RetryPreset = 'aggressive' | 'balanced' | 'conservative' | 'none';
25
+
26
+ /**
27
+ * Retry event callbacks for monitoring
28
+ */
29
+ export interface RetryEventCallbacks {
30
+ /** Called before each retry attempt */
31
+ onRetry?: (attempt: number, error: Error, delay: number) => void;
32
+
33
+ /** Called when all retry attempts are exhausted */
34
+ onRetryExhausted?: (operation: string, finalError: Error) => void;
35
+ }
36
+
37
+ /**
38
+ * Retry-related error types
39
+ */
40
+ export class RetryError extends Error {
41
+ constructor(
42
+ message: string,
43
+ public attempts: number,
44
+ public lastError: Error
45
+ ) {
46
+ super(message);
47
+ this.name = 'RetryError';
48
+ }
49
+ }
50
+
51
+ export class MaxRetriesExceededError extends RetryError {
52
+ constructor(attempts: number, lastError: Error) {
53
+ super(\`Maximum retry attempts (\${attempts}) exceeded\`, attempts, lastError);
54
+ this.name = 'MaxRetriesExceededError';
55
+ }
56
+ }
57
+ `}
58
+ </File>
59
+ );
60
+ };
@@ -12,14 +12,22 @@ module.exports = function ({ asyncapi, params }) {
12
12
  <File name="http.ts">
13
13
  {`import { Transport, TransportConfig, RequestOptions, MessageEnvelope } from '../types';
14
14
  import { TransportError, ConnectionError, TimeoutError } from '../errors';
15
+ import { generateAuthHeaders, generateAuthQueryParams, hasAuthCredentials, AuthError, UnauthorizedError, AuthCredentials } from '../auth';
16
+ import { createRetryManager, getRetryConfig } from '../retry';
15
17
 
16
18
  export class HttpTransport implements Transport {
17
19
  private config: TransportConfig;
18
20
  private baseUrl: string;
21
+ private retryManager: any;
19
22
 
20
23
  constructor(config: TransportConfig) {
21
24
  this.config = config;
22
25
  this.baseUrl = config.url;
26
+
27
+ // Initialize retry manager if retry config is provided
28
+ if (config.retry) {
29
+ this.retryManager = createRetryManager(config.retry, config.retryCallbacks);
30
+ }
23
31
  }
24
32
 
25
33
  async connect(): Promise<void> {
@@ -33,46 +41,114 @@ export class HttpTransport implements Transport {
33
41
  }
34
42
 
35
43
  async send(channel: string, envelope: MessageEnvelope, options?: RequestOptions): Promise<any> {
36
- const url = \`\${this.baseUrl}/\${channel}\`;
37
- const timeout = options?.timeout || 30000;
44
+ // Determine retry configuration (options override config)
45
+ const retryConfig = options?.retry ? getRetryConfig(options.retry) :
46
+ this.config.retry ? getRetryConfig(this.config.retry) : null;
47
+
48
+ const retryManager = retryConfig ? createRetryManager(retryConfig, this.config.retryCallbacks) : null;
49
+
50
+ const sendOperation = async () => {
51
+ return this.performHttpRequest(channel, envelope, options);
52
+ };
53
+
54
+ // Execute with retry if configured
55
+ if (retryManager) {
56
+ return retryManager.executeWithRetry(sendOperation, \`\${envelope.operation} on \${channel}\`);
57
+ } else {
58
+ return sendOperation();
59
+ }
60
+ }
61
+
62
+ private async performHttpRequest(channel: string, envelope: MessageEnvelope, options?: RequestOptions): Promise<any> {
63
+ let url = \`\${this.baseUrl}/\${channel}\`;
64
+ const timeout = options?.timeout || this.config.timeout || 30000;
65
+
66
+ // Generate auth headers if credentials are available
67
+ const authHeaders = this.config.auth ? generateAuthHeaders(this.config.auth) : {};
38
68
 
39
69
  // Prepare the complete envelope for HTTP transport
40
70
  const messageEnvelope: MessageEnvelope = {
41
71
  ...envelope,
42
72
  channel: envelope.channel || channel,
43
73
  timestamp: envelope.timestamp || new Date().toISOString(),
44
- id: options?.correlationId || envelope.id
74
+ id: options?.correlationId || envelope.id || this.generateCorrelationId(),
75
+ headers: {
76
+ ...envelope.headers,
77
+ ...authHeaders
78
+ }
79
+ };
80
+
81
+ // Prepare headers
82
+ const headers: Record<string, string> = {
83
+ 'Content-Type': 'application/json',
84
+ 'X-Operation': envelope.operation,
85
+ 'X-Correlation-ID': messageEnvelope.id || '',
86
+ ...this.config.headers
45
87
  };
46
88
 
89
+ // Add auth headers if auth is configured
90
+ if (this.config.auth && hasAuthCredentials(this.config.auth)) {
91
+ try {
92
+ const authHeaders = generateAuthHeaders(this.config.auth);
93
+ Object.assign(headers, authHeaders);
94
+ } catch (error) {
95
+ const errorMessage = error instanceof Error ? error.message : String(error);
96
+ throw new AuthError(\`Failed to generate auth headers: \${errorMessage}\`);
97
+ }
98
+ }
99
+
100
+ // Add auth query parameters if needed
101
+ if (this.config.auth?.apikey?.location === 'query') {
102
+ const authParams = generateAuthQueryParams(this.config.auth);
103
+ const urlObj = new URL(url);
104
+ Object.entries(authParams).forEach(([key, value]) => {
105
+ urlObj.searchParams.set(key, value);
106
+ });
107
+ url = urlObj.toString();
108
+ }
109
+
47
110
  const controller = new AbortController();
48
111
  const timeoutId = setTimeout(() => controller.abort(), timeout);
49
112
 
50
113
  try {
51
114
  const response = await fetch(url, {
52
115
  method: 'POST',
53
- headers: {
54
- 'Content-Type': 'application/json',
55
- 'X-Operation': envelope.operation,
56
- 'X-Correlation-ID': messageEnvelope.id || '',
57
- ...this.config.headers
58
- },
116
+ headers,
59
117
  body: JSON.stringify(messageEnvelope),
60
118
  signal: controller.signal
61
119
  });
62
120
 
63
121
  clearTimeout(timeoutId);
64
122
 
123
+ // Handle auth errors specifically
124
+ if (response.status === 401) {
125
+ // Call auth error callback if available
126
+ if (this.config.authCallbacks?.onAuthError) {
127
+ const shouldRetry = await this.config.authCallbacks.onAuthError();
128
+ if (shouldRetry) {
129
+ // Retry the request with potentially updated auth
130
+ return this.performHttpRequest(channel, envelope, options);
131
+ }
132
+ }
133
+ throw new UnauthorizedError('Authentication failed');
134
+ }
135
+
65
136
  if (!response.ok) {
137
+ // Create error with status for retry logic
138
+ const error = new TransportError(\`HTTP request failed: \${response.status} \${response.statusText}\`);
139
+ (error as any).status = response.status;
140
+
66
141
  // Try to parse error response as envelope
67
142
  try {
68
143
  const errorEnvelope: MessageEnvelope = await response.json();
69
144
  if (errorEnvelope.error) {
70
- throw new TransportError(\`\${errorEnvelope.error.code}: \${errorEnvelope.error.message}\`);
145
+ error.message = \`\${errorEnvelope.error.code}: \${errorEnvelope.error.message}\`;
71
146
  }
72
147
  } catch {
73
- // Fall back to HTTP status error
74
- throw new TransportError(\`HTTP request failed: \${response.status} \${response.statusText}\`);
148
+ // Use the default error message
75
149
  }
150
+
151
+ throw error;
76
152
  }
77
153
 
78
154
  // Parse response as envelope
@@ -88,15 +164,34 @@ export class HttpTransport implements Transport {
88
164
  clearTimeout(timeoutId);
89
165
 
90
166
  if (error.name === 'AbortError') {
91
- throw new TimeoutError(\`Request timeout after \${timeout}ms\`);
167
+ const timeoutError = new TimeoutError(\`Request timeout after \${timeout}ms\`);
168
+ (timeoutError as any).code = 'TIMEOUT';
169
+ throw timeoutError;
92
170
  }
93
171
 
94
- // Re-throw TransportError as-is
95
- if (error instanceof TransportError) {
172
+ // Add error codes for retry logic
173
+ if (error instanceof TransportError || error instanceof AuthError) {
96
174
  throw error;
97
175
  }
98
176
 
99
- throw new TransportError(\`HTTP request failed: \${error.message}\`);
177
+ // Network errors
178
+ const networkError = new TransportError(\`HTTP request failed: \${error.message}\`);
179
+ (networkError as any).code = 'NETWORK_ERROR';
180
+ throw networkError;
181
+ }
182
+ }
183
+
184
+ private generateCorrelationId(): string {
185
+ return \`http-\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}\`;
186
+ }
187
+
188
+ /**
189
+ * Update authentication configuration
190
+ * @param auth New authentication configuration
191
+ */
192
+ updateAuth(auth: AuthCredentials): void {
193
+ if (this.config) {
194
+ this.config.auth = auth;
100
195
  }
101
196
  }
102
197
 
@@ -119,4 +214,4 @@ export class HttpTransport implements Transport {
119
214
  }`}
120
215
  </File>
121
216
  );
122
- }
217
+ };