@uipath/uipath-typescript 1.0.0 → 1.1.0

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.
@@ -3889,1333 +3889,1371 @@ function hasSecretConfig(config) {
3889
3889
  }
3890
3890
 
3891
3891
  /**
3892
- * TokenManager is responsible for managing authentication tokens.
3893
- * It provides token operations for a specific client ID.
3894
- * - For OAuth tokens: Uses session storage with client ID-based keys
3895
- * - For Secret tokens: Stores only in memory, allowing multiple instances
3892
+ * Base error class for all UiPath SDK errors
3893
+ * Extends Error for standard error handling compatibility
3896
3894
  */
3897
- class TokenManager {
3898
- /**
3899
- * Creates a new TokenManager instance
3900
- * @param executionContext The execution context
3901
- * @param config The SDK configuration
3902
- * @param isOAuth Whether this is an OAuth-based authentication
3903
- */
3904
- constructor(executionContext, config, isOAuth = false) {
3905
- this.executionContext = executionContext;
3906
- this.config = config;
3907
- this.isOAuth = isOAuth;
3908
- this.STORAGE_KEY_PREFIX = 'uipath_sdk_user_token-';
3909
- this.refreshPromise = null;
3910
- }
3911
- /**
3912
- * Checks if a token is expired
3913
- * @param tokenInfo The token info to check
3914
- * @returns true if the token is expired, false otherwise
3915
- */
3916
- isTokenExpired(tokenInfo) {
3917
- // If no token info or no expiration date, token is not expired
3918
- if (!tokenInfo?.expiresAt) {
3919
- return false;
3920
- }
3921
- return new Date() >= tokenInfo.expiresAt;
3922
- }
3923
- /**
3924
- * Gets the storage key for this TokenManager instance
3925
- */
3926
- _getStorageKey() {
3927
- return `${this.STORAGE_KEY_PREFIX}${this.config.clientId}`;
3928
- }
3929
- /**
3930
- * Loads token from session storage if available
3931
- * @returns true if a valid token was loaded, false otherwise
3932
- */
3933
- loadFromStorage() {
3934
- // Only OAuth tokens are stored in session storage
3935
- if (!isBrowser || !this.isOAuth) {
3936
- return false;
3937
- }
3938
- try {
3939
- const storedToken = sessionStorage.getItem(this._getStorageKey());
3940
- if (!storedToken) {
3941
- return false;
3942
- }
3943
- const tokenInfo = this._parseTokenInfo(storedToken);
3944
- if (!tokenInfo) {
3945
- // Invalid token format, clear it
3946
- sessionStorage.removeItem(this._getStorageKey());
3947
- return false;
3948
- }
3949
- // Check if token is expired
3950
- if (this.isTokenExpired(tokenInfo)) {
3951
- // Token expired, clear it
3952
- sessionStorage.removeItem(this._getStorageKey());
3953
- return false;
3954
- }
3955
- // Valid token found, use it
3956
- this.currentToken = tokenInfo;
3957
- this._updateExecutionContext(tokenInfo);
3958
- return true;
3959
- }
3960
- catch (error) {
3961
- console.warn('Failed to load token from session storage', error);
3962
- return false;
3963
- }
3964
- }
3965
- /**
3966
- * Parse and validate token info from storage
3967
- * @param storedToken JSON string from storage
3968
- * @returns Valid TokenInfo or undefined if invalid
3969
- */
3970
- _parseTokenInfo(storedToken) {
3971
- try {
3972
- const parsed = JSON.parse(storedToken);
3973
- // Basic validation
3974
- if (typeof parsed !== 'object' || !parsed) {
3975
- return undefined;
3976
- }
3977
- if (typeof parsed.token !== 'string' || !parsed.token) {
3978
- return undefined;
3979
- }
3980
- if (parsed.type !== 'secret' && parsed.type !== 'oauth') {
3981
- return undefined;
3982
- }
3983
- const tokenInfo = parsed;
3984
- // Convert string date back to Date object
3985
- if (tokenInfo.expiresAt) {
3986
- tokenInfo.expiresAt = new Date(tokenInfo.expiresAt);
3987
- // Verify it's a valid date
3988
- if (isNaN(tokenInfo.expiresAt.getTime())) {
3989
- return undefined;
3990
- }
3991
- }
3992
- return tokenInfo;
3993
- }
3994
- catch (error) {
3995
- console.warn('Failed to parse token info', error);
3996
- return undefined;
3997
- }
3998
- }
3999
- /**
4000
- * Sets a new token and updates all necessary contexts
4001
- */
4002
- setToken(tokenInfo) {
4003
- this.currentToken = tokenInfo;
4004
- // Store token in execution context
4005
- this._updateExecutionContext(tokenInfo);
4006
- // Store in session storage if in browser and this is an OAuth token
4007
- if (isBrowser && this.isOAuth) {
4008
- try {
4009
- sessionStorage.setItem(this._getStorageKey(), JSON.stringify(tokenInfo));
4010
- }
4011
- catch (error) {
4012
- console.warn('Failed to store token in session storage', error);
4013
- }
4014
- }
4015
- }
4016
- /**
4017
- * Gets the current token information
4018
- */
4019
- getTokenInfo() {
4020
- return this.currentToken;
4021
- }
4022
- /**
4023
- * Gets just the token string
4024
- */
4025
- getToken() {
4026
- return this.currentToken?.token;
4027
- }
4028
- /**
4029
- * Checks if we have a valid token
4030
- */
4031
- hasValidToken() {
4032
- if (!this.currentToken) {
4033
- return false;
4034
- }
4035
- if (this.isTokenExpired(this.currentToken)) {
4036
- return false;
4037
- }
4038
- return true;
4039
- }
4040
- /**
4041
- * Clears the current token
4042
- */
4043
- clearToken() {
4044
- this.currentToken = undefined;
4045
- this.executionContext.set('tokenInfo', undefined);
4046
- const headers = this.executionContext.getHeaders();
4047
- delete headers['Authorization'];
4048
- this.executionContext.setHeaders(headers);
4049
- // Remove from session storage if this is an OAuth token
4050
- if (isBrowser && this.isOAuth) {
4051
- try {
4052
- sessionStorage.removeItem(this._getStorageKey());
4053
- }
4054
- catch (error) {
4055
- console.warn('Failed to remove token from session storage', error);
4056
- }
3895
+ class UiPathError extends Error {
3896
+ constructor(type, params) {
3897
+ super(params.message);
3898
+ this.name = type;
3899
+ this.type = type;
3900
+ this.statusCode = params.statusCode;
3901
+ this.requestId = params.requestId;
3902
+ this.timestamp = new Date();
3903
+ // Maintains proper stack trace for where our error was thrown
3904
+ if (Error.captureStackTrace) {
3905
+ Error.captureStackTrace(this, this.constructor);
4057
3906
  }
4058
3907
  }
4059
3908
  /**
4060
- * Updates execution context with token information
4061
- */
4062
- _updateExecutionContext(tokenInfo) {
4063
- this.executionContext.set('tokenInfo', tokenInfo);
4064
- // Update authorization header
4065
- this.executionContext.setHeaders({
4066
- 'Authorization': `Bearer ${tokenInfo.token}`
4067
- });
4068
- }
4069
- /**
4070
- * Refreshes the access token using the stored refresh token.
4071
- * This method only works for OAuth flow.
4072
- * Uses a lock mechanism to prevent multiple simultaneous refreshes.
4073
- * @returns A promise that resolves to the new AuthToken
4074
- * @throws Error if not in OAuth flow, refresh token is missing, or the request fails
3909
+ * Returns a clean JSON representation of the error
4075
3910
  */
4076
- async refreshAccessToken() {
4077
- // If there's already a refresh in progress, return that promise
4078
- if (this.refreshPromise) {
4079
- return this.refreshPromise;
4080
- }
4081
- try {
4082
- // Create new refresh promise
4083
- this.refreshPromise = this._doRefreshToken();
4084
- // Wait for refresh to complete
4085
- const result = await this.refreshPromise;
4086
- return result;
4087
- }
4088
- finally {
4089
- // Clear the refresh promise when done (success or failure)
4090
- this.refreshPromise = null;
4091
- }
3911
+ toJSON() {
3912
+ return {
3913
+ type: this.type,
3914
+ message: this.message,
3915
+ statusCode: this.statusCode,
3916
+ requestId: this.requestId,
3917
+ timestamp: this.timestamp
3918
+ };
4092
3919
  }
4093
3920
  /**
4094
- * Internal method to perform the actual token refresh
3921
+ * Returns detailed debug information including stack trace
4095
3922
  */
4096
- async _doRefreshToken() {
4097
- // Check if we're in OAuth flow
4098
- if (!hasOAuthConfig(this.config)) {
4099
- throw new Error('refreshAccessToken is only available in OAuth flow');
4100
- }
4101
- // Get current token info from token manager
4102
- const tokenInfo = this.getTokenInfo();
4103
- if (!tokenInfo?.refreshToken) {
4104
- throw new Error('No refresh token available. User may need to re-authenticate.');
4105
- }
4106
- const orgName = this.config.orgName;
4107
- const body = new URLSearchParams({
4108
- grant_type: 'refresh_token',
4109
- client_id: this.config.clientId,
4110
- refresh_token: tokenInfo.refreshToken
4111
- });
4112
- const response = await fetch(`${this.config.baseUrl}/${orgName}/identity_/connect/token`, {
4113
- method: 'POST',
4114
- headers: {
4115
- 'Content-Type': 'application/x-www-form-urlencoded'
4116
- },
4117
- body: body.toString()
4118
- });
4119
- if (!response.ok) {
4120
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
4121
- console.error("Token refresh error:", errorData);
4122
- // Clear the invalid token to prevent further failed requests
4123
- this.clearToken();
4124
- throw new Error(`Failed to refresh access token: ${JSON.stringify(errorData)}`);
4125
- }
4126
- const token = await response.json();
4127
- this.setToken({
4128
- token: token.access_token,
4129
- type: 'oauth',
4130
- expiresAt: new Date(Date.now() + token.expires_in * 1000),
4131
- refreshToken: token.refresh_token
4132
- });
4133
- return token;
3923
+ getDebugInfo() {
3924
+ return {
3925
+ ...this.toJSON(),
3926
+ stack: this.stack
3927
+ };
4134
3928
  }
4135
3929
  }
4136
3930
 
4137
3931
  /**
4138
- * API Endpoint Constants
4139
- * Centralized location for all API endpoints used throughout the SDK
3932
+ * HTTP status code constants for error handling
4140
3933
  */
3934
+ const HttpStatus = {
3935
+ // Client errors (4xx)
3936
+ BAD_REQUEST: 400,
3937
+ UNAUTHORIZED: 401,
3938
+ FORBIDDEN: 403,
3939
+ NOT_FOUND: 404,
3940
+ TOO_MANY_REQUESTS: 429,
3941
+ // Server errors (5xx)
3942
+ INTERNAL_SERVER_ERROR: 500,
3943
+ NOT_IMPLEMENTED: 501,
3944
+ BAD_GATEWAY: 502,
3945
+ SERVICE_UNAVAILABLE: 503,
3946
+ GATEWAY_TIMEOUT: 504
3947
+ };
4141
3948
  /**
4142
- * Base path constants for different services
3949
+ * Error type constants for consistent error identification
4143
3950
  */
4144
- const IDENTITY_BASE = 'identity_';
3951
+ const ErrorType = {
3952
+ AUTHENTICATION: 'AuthenticationError',
3953
+ AUTHORIZATION: 'AuthorizationError',
3954
+ VALIDATION: 'ValidationError',
3955
+ NOT_FOUND: 'NotFoundError',
3956
+ RATE_LIMIT: 'RateLimitError',
3957
+ SERVER: 'ServerError',
3958
+ NETWORK: 'NetworkError'
3959
+ };
4145
3960
  /**
4146
- * Identity/Authentication Endpoints
3961
+ * Standard error message constants
4147
3962
  */
4148
- const IDENTITY_ENDPOINTS = {
4149
- TOKEN: `${IDENTITY_BASE}/connect/token`,
4150
- AUTHORIZE: `${IDENTITY_BASE}/connect/authorize`,
4151
- };
3963
+ const ErrorMessages = {
3964
+ // Authentication errors
3965
+ AUTHENTICATION_FAILED: 'Authentication failed',
3966
+ // Authorization errors
3967
+ ACCESS_DENIED: 'Access denied',
3968
+ // Validation errors
3969
+ VALIDATION_FAILED: 'Validation failed',
3970
+ // Not found errors
3971
+ RESOURCE_NOT_FOUND: 'Resource not found',
3972
+ // Rate limit errors
3973
+ RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
3974
+ // Server errors
3975
+ INTERNAL_SERVER_ERROR: 'Internal Server error occurred',
3976
+ // Network errors
3977
+ NETWORK_ERROR: 'Network error occurred'};
4152
3978
 
4153
- class AuthService {
4154
- constructor(config, executionContext) {
4155
- // Check if we should use stored OAuth context instead of provided config
4156
- const storedContext = AuthService.getStoredOAuthContext();
4157
- const effectiveConfig = storedContext ? AuthService._mergeConfigWithContext(config, storedContext) : config;
4158
- this.config = effectiveConfig;
4159
- const isOAuth = hasOAuthConfig(effectiveConfig);
4160
- this.tokenManager = new TokenManager(executionContext, effectiveConfig, isOAuth);
4161
- // Auto-load token from storage on initialization
4162
- // This ensures isAuthenticated() returns true after page refresh if a valid token exists
4163
- this.tokenManager.loadFromStorage();
4164
- }
4165
- /**
4166
- * Check if we're in an OAuth callback state
4167
- */
4168
- static isInOAuthCallback() {
4169
- if (!isBrowser)
4170
- return false;
4171
- const urlParams = new URLSearchParams(window.location.search);
4172
- const code = urlParams.get('code');
4173
- const hasCodeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4174
- return !!(code && hasCodeVerifier);
4175
- }
4176
- /**
4177
- * Get stored OAuth context
4178
- */
4179
- static getStoredOAuthContext() {
4180
- if (!isBrowser) {
4181
- return null;
4182
- }
4183
- try {
4184
- const stored = sessionStorage.getItem('uipath_sdk_oauth_context');
4185
- if (!stored) {
4186
- return null;
4187
- }
4188
- const context = JSON.parse(stored);
4189
- // Validate required fields
4190
- if (!context.codeVerifier || !context.clientId || !context.redirectUri ||
4191
- !context.baseUrl || !context.orgName) {
4192
- sessionStorage.removeItem('uipath_sdk_oauth_context');
4193
- return null;
4194
- }
4195
- return context;
4196
- }
4197
- catch (error) {
4198
- sessionStorage.removeItem('uipath_sdk_oauth_context');
4199
- console.warn('Failed to parse stored OAuth context from session storage', error);
4200
- return null;
4201
- }
4202
- }
4203
- /**
4204
- * Merges provided config with stored OAuth context, prioritizing stored values
4205
- */
4206
- static _mergeConfigWithContext(config, context) {
4207
- return {
4208
- ...config,
4209
- baseUrl: context.baseUrl,
4210
- orgName: context.orgName,
4211
- tenantName: context.tenantName,
4212
- clientId: context.clientId,
4213
- redirectUri: context.redirectUri,
4214
- scope: context.scope
4215
- };
4216
- }
4217
- /**
4218
- * Get the token manager instance
4219
- */
4220
- getTokenManager() {
4221
- return this.tokenManager;
4222
- }
4223
- /**
4224
- * Authenticates the user based on the provided SDK configuration.
4225
- * This method handles OAuth 2.0 authentication flow only.
4226
- * For secret-based authentication, see authenticateWithSecret().
4227
- * @param config The SDK configuration object.
4228
- * @returns A promise that resolves to true if authentication is successful, otherwise false.
4229
- * In an OAuth flow, this method will trigger a page redirect and the promise will not resolve.
4230
- */
4231
- async authenticate(config) {
4232
- if (!isBrowser) {
4233
- return false;
4234
- }
4235
- // First priority: Complete OAuth callback if we detect it
4236
- if (AuthService.isInOAuthCallback()) {
4237
- const urlParams = new URLSearchParams(window.location.search);
4238
- const code = urlParams.get('code');
4239
- if (!code) {
4240
- throw new Error('Authorization code missing in OAuth callback');
4241
- }
4242
- // Check if token already exists (prevents duplicate processing)
4243
- if (this.tokenManager.hasValidToken()) {
4244
- return true;
4245
- }
4246
- // Ensure we have OAuth config for callback completion
4247
- if (!hasOAuthConfig(config)) {
4248
- throw new Error('OAuth configuration incomplete: clientId, redirectUri, and scope are required for OAuth callback');
4249
- }
4250
- const result = await this._authenticateWithOAuth(config.clientId, config.redirectUri, config.scope);
4251
- return result;
4252
- }
4253
- // Secondly: Try to load existing valid token from storage
4254
- const loadedFromStorage = this.tokenManager.loadFromStorage();
4255
- // If we have a valid token from storage, return true
4256
- if (loadedFromStorage && this.tokenManager.hasValidToken()) {
4257
- return true;
4258
- }
4259
- // Start new OAuth flow if config has OAuth fields
4260
- if (hasOAuthConfig(config)) {
4261
- return await this._authenticateWithOAuth(config.clientId, config.redirectUri, config.scope);
4262
- }
4263
- return false;
4264
- }
4265
- /**
4266
- * Authenticate using OAuth flow
4267
- */
4268
- async _authenticateWithOAuth(clientId, redirectUri, scope) {
4269
- if (!isBrowser) {
4270
- throw new Error('OAuth flow is only supported in browser environments');
4271
- }
4272
- // Check if we have a stored code verifier indicating we're in an OAuth flow
4273
- const codeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4274
- const isInOAuthFlow = codeVerifier !== null;
4275
- const urlParams = new URLSearchParams(window.location.search);
4276
- const code = urlParams.get('code');
4277
- // If we're in an OAuth flow (server-controlled code verifier exists), handle the callback
4278
- if (isInOAuthFlow) {
4279
- // We're expecting a callback - validate parameters
4280
- if (!code) {
4281
- // Clear stored state on error
4282
- sessionStorage.removeItem('uipath_sdk_code_verifier');
4283
- throw new Error('Authorization code missing in OAuth callback');
4284
- }
4285
- // Validate the authorization code format before using it
4286
- // OAuth authorization codes should be alphanumeric with some special characters
4287
- const codePattern = /^[A-Za-z0-9\-._~+/]+=*$/;
4288
- if (!codePattern.test(code)) {
4289
- // Clear stored state on error
4290
- sessionStorage.removeItem('uipath_sdk_code_verifier');
4291
- throw new Error('Invalid authorization code format');
4292
- }
4293
- // Authorization code is present and validated, so we can exchange it for a token.
4294
- await this._handleOAuthCallback(code, clientId, redirectUri);
4295
- return this.hasValidToken();
4296
- }
4297
- else {
4298
- // Not in an OAuth flow - initiate one
4299
- // Ignore any URL parameters that might be present
4300
- await this._initiateOAuthFlow(clientId, redirectUri, scope);
4301
- // This line is not expected to be reached due to redirect
4302
- return false;
4303
- }
4304
- }
4305
- /**
4306
- * Authenticate using API secret
4307
- */
4308
- authenticateWithSecret(secret) {
4309
- try {
4310
- this.updateToken({ token: secret, type: 'secret' });
4311
- return true;
4312
- }
4313
- catch (error) {
4314
- console.error('Failed to authenticate with secret', error);
4315
- return false;
4316
- }
4317
- }
4318
- /**
4319
- * Updates the access token used for API requests
4320
- * @param tokenInfo The token information containing the access token, type, expiration, and refresh token
4321
- */
4322
- updateToken(tokenInfo) {
4323
- this.tokenManager.setToken(tokenInfo);
4324
- }
4325
- /**
4326
- * Checks if the current token is valid
4327
- */
4328
- hasValidToken() {
4329
- return this.tokenManager.hasValidToken();
4330
- }
4331
- /**
4332
- * Get the current token
4333
- */
4334
- getToken() {
4335
- if (!this.tokenManager.hasValidToken()) {
4336
- return undefined;
4337
- }
4338
- return this.tokenManager.getToken();
4339
- }
4340
- /**
4341
- * Generates a random code verifier for PKCE
4342
- */
4343
- generateCodeVerifier() {
4344
- if (isBrowser) {
4345
- const array = new Uint8Array(32);
4346
- crypto.getRandomValues(array);
4347
- return this._base64URLEncode(array);
4348
- }
4349
- else {
4350
- // In Node.js environment
4351
- try {
4352
- const crypto = require('crypto');
4353
- return crypto.randomBytes(32)
4354
- .toString('base64')
4355
- .replace(/\+/g, '-')
4356
- .replace(/\//g, '_')
4357
- .replace(/=/g, '');
4358
- }
4359
- catch {
4360
- throw new Error("crypto not available in browser");
4361
- }
4362
- }
3979
+ /**
3980
+ * Error thrown when authentication fails (401 errors)
3981
+ * Common scenarios:
3982
+ * - Invalid credentials
3983
+ * - Expired token
3984
+ * - Missing authentication
3985
+ */
3986
+ class AuthenticationError extends UiPathError {
3987
+ constructor(params = {}) {
3988
+ super(ErrorType.AUTHENTICATION, {
3989
+ message: params.message || ErrorMessages.AUTHENTICATION_FAILED,
3990
+ statusCode: params.statusCode ?? HttpStatus.UNAUTHORIZED,
3991
+ requestId: params.requestId
3992
+ });
4363
3993
  }
4364
- /**
4365
- * Generates a code challenge from the code verifier
4366
- */
4367
- async generateCodeChallenge(codeVerifier) {
4368
- if (isBrowser) {
4369
- const encoder = new TextEncoder();
4370
- const data = encoder.encode(codeVerifier);
4371
- const hash = await crypto.subtle.digest('SHA-256', data);
4372
- return this._base64URLEncode(new Uint8Array(hash));
4373
- }
4374
- else {
4375
- // In Node.js environment
4376
- try {
4377
- const crypto = require('crypto');
4378
- return crypto.createHash('sha256')
4379
- .update(codeVerifier)
4380
- .digest('base64')
4381
- .replace(/\+/g, '-')
4382
- .replace(/\//g, '_')
4383
- .replace(/=/g, '');
4384
- }
4385
- catch {
4386
- throw new Error("crypto not available in browser");
4387
- }
4388
- }
3994
+ }
3995
+
3996
+ /**
3997
+ * Error thrown when authorization fails (403 errors)
3998
+ * Common scenarios:
3999
+ * - Insufficient permissions
4000
+ * - Access denied to resource
4001
+ * - Invalid scope
4002
+ */
4003
+ class AuthorizationError extends UiPathError {
4004
+ constructor(params = {}) {
4005
+ super(ErrorType.AUTHORIZATION, {
4006
+ message: params.message || ErrorMessages.ACCESS_DENIED,
4007
+ statusCode: params.statusCode ?? HttpStatus.FORBIDDEN,
4008
+ requestId: params.requestId
4009
+ });
4389
4010
  }
4390
- /**
4391
- * Gets the authorization URL for the OAuth flow
4392
- */
4393
- getAuthorizationUrl(params) {
4394
- const orgName = this.config.orgName;
4395
- const queryParams = new URLSearchParams({
4396
- response_type: 'code',
4397
- client_id: params.clientId,
4398
- redirect_uri: params.redirectUri,
4399
- code_challenge: params.codeChallenge,
4400
- code_challenge_method: 'S256',
4401
- scope: params.scope + ' offline_access',
4402
- state: params.state || this.generateCodeVerifier().slice(0, 16)
4011
+ }
4012
+
4013
+ /**
4014
+ * Error thrown when validation fails (400 errors or client-side validation)
4015
+ * Common scenarios:
4016
+ * - Invalid input parameters
4017
+ * - Missing required fields
4018
+ * - Invalid data format
4019
+ */
4020
+ class ValidationError extends UiPathError {
4021
+ constructor(params = {}) {
4022
+ super(ErrorType.VALIDATION, {
4023
+ message: params.message || ErrorMessages.VALIDATION_FAILED,
4024
+ statusCode: params.statusCode ?? HttpStatus.BAD_REQUEST,
4025
+ requestId: params.requestId
4403
4026
  });
4404
- return `${this.config.baseUrl}/${orgName}/${IDENTITY_ENDPOINTS.AUTHORIZE}?${queryParams.toString()}`;
4405
4027
  }
4406
- /**
4407
- * Exchanges the authorization code for an access token and automatically updates the current token
4408
- */
4409
- async _getAccessToken(params) {
4410
- const orgName = this.config.orgName;
4411
- const body = new URLSearchParams({
4412
- grant_type: 'authorization_code',
4413
- client_id: params.clientId,
4414
- code: params.code,
4415
- redirect_uri: params.redirectUri,
4416
- code_verifier: params.codeVerifier
4028
+ }
4029
+
4030
+ /**
4031
+ * Error thrown when a resource is not found (404 errors)
4032
+ * Common scenarios:
4033
+ * - Resource doesn't exist
4034
+ * - Invalid ID provided
4035
+ * - Resource deleted
4036
+ */
4037
+ class NotFoundError extends UiPathError {
4038
+ constructor(params = {}) {
4039
+ super(ErrorType.NOT_FOUND, {
4040
+ message: params.message || ErrorMessages.RESOURCE_NOT_FOUND,
4041
+ statusCode: params.statusCode ?? HttpStatus.NOT_FOUND,
4042
+ requestId: params.requestId
4417
4043
  });
4418
- const response = await fetch(`${this.config.baseUrl}/${orgName}/${IDENTITY_ENDPOINTS.TOKEN}`, {
4419
- method: 'POST',
4420
- headers: {
4421
- 'Content-Type': 'application/x-www-form-urlencoded'
4422
- },
4423
- body: body.toString()
4044
+ }
4045
+ }
4046
+
4047
+ /**
4048
+ * Error thrown when rate limit is exceeded (429 errors)
4049
+ * Common scenarios:
4050
+ * - Too many requests in a time window
4051
+ * - API throttling
4052
+ */
4053
+ class RateLimitError extends UiPathError {
4054
+ constructor(params = {}) {
4055
+ super(ErrorType.RATE_LIMIT, {
4056
+ message: params.message || ErrorMessages.RATE_LIMIT_EXCEEDED,
4057
+ statusCode: params.statusCode ?? HttpStatus.TOO_MANY_REQUESTS,
4058
+ requestId: params.requestId
4424
4059
  });
4425
- if (!response.ok) {
4426
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
4427
- console.error("OAuth error:", errorData);
4428
- throw new Error(`Failed to get access token: ${JSON.stringify(errorData)}`);
4429
- }
4430
- const token = await response.json();
4431
- this.updateToken({
4432
- token: token.access_token,
4433
- type: 'oauth',
4434
- expiresAt: token.expires_in ? new Date(Date.now() + token.expires_in * 1000) : undefined,
4435
- refreshToken: token.refresh_token
4060
+ }
4061
+ }
4062
+
4063
+ /**
4064
+ * Error thrown when server encounters an error (5xx errors)
4065
+ * Common scenarios:
4066
+ * - Internal server error
4067
+ * - Service unavailable
4068
+ * - Gateway timeout
4069
+ */
4070
+ class ServerError extends UiPathError {
4071
+ constructor(params = {}) {
4072
+ super(ErrorType.SERVER, {
4073
+ message: params.message || ErrorMessages.INTERNAL_SERVER_ERROR,
4074
+ statusCode: params.statusCode ?? HttpStatus.INTERNAL_SERVER_ERROR,
4075
+ requestId: params.requestId
4436
4076
  });
4437
- return token;
4438
4077
  }
4439
4078
  /**
4440
- * Base64URL encodes an array buffer
4079
+ * Checks if this is a temporary error that might succeed on retry
4441
4080
  */
4442
- _base64URLEncode(buffer) {
4443
- const base64 = btoa(String.fromCharCode(...buffer));
4444
- return base64
4445
- .replace(/\+/g, '-')
4446
- .replace(/\//g, '_')
4447
- .replace(/=/g, '');
4448
- }
4449
- async _initiateOAuthFlow(clientId, redirectUri, scope) {
4450
- const codeVerifier = this.generateCodeVerifier();
4451
- const codeChallenge = await this.generateCodeChallenge(codeVerifier);
4452
- // Store complete OAuth context for callback completion
4453
- const oauthContext = {
4454
- codeVerifier,
4455
- clientId,
4456
- redirectUri,
4457
- baseUrl: this.config.baseUrl,
4458
- orgName: this.config.orgName,
4459
- tenantName: this.config.tenantName,
4460
- scope
4461
- };
4462
- sessionStorage.setItem('uipath_sdk_oauth_context', JSON.stringify(oauthContext));
4463
- sessionStorage.setItem('uipath_sdk_code_verifier', codeVerifier);
4464
- const authUrl = this.getAuthorizationUrl({
4465
- clientId,
4466
- redirectUri,
4467
- codeChallenge,
4468
- scope
4469
- });
4470
- window.location.href = authUrl;
4081
+ get isRetryable() {
4082
+ return this.statusCode === HttpStatus.BAD_GATEWAY ||
4083
+ this.statusCode === HttpStatus.SERVICE_UNAVAILABLE ||
4084
+ this.statusCode === HttpStatus.GATEWAY_TIMEOUT;
4471
4085
  }
4472
- async _handleOAuthCallback(code, clientId, redirectUri) {
4473
- const codeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4474
- if (!codeVerifier) {
4475
- throw new Error('Code verifier not found in session storage. Authentication may have been interrupted.');
4476
- }
4477
- await this._getAccessToken({
4478
- clientId,
4479
- redirectUri,
4480
- code,
4481
- codeVerifier
4086
+ }
4087
+
4088
+ /**
4089
+ * Error thrown when network/connection issues occur
4090
+ * Common scenarios:
4091
+ * - Connection timeout
4092
+ * - DNS resolution failure
4093
+ * - Network unreachable
4094
+ * - Request aborted
4095
+ */
4096
+ class NetworkError extends UiPathError {
4097
+ constructor(params = {}) {
4098
+ super(ErrorType.NETWORK, {
4099
+ message: params.message || ErrorMessages.NETWORK_ERROR,
4100
+ statusCode: params.statusCode, // Network errors typically don't have HTTP status codes
4101
+ requestId: params.requestId
4482
4102
  });
4483
- // Clear OAuth context and code verifier after successful token exchange
4484
- sessionStorage.removeItem('uipath_sdk_oauth_context');
4485
- sessionStorage.removeItem('uipath_sdk_code_verifier');
4486
- const url = new URL(window.location.href);
4487
- url.searchParams.delete('code');
4488
- url.searchParams.delete('state');
4489
- window.history.replaceState({}, '', url.toString());
4490
4103
  }
4491
4104
  }
4492
4105
 
4493
- function validateConfig(config) {
4494
- if (!config.baseUrl || !config.orgName || !config.tenantName) {
4495
- throw new Error('Missing required configuration: baseUrl, orgName, and tenantName are required');
4496
- }
4497
- if (!hasSecretConfig(config) && !hasOAuthConfig(config)) {
4498
- throw new Error('Invalid configuration: must provide either secret or (clientId, redirectUri, and scope)');
4499
- }
4106
+ /**
4107
+ * Type guard to check if an error is a UiPathError
4108
+ */
4109
+ function isUiPathError(error) {
4110
+ return error instanceof UiPathError;
4111
+ }
4112
+ /**
4113
+ * Type guard to check if an error is an AuthenticationError
4114
+ */
4115
+ function isAuthenticationError(error) {
4116
+ return error instanceof AuthenticationError;
4117
+ }
4118
+ /**
4119
+ * Type guard to check if an error is an AuthorizationError
4120
+ */
4121
+ function isAuthorizationError(error) {
4122
+ return error instanceof AuthorizationError;
4123
+ }
4124
+ /**
4125
+ * Type guard to check if an error is a ValidationError
4126
+ */
4127
+ function isValidationError(error) {
4128
+ return error instanceof ValidationError;
4129
+ }
4130
+ /**
4131
+ * Type guard to check if an error is a NotFoundError
4132
+ */
4133
+ function isNotFoundError(error) {
4134
+ return error instanceof NotFoundError;
4135
+ }
4136
+ /**
4137
+ * Type guard to check if an error is a RateLimitError
4138
+ */
4139
+ function isRateLimitError(error) {
4140
+ return error instanceof RateLimitError;
4500
4141
  }
4501
- function normalizeBaseUrl(url) {
4502
- return url.endsWith('/') ? url.slice(0, -1) : url;
4142
+ /**
4143
+ * Type guard to check if an error is a ServerError
4144
+ */
4145
+ function isServerError(error) {
4146
+ return error instanceof ServerError;
4503
4147
  }
4504
-
4505
4148
  /**
4506
- * SDK Telemetry constants
4149
+ * Type guard to check if an error is a NetworkError
4507
4150
  */
4508
- // Connection string placeholder that will be replaced during build
4509
- const CONNECTION_STRING = "InstrumentationKey=a6efa11d-1feb-4508-9738-e13e12dcae5e;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=7c58eb1c-9581-4ba6-839e-11725848a037";
4510
- // SDK Version placeholder
4511
- const SDK_VERSION = "1.0.0";
4512
- const VERSION = "Version";
4513
- const SERVICE = "Service";
4514
- const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
4515
- const CLOUD_TENANT_NAME = "CloudTenantName";
4516
- const CLOUD_URL = "CloudUrl";
4517
- const CLOUD_CLIENT_ID = "CloudClientId";
4518
- const CLOUD_REDIRECT_URI = "CloudRedirectUri";
4519
- const APP_NAME = "ApplicationName";
4520
- const CLOUD_ROLE_NAME = "uipath-ts-sdk";
4521
- // Service and logger names
4522
- const SDK_SERVICE_NAME = "UiPath.TypeScript.Sdk";
4523
- const SDK_LOGGER_NAME = "uipath-ts-sdk-telemetry";
4524
- // Event names
4525
- const SDK_RUN_EVENT = "Sdk.Run";
4526
- // Default value for unknown/empty attributes
4527
- const UNKNOWN = "";
4151
+ function isNetworkError(error) {
4152
+ return error instanceof NetworkError;
4153
+ }
4154
+ /**
4155
+ * Helper to get error details in a safe way
4156
+ */
4157
+ function getErrorDetails(error) {
4158
+ if (isUiPathError(error)) {
4159
+ return {
4160
+ message: error.message,
4161
+ statusCode: error.statusCode
4162
+ };
4163
+ }
4164
+ if (error instanceof Error) {
4165
+ return {
4166
+ message: error.message
4167
+ };
4168
+ }
4169
+ return {
4170
+ message: String(error)
4171
+ };
4172
+ }
4528
4173
 
4529
4174
  /**
4530
- * Log exporter that sends ALL logs as Application Insights custom events
4175
+ * TokenManager is responsible for managing authentication tokens.
4176
+ * It provides token operations for a specific client ID.
4177
+ * - For OAuth tokens: Uses session storage with client ID-based keys
4178
+ * - For Secret tokens: Stores only in memory, allowing multiple instances
4531
4179
  */
4532
- class ApplicationInsightsEventExporter {
4533
- constructor(connectionString) {
4534
- this.connectionString = connectionString;
4180
+ class TokenManager {
4181
+ /**
4182
+ * Creates a new TokenManager instance
4183
+ * @param executionContext The execution context
4184
+ * @param config The SDK configuration
4185
+ * @param isOAuth Whether this is an OAuth-based authentication
4186
+ */
4187
+ constructor(executionContext, config, isOAuth = false) {
4188
+ this.executionContext = executionContext;
4189
+ this.config = config;
4190
+ this.isOAuth = isOAuth;
4191
+ this.STORAGE_KEY_PREFIX = 'uipath_sdk_user_token-';
4192
+ this.refreshPromise = null;
4535
4193
  }
4536
- export(logs, resultCallback) {
4537
- try {
4538
- logs.forEach(logRecord => {
4539
- this.sendAsCustomEvent(logRecord);
4194
+ /**
4195
+ * Checks if a token is expired
4196
+ * @param tokenInfo The token info to check
4197
+ * @returns true if the token is expired, false otherwise
4198
+ */
4199
+ isTokenExpired(tokenInfo) {
4200
+ // If no token info or no expiration date, token is not expired
4201
+ if (!tokenInfo?.expiresAt) {
4202
+ return false;
4203
+ }
4204
+ return new Date() >= tokenInfo.expiresAt;
4205
+ }
4206
+ /**
4207
+ * Gets a valid authentication token, refreshing if necessary.
4208
+ * This is the single source of truth for token validation and refresh logic.
4209
+ *
4210
+ * @returns The valid token string
4211
+ * @throws AuthenticationError if no token available or refresh fails
4212
+ */
4213
+ async getValidToken() {
4214
+ const tokenInfo = this.executionContext.get('tokenInfo');
4215
+ if (!tokenInfo) {
4216
+ throw new AuthenticationError({
4217
+ message: 'No authentication token available. Make sure to initialize the SDK first.'
4540
4218
  });
4541
- resultCallback({ code: 0 });
4219
+ }
4220
+ // For secret-based tokens, they never expire
4221
+ if (tokenInfo.type === 'secret') {
4222
+ return tokenInfo.token;
4223
+ }
4224
+ // If token is not expired, return it
4225
+ if (!this.isTokenExpired(tokenInfo)) {
4226
+ return tokenInfo.token;
4227
+ }
4228
+ // Token is expired, refresh it
4229
+ try {
4230
+ const newToken = await this.refreshAccessToken();
4231
+ return newToken.access_token;
4542
4232
  }
4543
4233
  catch (error) {
4544
- console.debug('Failed to export logs to Application Insights:', error);
4545
- resultCallback({ code: 2, error });
4234
+ const message = error instanceof Error ? error.message : 'Unknown error';
4235
+ throw new AuthenticationError({
4236
+ message: `Token refresh failed: ${message}. Please re-authenticate.`,
4237
+ statusCode: HttpStatus.UNAUTHORIZED
4238
+ });
4546
4239
  }
4547
4240
  }
4548
- shutdown() {
4549
- return Promise.resolve();
4241
+ /**
4242
+ * Gets the storage key for this TokenManager instance
4243
+ */
4244
+ _getStorageKey() {
4245
+ return `${this.STORAGE_KEY_PREFIX}${this.config.clientId}`;
4550
4246
  }
4551
- sendAsCustomEvent(logRecord) {
4552
- // Get event name from body or attributes
4553
- const eventName = logRecord.body || SDK_RUN_EVENT;
4554
- const payload = {
4555
- name: 'Microsoft.ApplicationInsights.Event',
4556
- time: new Date().toISOString(),
4557
- iKey: this.extractInstrumentationKey(),
4558
- data: {
4559
- baseType: 'EventData',
4560
- baseData: {
4561
- ver: 2,
4562
- name: eventName,
4563
- properties: this.convertAttributesToProperties(logRecord.attributes || {})
4564
- }
4565
- },
4566
- tags: {
4567
- 'ai.cloud.role': CLOUD_ROLE_NAME,
4568
- 'ai.cloud.roleInstance': SDK_VERSION
4247
+ /**
4248
+ * Loads token from session storage if available
4249
+ * @returns true if a valid token was loaded, false otherwise
4250
+ */
4251
+ loadFromStorage() {
4252
+ // Only OAuth tokens are stored in session storage
4253
+ if (!isBrowser || !this.isOAuth) {
4254
+ return false;
4255
+ }
4256
+ try {
4257
+ const storedToken = sessionStorage.getItem(this._getStorageKey());
4258
+ if (!storedToken) {
4259
+ return false;
4569
4260
  }
4570
- };
4571
- this.sendToApplicationInsights(payload);
4572
- }
4573
- extractInstrumentationKey() {
4574
- const match = this.connectionString.match(/InstrumentationKey=([^;]+)/);
4575
- return match ? match[1] : '';
4576
- }
4577
- convertAttributesToProperties(attributes) {
4578
- const properties = {};
4579
- Object.entries(attributes || {}).forEach(([key, value]) => {
4580
- properties[key] = String(value);
4581
- });
4582
- return properties;
4261
+ const tokenInfo = this._parseTokenInfo(storedToken);
4262
+ if (!tokenInfo) {
4263
+ // Invalid token format, clear it
4264
+ sessionStorage.removeItem(this._getStorageKey());
4265
+ return false;
4266
+ }
4267
+ // Check if token is expired
4268
+ if (this.isTokenExpired(tokenInfo)) {
4269
+ // Token expired, clear it
4270
+ sessionStorage.removeItem(this._getStorageKey());
4271
+ return false;
4272
+ }
4273
+ // Valid token found, use it
4274
+ this.currentToken = tokenInfo;
4275
+ this._updateExecutionContext(tokenInfo);
4276
+ return true;
4277
+ }
4278
+ catch (error) {
4279
+ console.warn('Failed to load token from session storage', error);
4280
+ return false;
4281
+ }
4583
4282
  }
4584
- async sendToApplicationInsights(payload) {
4283
+ /**
4284
+ * Parse and validate token info from storage
4285
+ * @param storedToken JSON string from storage
4286
+ * @returns Valid TokenInfo or undefined if invalid
4287
+ */
4288
+ _parseTokenInfo(storedToken) {
4585
4289
  try {
4586
- const ingestionEndpoint = this.extractIngestionEndpoint();
4587
- if (!ingestionEndpoint) {
4588
- console.debug('No ingestion endpoint found in connection string');
4589
- return;
4290
+ const parsed = JSON.parse(storedToken);
4291
+ // Basic validation
4292
+ if (typeof parsed !== 'object' || !parsed) {
4293
+ return undefined;
4590
4294
  }
4591
- const url = `${ingestionEndpoint}/v2/track`;
4592
- const response = await fetch(url, {
4593
- method: 'POST',
4594
- headers: {
4595
- 'Content-Type': 'application/json',
4596
- },
4597
- body: JSON.stringify(payload)
4598
- });
4599
- if (!response.ok) {
4600
- console.debug(`Failed to send event telemetry: ${response.status} ${response.statusText}`);
4295
+ if (typeof parsed.token !== 'string' || !parsed.token) {
4296
+ return undefined;
4297
+ }
4298
+ if (parsed.type !== 'secret' && parsed.type !== 'oauth') {
4299
+ return undefined;
4300
+ }
4301
+ const tokenInfo = parsed;
4302
+ // Convert string date back to Date object
4303
+ if (tokenInfo.expiresAt) {
4304
+ tokenInfo.expiresAt = new Date(tokenInfo.expiresAt);
4305
+ // Verify it's a valid date
4306
+ if (isNaN(tokenInfo.expiresAt.getTime())) {
4307
+ return undefined;
4308
+ }
4601
4309
  }
4310
+ return tokenInfo;
4602
4311
  }
4603
4312
  catch (error) {
4604
- console.debug('Error sending event telemetry to Application Insights:', error);
4313
+ console.warn('Failed to parse token info', error);
4314
+ return undefined;
4605
4315
  }
4606
4316
  }
4607
- extractIngestionEndpoint() {
4608
- const match = this.connectionString.match(/IngestionEndpoint=([^;]+)/);
4609
- return match ? match[1] : '';
4317
+ /**
4318
+ * Sets a new token and updates all necessary contexts
4319
+ */
4320
+ setToken(tokenInfo) {
4321
+ this.currentToken = tokenInfo;
4322
+ // Store token in execution context
4323
+ this._updateExecutionContext(tokenInfo);
4324
+ // Store in session storage if in browser and this is an OAuth token
4325
+ if (isBrowser && this.isOAuth) {
4326
+ try {
4327
+ sessionStorage.setItem(this._getStorageKey(), JSON.stringify(tokenInfo));
4328
+ }
4329
+ catch (error) {
4330
+ console.warn('Failed to store token in session storage', error);
4331
+ }
4332
+ }
4610
4333
  }
4611
- }
4612
- /**
4613
- * Singleton telemetry client
4614
- */
4615
- class TelemetryClient {
4616
- constructor() {
4617
- this.isInitialized = false;
4334
+ /**
4335
+ * Gets the current token information
4336
+ */
4337
+ getTokenInfo() {
4338
+ return this.currentToken;
4618
4339
  }
4619
- static getInstance() {
4620
- if (!TelemetryClient.instance) {
4621
- TelemetryClient.instance = new TelemetryClient();
4622
- }
4623
- return TelemetryClient.instance;
4340
+ /**
4341
+ * Gets just the token string
4342
+ */
4343
+ getToken() {
4344
+ return this.currentToken?.token;
4624
4345
  }
4625
4346
  /**
4626
- * Initialize telemetry
4347
+ * Checks if we have a valid token
4627
4348
  */
4628
- initialize(config) {
4629
- if (this.isInitialized) {
4630
- return;
4349
+ hasValidToken() {
4350
+ if (!this.currentToken) {
4351
+ return false;
4631
4352
  }
4632
- this.isInitialized = true;
4633
- if (config) {
4634
- this.telemetryContext = config;
4353
+ if (this.isTokenExpired(this.currentToken)) {
4354
+ return false;
4635
4355
  }
4636
- try {
4637
- const connectionString = this.getConnectionString();
4638
- if (!connectionString) {
4639
- return;
4356
+ return true;
4357
+ }
4358
+ /**
4359
+ * Clears the current token
4360
+ */
4361
+ clearToken() {
4362
+ this.currentToken = undefined;
4363
+ this.executionContext.set('tokenInfo', undefined);
4364
+ const headers = this.executionContext.getHeaders();
4365
+ delete headers['Authorization'];
4366
+ this.executionContext.setHeaders(headers);
4367
+ // Remove from session storage if this is an OAuth token
4368
+ if (isBrowser && this.isOAuth) {
4369
+ try {
4370
+ sessionStorage.removeItem(this._getStorageKey());
4371
+ }
4372
+ catch (error) {
4373
+ console.warn('Failed to remove token from session storage', error);
4640
4374
  }
4641
- this.setupTelemetryProvider(connectionString);
4642
- }
4643
- catch (error) {
4644
- // Silent failure - telemetry errors shouldn't break functionality
4645
- console.debug('Failed to initialize OpenTelemetry:', error);
4646
4375
  }
4647
4376
  }
4648
- getConnectionString() {
4649
- const connectionString = CONNECTION_STRING;
4650
- return connectionString;
4651
- }
4652
- setupTelemetryProvider(connectionString) {
4653
- const exporter = new ApplicationInsightsEventExporter(connectionString);
4654
- const processor = new sdkLogs.BatchLogRecordProcessor(exporter);
4655
- this.logProvider = new sdkLogs.LoggerProvider({
4656
- processors: [processor]
4377
+ /**
4378
+ * Updates execution context with token information
4379
+ */
4380
+ _updateExecutionContext(tokenInfo) {
4381
+ this.executionContext.set('tokenInfo', tokenInfo);
4382
+ // Update authorization header
4383
+ this.executionContext.setHeaders({
4384
+ 'Authorization': `Bearer ${tokenInfo.token}`
4657
4385
  });
4658
- this.logger = this.logProvider.getLogger(SDK_LOGGER_NAME);
4659
4386
  }
4660
4387
  /**
4661
- * Track a telemetry event
4388
+ * Refreshes the access token using the stored refresh token.
4389
+ * This method only works for OAuth flow.
4390
+ * Uses a lock mechanism to prevent multiple simultaneous refreshes.
4391
+ * @returns A promise that resolves to the new AuthToken
4392
+ * @throws Error if not in OAuth flow, refresh token is missing, or the request fails
4662
4393
  */
4663
- track(eventName, name, extraAttributes = {}) {
4394
+ async refreshAccessToken() {
4395
+ // If there's already a refresh in progress, return that promise
4396
+ if (this.refreshPromise) {
4397
+ return this.refreshPromise;
4398
+ }
4664
4399
  try {
4665
- // Skip if logger not initialized
4666
- if (!this.logger) {
4667
- return;
4668
- }
4669
- const finalDisplayName = name || eventName;
4670
- const attributes = this.getEnrichedAttributes(extraAttributes, eventName);
4671
- // Emit as log
4672
- this.logger.emit({
4673
- body: finalDisplayName,
4674
- attributes: attributes,
4675
- timestamp: Date.now(),
4676
- });
4400
+ // Create new refresh promise
4401
+ this.refreshPromise = this._doRefreshToken();
4402
+ // Wait for refresh to complete
4403
+ const result = await this.refreshPromise;
4404
+ return result;
4677
4405
  }
4678
- catch (error) {
4679
- // Silent failure
4680
- console.debug('Failed to track telemetry event:', error);
4406
+ finally {
4407
+ // Clear the refresh promise when done (success or failure)
4408
+ this.refreshPromise = null;
4681
4409
  }
4682
4410
  }
4683
4411
  /**
4684
- * Get enriched attributes for telemetry events
4685
- */
4686
- getEnrichedAttributes(extraAttributes, eventName) {
4687
- const attributes = {
4688
- ...extraAttributes,
4689
- [APP_NAME]: SDK_SERVICE_NAME,
4690
- [VERSION]: SDK_VERSION,
4691
- [SERVICE]: eventName,
4692
- [CLOUD_URL]: this.createCloudUrl(),
4693
- [CLOUD_ORGANIZATION_NAME]: this.telemetryContext?.orgName || UNKNOWN,
4694
- [CLOUD_TENANT_NAME]: this.telemetryContext?.tenantName || UNKNOWN,
4695
- [CLOUD_REDIRECT_URI]: this.telemetryContext?.redirectUri || UNKNOWN,
4696
- [CLOUD_CLIENT_ID]: this.telemetryContext?.clientId || UNKNOWN,
4697
- };
4698
- return attributes;
4699
- }
4700
- /**
4701
- * Create cloud URL from base URL, organization ID, and tenant ID
4412
+ * Internal method to perform the actual token refresh
4702
4413
  */
4703
- createCloudUrl() {
4704
- const baseUrl = this.telemetryContext?.baseUrl;
4705
- const orgId = this.telemetryContext?.orgName;
4706
- const tenantId = this.telemetryContext?.tenantName;
4707
- if (!baseUrl || !orgId || !tenantId) {
4708
- return UNKNOWN;
4414
+ async _doRefreshToken() {
4415
+ // Check if we're in OAuth flow
4416
+ if (!hasOAuthConfig(this.config)) {
4417
+ throw new Error('refreshAccessToken is only available in OAuth flow');
4709
4418
  }
4710
- return `${baseUrl}/${orgId}/${tenantId}`;
4419
+ // Get current token info from token manager
4420
+ const tokenInfo = this.getTokenInfo();
4421
+ if (!tokenInfo?.refreshToken) {
4422
+ throw new Error('No refresh token available. User may need to re-authenticate.');
4423
+ }
4424
+ const orgName = this.config.orgName;
4425
+ const body = new URLSearchParams({
4426
+ grant_type: 'refresh_token',
4427
+ client_id: this.config.clientId,
4428
+ refresh_token: tokenInfo.refreshToken
4429
+ });
4430
+ const response = await fetch(`${this.config.baseUrl}/${orgName}/identity_/connect/token`, {
4431
+ method: 'POST',
4432
+ headers: {
4433
+ 'Content-Type': 'application/x-www-form-urlencoded'
4434
+ },
4435
+ body: body.toString()
4436
+ });
4437
+ if (!response.ok) {
4438
+ const errorData = await response.json().catch(() => ({ message: response.statusText }));
4439
+ console.error("Token refresh error:", errorData);
4440
+ // Clear the invalid token to prevent further failed requests
4441
+ this.clearToken();
4442
+ throw new Error(`Failed to refresh access token: ${JSON.stringify(errorData)}`);
4443
+ }
4444
+ const token = await response.json();
4445
+ this.setToken({
4446
+ token: token.access_token,
4447
+ type: 'oauth',
4448
+ expiresAt: new Date(Date.now() + token.expires_in * 1000),
4449
+ refreshToken: token.refresh_token
4450
+ });
4451
+ return token;
4711
4452
  }
4712
4453
  }
4713
- // Export singleton instance
4714
- const telemetryClient = TelemetryClient.getInstance();
4715
4454
 
4716
4455
  /**
4717
- * SDK Track decorator and function for telemetry
4718
- */
4719
- /**
4720
- * Direct tracking function
4456
+ * Base path constants for different services
4721
4457
  */
4722
- function trackEvent(eventName, name, attributes) {
4723
- telemetryClient.track(eventName, name, attributes);
4724
- }
4458
+ const IDENTITY_BASE = 'identity_';
4725
4459
 
4726
4460
  /**
4727
- * SDK Internals Registry - Internal registry for SDK instances
4728
- *
4729
- * This class is NOT exported in the public API.
4730
- * It provides a secure way to share SDK internals between
4731
- * the UiPath class and service classes without exposing them publicly.
4732
- *
4733
- * @internal
4461
+ * Identity/Authentication Endpoints
4734
4462
  */
4735
- // Global symbol key to ensure WeakMap is shared across module instances
4736
- // This prevents issues when core and service modules are bundled separately
4737
- const REGISTRY_KEY = Symbol.for('@uipath/sdk-internals-registry');
4738
- // Get or create the global WeakMap store
4739
- const getGlobalStore = () => {
4740
- const globalObj = globalThis;
4741
- if (!globalObj[REGISTRY_KEY]) {
4742
- globalObj[REGISTRY_KEY] = new WeakMap();
4743
- }
4744
- return globalObj[REGISTRY_KEY];
4745
- };
4746
4463
  /**
4747
- * Internal registry for SDK private components.
4748
- * Uses WeakMap to prevent memory leaks - entries are automatically
4749
- * garbage collected when the SDK instance is no longer referenced.
4750
- *
4751
- * Uses a global singleton pattern to ensure the same WeakMap is shared
4752
- * across separately bundled modules (core, entities, tasks, etc.).
4753
- *
4754
- * @internal - Not exported in public API
4464
+ * Identity Service Endpoints
4755
4465
  */
4756
- class SDKInternalsRegistry {
4757
- // Use global store to ensure sharing across module bundles
4758
- static get store() {
4759
- return getGlobalStore();
4466
+ const IDENTITY_ENDPOINTS = {
4467
+ TOKEN: `${IDENTITY_BASE}/connect/token`,
4468
+ AUTHORIZE: `${IDENTITY_BASE}/connect/authorize`,
4469
+ };
4470
+
4471
+ class AuthService {
4472
+ constructor(config, executionContext) {
4473
+ // Check if we should use stored OAuth context instead of provided config
4474
+ const storedContext = AuthService.getStoredOAuthContext();
4475
+ const effectiveConfig = storedContext ? AuthService._mergeConfigWithContext(config, storedContext) : config;
4476
+ this.config = effectiveConfig;
4477
+ const isOAuth = hasOAuthConfig(effectiveConfig);
4478
+ this.tokenManager = new TokenManager(executionContext, effectiveConfig, isOAuth);
4479
+ // Auto-load token from storage on initialization
4480
+ // This ensures isAuthenticated() returns true after page refresh if a valid token exists
4481
+ this.tokenManager.loadFromStorage();
4482
+ }
4483
+ /**
4484
+ * Check if we're in an OAuth callback state
4485
+ */
4486
+ static isInOAuthCallback() {
4487
+ if (!isBrowser)
4488
+ return false;
4489
+ const urlParams = new URLSearchParams(window.location.search);
4490
+ const code = urlParams.get('code');
4491
+ const hasCodeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4492
+ return !!(code && hasCodeVerifier);
4493
+ }
4494
+ /**
4495
+ * Get stored OAuth context
4496
+ */
4497
+ static getStoredOAuthContext() {
4498
+ if (!isBrowser) {
4499
+ return null;
4500
+ }
4501
+ try {
4502
+ const stored = sessionStorage.getItem('uipath_sdk_oauth_context');
4503
+ if (!stored) {
4504
+ return null;
4505
+ }
4506
+ const context = JSON.parse(stored);
4507
+ // Validate required fields
4508
+ if (!context.codeVerifier || !context.clientId || !context.redirectUri ||
4509
+ !context.baseUrl || !context.orgName) {
4510
+ sessionStorage.removeItem('uipath_sdk_oauth_context');
4511
+ return null;
4512
+ }
4513
+ return context;
4514
+ }
4515
+ catch (error) {
4516
+ sessionStorage.removeItem('uipath_sdk_oauth_context');
4517
+ console.warn('Failed to parse stored OAuth context from session storage', error);
4518
+ return null;
4519
+ }
4520
+ }
4521
+ /**
4522
+ * Merges provided config with stored OAuth context, prioritizing stored values
4523
+ */
4524
+ static _mergeConfigWithContext(config, context) {
4525
+ return {
4526
+ ...config,
4527
+ baseUrl: context.baseUrl,
4528
+ orgName: context.orgName,
4529
+ tenantName: context.tenantName,
4530
+ clientId: context.clientId,
4531
+ redirectUri: context.redirectUri,
4532
+ scope: context.scope
4533
+ };
4760
4534
  }
4761
4535
  /**
4762
- * Register SDK instance internals
4763
- * Called by UiPath constructor
4536
+ * Get the token manager instance
4764
4537
  */
4765
- static set(instance, internals) {
4766
- this.store.set(instance, internals);
4538
+ getTokenManager() {
4539
+ return this.tokenManager;
4767
4540
  }
4768
4541
  /**
4769
- * Retrieve SDK instance internals
4770
- * Called by BaseService constructor
4542
+ * Authenticates the user based on the provided SDK configuration.
4543
+ * This method handles OAuth 2.0 authentication flow only.
4544
+ * For secret-based authentication, see authenticateWithSecret().
4545
+ * @param config The SDK configuration object.
4546
+ * @returns A promise that resolves to true if authentication is successful, otherwise false.
4547
+ * In an OAuth flow, this method will trigger a page redirect and the promise will not resolve.
4771
4548
  */
4772
- static get(instance) {
4773
- const internals = this.store.get(instance);
4774
- if (!internals) {
4775
- throw new Error('Invalid SDK instance. Make sure to pass a valid UiPath instance to the service constructor.');
4549
+ async authenticate(config) {
4550
+ if (!isBrowser) {
4551
+ return false;
4776
4552
  }
4777
- return internals;
4778
- }
4779
- }
4780
-
4781
- var _UiPath_config, _UiPath_authService, _UiPath_initialized;
4782
- /**
4783
- * UiPath - Core SDK class for authentication and configuration management.
4784
- *
4785
- * Handles authentication, configuration, and provides access to SDK internals
4786
- * for service instantiation in the modular pattern.
4787
- *
4788
- * @example
4789
- * ```typescript
4790
- * // Modular pattern
4791
- * import { UiPath } from '@uipath/uipath-typescript/core';
4792
- * import { Entities } from '@uipath/uipath-typescript/entities';
4793
- *
4794
- * const sdk = new UiPath({
4795
- * baseUrl: 'https://cloud.uipath.com',
4796
- * orgName: 'myorg',
4797
- * tenantName: 'mytenant',
4798
- * clientId: 'xxx',
4799
- * redirectUri: 'http://localhost:3000/callback',
4800
- * scope: 'OR.Users OR.Robots'
4801
- * });
4802
- *
4803
- * await sdk.initialize();
4804
- *
4805
- * const entitiesService = new Entities(sdk);
4806
- * const allEntities = await entitiesService.getAll();
4807
- * ```
4808
- */
4809
- class UiPath {
4810
- constructor(config) {
4811
- // Private fields - true runtime privacy, not visible via Object.keys()
4812
- _UiPath_config.set(this, void 0);
4813
- _UiPath_authService.set(this, void 0);
4814
- _UiPath_initialized.set(this, false);
4815
- // Validate and normalize the configuration
4816
- validateConfig(config);
4817
- const hasSecretAuth = hasSecretConfig(config);
4818
- const hasOAuthAuth = hasOAuthConfig(config);
4819
- // Initialize core components
4820
- const internalConfig = new UiPathConfig({
4821
- baseUrl: normalizeBaseUrl(config.baseUrl),
4822
- orgName: config.orgName,
4823
- tenantName: config.tenantName,
4824
- secret: hasSecretAuth ? config.secret : undefined,
4825
- clientId: hasOAuthAuth ? config.clientId : undefined,
4826
- redirectUri: hasOAuthAuth ? config.redirectUri : undefined,
4827
- scope: hasOAuthAuth ? config.scope : undefined
4828
- });
4829
- const executionContext = new ExecutionContext();
4830
- __classPrivateFieldSet(this, _UiPath_authService, new AuthService(internalConfig, executionContext), "f");
4831
- __classPrivateFieldSet(this, _UiPath_config, internalConfig, "f");
4832
- // Store internals in SDKInternalsRegistry (not visible on instance)
4833
- SDKInternalsRegistry.set(this, {
4834
- config: internalConfig,
4835
- context: executionContext,
4836
- tokenManager: __classPrivateFieldGet(this, _UiPath_authService, "f").getTokenManager()
4837
- });
4838
- // Expose read-only config for user convenience
4839
- this.config = {
4840
- baseUrl: internalConfig.baseUrl,
4841
- orgName: internalConfig.orgName,
4842
- tenantName: internalConfig.tenantName
4843
- };
4844
- // Initialize telemetry with SDK configuration
4845
- telemetryClient.initialize({
4846
- baseUrl: config.baseUrl,
4847
- orgName: config.orgName,
4848
- tenantName: config.tenantName,
4849
- clientId: hasOAuthAuth ? config.clientId : undefined,
4850
- redirectUri: hasOAuthAuth ? config.redirectUri : undefined
4851
- });
4852
- // Track SDK initialization
4853
- trackEvent('Sdk.Auth');
4854
- // Auto-initialize for secret-based auth
4855
- if (hasSecretAuth) {
4856
- __classPrivateFieldGet(this, _UiPath_authService, "f").authenticateWithSecret(config.secret);
4857
- __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
4553
+ // First priority: Complete OAuth callback if we detect it
4554
+ if (AuthService.isInOAuthCallback()) {
4555
+ const urlParams = new URLSearchParams(window.location.search);
4556
+ const code = urlParams.get('code');
4557
+ if (!code) {
4558
+ throw new Error('Authorization code missing in OAuth callback');
4559
+ }
4560
+ // Check if token already exists (prevents duplicate processing)
4561
+ if (this.tokenManager.hasValidToken()) {
4562
+ return true;
4563
+ }
4564
+ // Ensure we have OAuth config for callback completion
4565
+ if (!hasOAuthConfig(config)) {
4566
+ throw new Error('OAuth configuration incomplete: clientId, redirectUri, and scope are required for OAuth callback');
4567
+ }
4568
+ const result = await this._authenticateWithOAuth(config.clientId, config.redirectUri, config.scope);
4569
+ return result;
4570
+ }
4571
+ // Secondly: Try to load existing valid token from storage
4572
+ const loadedFromStorage = this.tokenManager.loadFromStorage();
4573
+ // If we have a valid token from storage, return true
4574
+ if (loadedFromStorage && this.tokenManager.hasValidToken()) {
4575
+ return true;
4576
+ }
4577
+ // Start new OAuth flow if config has OAuth fields
4578
+ if (hasOAuthConfig(config)) {
4579
+ return await this._authenticateWithOAuth(config.clientId, config.redirectUri, config.scope);
4858
4580
  }
4581
+ return false;
4859
4582
  }
4860
4583
  /**
4861
- * Initialize the SDK based on the provided configuration.
4862
- * This method handles both OAuth flow initiation and completion automatically.
4863
- * For secret-based authentication, initialization is automatic and this returns immediately.
4584
+ * Authenticate using OAuth flow
4864
4585
  */
4865
- async initialize() {
4866
- // For secret-based auth, it's already initialized in constructor
4867
- if (hasSecretConfig(__classPrivateFieldGet(this, _UiPath_config, "f"))) {
4868
- return;
4586
+ async _authenticateWithOAuth(clientId, redirectUri, scope) {
4587
+ if (!isBrowser) {
4588
+ throw new Error('OAuth flow is only supported in browser environments');
4869
4589
  }
4870
- try {
4871
- // Check for OAuth callback first
4872
- if (AuthService.isInOAuthCallback()) {
4873
- if (await this.completeOAuth()) {
4874
- return;
4875
- }
4876
- }
4877
- // Check if already authenticated
4878
- if (this.isAuthenticated()) {
4879
- __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
4880
- return;
4590
+ // Check if we have a stored code verifier indicating we're in an OAuth flow
4591
+ const codeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4592
+ const isInOAuthFlow = codeVerifier !== null;
4593
+ const urlParams = new URLSearchParams(window.location.search);
4594
+ const code = urlParams.get('code');
4595
+ // If we're in an OAuth flow (server-controlled code verifier exists), handle the callback
4596
+ if (isInOAuthFlow) {
4597
+ // We're expecting a callback - validate parameters
4598
+ if (!code) {
4599
+ // Clear stored state on error
4600
+ sessionStorage.removeItem('uipath_sdk_code_verifier');
4601
+ throw new Error('Authorization code missing in OAuth callback');
4881
4602
  }
4882
- // Start new OAuth flow
4883
- await __classPrivateFieldGet(this, _UiPath_authService, "f").authenticate(__classPrivateFieldGet(this, _UiPath_config, "f"));
4884
- if (this.isAuthenticated()) {
4885
- __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
4603
+ // Validate the authorization code format before using it
4604
+ // OAuth authorization codes should be alphanumeric with some special characters
4605
+ const codePattern = /^[A-Za-z0-9\-._~+/]+=*$/;
4606
+ if (!codePattern.test(code)) {
4607
+ // Clear stored state on error
4608
+ sessionStorage.removeItem('uipath_sdk_code_verifier');
4609
+ throw new Error('Invalid authorization code format');
4886
4610
  }
4611
+ // Authorization code is present and validated, so we can exchange it for a token.
4612
+ await this._handleOAuthCallback(code, clientId, redirectUri);
4613
+ return this.hasValidToken();
4614
+ }
4615
+ else {
4616
+ // Not in an OAuth flow - initiate one
4617
+ // Ignore any URL parameters that might be present
4618
+ await this._initiateOAuthFlow(clientId, redirectUri, scope);
4619
+ // This line is not expected to be reached due to redirect
4620
+ return false;
4621
+ }
4622
+ }
4623
+ /**
4624
+ * Authenticate using API secret
4625
+ */
4626
+ authenticateWithSecret(secret) {
4627
+ try {
4628
+ this.updateToken({ token: secret, type: 'secret' });
4629
+ return true;
4887
4630
  }
4888
4631
  catch (error) {
4889
- const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
4890
- throw new Error(`Failed to initialize UiPath SDK: ${errorMessage}`);
4632
+ console.error('Failed to authenticate with secret', error);
4633
+ return false;
4891
4634
  }
4892
4635
  }
4893
4636
  /**
4894
- * Check if the SDK has been initialized
4637
+ * Updates the access token used for API requests
4638
+ * @param tokenInfo The token information containing the access token, type, expiration, and refresh token
4895
4639
  */
4896
- isInitialized() {
4897
- return __classPrivateFieldGet(this, _UiPath_initialized, "f");
4640
+ updateToken(tokenInfo) {
4641
+ this.tokenManager.setToken(tokenInfo);
4898
4642
  }
4899
4643
  /**
4900
- * Check if we're in an OAuth callback state
4644
+ * Checks if the current token is valid
4901
4645
  */
4902
- isInOAuthCallback() {
4903
- return AuthService.isInOAuthCallback();
4646
+ hasValidToken() {
4647
+ return this.tokenManager.hasValidToken();
4648
+ }
4649
+ /**
4650
+ * Get the current token
4651
+ */
4652
+ getToken() {
4653
+ if (!this.tokenManager.hasValidToken()) {
4654
+ return undefined;
4655
+ }
4656
+ return this.tokenManager.getToken();
4657
+ }
4658
+ /**
4659
+ * Generates a random code verifier for PKCE
4660
+ */
4661
+ generateCodeVerifier() {
4662
+ if (isBrowser) {
4663
+ const array = new Uint8Array(32);
4664
+ crypto.getRandomValues(array);
4665
+ return this._base64URLEncode(array);
4666
+ }
4667
+ else {
4668
+ // In Node.js environment
4669
+ try {
4670
+ const crypto = require('crypto');
4671
+ return crypto.randomBytes(32)
4672
+ .toString('base64')
4673
+ .replace(/\+/g, '-')
4674
+ .replace(/\//g, '_')
4675
+ .replace(/=/g, '');
4676
+ }
4677
+ catch {
4678
+ throw new Error("crypto not available in browser");
4679
+ }
4680
+ }
4904
4681
  }
4905
4682
  /**
4906
- * Complete OAuth authentication flow (only call if isInOAuthCallback() is true)
4683
+ * Generates a code challenge from the code verifier
4907
4684
  */
4908
- async completeOAuth() {
4909
- if (!AuthService.isInOAuthCallback()) {
4910
- throw new Error('Not in OAuth callback state. Call initialize() first to start OAuth flow.');
4685
+ async generateCodeChallenge(codeVerifier) {
4686
+ if (isBrowser) {
4687
+ const encoder = new TextEncoder();
4688
+ const data = encoder.encode(codeVerifier);
4689
+ const hash = await crypto.subtle.digest('SHA-256', data);
4690
+ return this._base64URLEncode(new Uint8Array(hash));
4911
4691
  }
4912
- try {
4913
- const success = await __classPrivateFieldGet(this, _UiPath_authService, "f").authenticate(__classPrivateFieldGet(this, _UiPath_config, "f"));
4914
- if (success && this.isAuthenticated()) {
4915
- __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
4916
- return true;
4692
+ else {
4693
+ // In Node.js environment
4694
+ try {
4695
+ const crypto = require('crypto');
4696
+ return crypto.createHash('sha256')
4697
+ .update(codeVerifier)
4698
+ .digest('base64')
4699
+ .replace(/\+/g, '-')
4700
+ .replace(/\//g, '_')
4701
+ .replace(/=/g, '');
4702
+ }
4703
+ catch {
4704
+ throw new Error("crypto not available in browser");
4917
4705
  }
4918
- return false;
4919
- }
4920
- catch (error) {
4921
- const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
4922
- throw new Error(`Failed to complete OAuth: ${errorMessage}`);
4923
4706
  }
4924
4707
  }
4925
4708
  /**
4926
- * Check if the user is authenticated (has valid token)
4709
+ * Gets the authorization URL for the OAuth flow
4927
4710
  */
4928
- isAuthenticated() {
4929
- return __classPrivateFieldGet(this, _UiPath_authService, "f").hasValidToken();
4711
+ getAuthorizationUrl(params) {
4712
+ const orgName = this.config.orgName;
4713
+ const queryParams = new URLSearchParams({
4714
+ response_type: 'code',
4715
+ client_id: params.clientId,
4716
+ redirect_uri: params.redirectUri,
4717
+ code_challenge: params.codeChallenge,
4718
+ code_challenge_method: 'S256',
4719
+ scope: params.scope + ' offline_access',
4720
+ state: params.state || this.generateCodeVerifier().slice(0, 16)
4721
+ });
4722
+ return `${this.config.baseUrl}/${orgName}/${IDENTITY_ENDPOINTS.AUTHORIZE}?${queryParams.toString()}`;
4930
4723
  }
4931
4724
  /**
4932
- * Get the current authentication token
4725
+ * Exchanges the authorization code for an access token and automatically updates the current token
4933
4726
  */
4934
- getToken() {
4935
- return __classPrivateFieldGet(this, _UiPath_authService, "f").getToken();
4936
- }
4937
- }
4938
- _UiPath_config = new WeakMap(), _UiPath_authService = new WeakMap(), _UiPath_initialized = new WeakMap();
4939
-
4940
- /**
4941
- * Base error class for all UiPath SDK errors
4942
- * Pure TypeScript class with clean interface
4943
- */
4944
- class UiPathError {
4945
- constructor(type, params) {
4946
- this.type = type;
4947
- this.message = params.message;
4948
- this.statusCode = params.statusCode;
4949
- this.requestId = params.requestId;
4950
- this.timestamp = new Date();
4951
- // Capture stack trace for debugging
4952
- this.stack = (new Error()).stack;
4727
+ async _getAccessToken(params) {
4728
+ const orgName = this.config.orgName;
4729
+ const body = new URLSearchParams({
4730
+ grant_type: 'authorization_code',
4731
+ client_id: params.clientId,
4732
+ code: params.code,
4733
+ redirect_uri: params.redirectUri,
4734
+ code_verifier: params.codeVerifier
4735
+ });
4736
+ const response = await fetch(`${this.config.baseUrl}/${orgName}/${IDENTITY_ENDPOINTS.TOKEN}`, {
4737
+ method: 'POST',
4738
+ headers: {
4739
+ 'Content-Type': 'application/x-www-form-urlencoded'
4740
+ },
4741
+ body: body.toString()
4742
+ });
4743
+ if (!response.ok) {
4744
+ const errorData = await response.json().catch(() => ({ message: response.statusText }));
4745
+ console.error("OAuth error:", errorData);
4746
+ throw new Error(`Failed to get access token: ${JSON.stringify(errorData)}`);
4747
+ }
4748
+ const token = await response.json();
4749
+ this.updateToken({
4750
+ token: token.access_token,
4751
+ type: 'oauth',
4752
+ expiresAt: token.expires_in ? new Date(Date.now() + token.expires_in * 1000) : undefined,
4753
+ refreshToken: token.refresh_token
4754
+ });
4755
+ return token;
4953
4756
  }
4954
4757
  /**
4955
- * Returns a clean JSON representation of the error
4758
+ * Base64URL encodes an array buffer
4956
4759
  */
4957
- toJSON() {
4958
- return {
4959
- type: this.type,
4960
- message: this.message,
4961
- statusCode: this.statusCode,
4962
- requestId: this.requestId,
4963
- timestamp: this.timestamp
4964
- };
4760
+ _base64URLEncode(buffer) {
4761
+ const base64 = btoa(String.fromCharCode(...buffer));
4762
+ return base64
4763
+ .replace(/\+/g, '-')
4764
+ .replace(/\//g, '_')
4765
+ .replace(/=/g, '');
4965
4766
  }
4966
- /**
4967
- * Returns detailed debug information including stack trace
4968
- */
4969
- getDebugInfo() {
4970
- return {
4971
- ...this.toJSON(),
4972
- stack: this.stack
4767
+ async _initiateOAuthFlow(clientId, redirectUri, scope) {
4768
+ const codeVerifier = this.generateCodeVerifier();
4769
+ const codeChallenge = await this.generateCodeChallenge(codeVerifier);
4770
+ // Store complete OAuth context for callback completion
4771
+ const oauthContext = {
4772
+ codeVerifier,
4773
+ clientId,
4774
+ redirectUri,
4775
+ baseUrl: this.config.baseUrl,
4776
+ orgName: this.config.orgName,
4777
+ tenantName: this.config.tenantName,
4778
+ scope
4973
4779
  };
4974
- }
4975
- }
4976
-
4977
- /**
4978
- * HTTP status code constants for error handling
4979
- */
4980
- const HttpStatus = {
4981
- // Client errors (4xx)
4982
- BAD_REQUEST: 400,
4983
- UNAUTHORIZED: 401,
4984
- FORBIDDEN: 403,
4985
- NOT_FOUND: 404,
4986
- TOO_MANY_REQUESTS: 429,
4987
- // Server errors (5xx)
4988
- INTERNAL_SERVER_ERROR: 500,
4989
- NOT_IMPLEMENTED: 501,
4990
- BAD_GATEWAY: 502,
4991
- SERVICE_UNAVAILABLE: 503,
4992
- GATEWAY_TIMEOUT: 504
4993
- };
4994
- /**
4995
- * Error type constants for consistent error identification
4996
- */
4997
- const ErrorType = {
4998
- AUTHENTICATION: 'AuthenticationError',
4999
- AUTHORIZATION: 'AuthorizationError',
5000
- VALIDATION: 'ValidationError',
5001
- NOT_FOUND: 'NotFoundError',
5002
- RATE_LIMIT: 'RateLimitError',
5003
- SERVER: 'ServerError',
5004
- NETWORK: 'NetworkError'
5005
- };
5006
- /**
5007
- * Standard error message constants
5008
- */
5009
- const ErrorMessages = {
5010
- // Authentication errors
5011
- AUTHENTICATION_FAILED: 'Authentication failed',
5012
- // Authorization errors
5013
- ACCESS_DENIED: 'Access denied',
5014
- // Validation errors
5015
- VALIDATION_FAILED: 'Validation failed',
5016
- // Not found errors
5017
- RESOURCE_NOT_FOUND: 'Resource not found',
5018
- // Rate limit errors
5019
- RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
5020
- // Server errors
5021
- INTERNAL_SERVER_ERROR: 'Internal Server error occurred',
5022
- // Network errors
5023
- NETWORK_ERROR: 'Network error occurred'};
5024
-
5025
- /**
5026
- * Error thrown when authentication fails (401 errors)
5027
- * Common scenarios:
5028
- * - Invalid credentials
5029
- * - Expired token
5030
- * - Missing authentication
5031
- */
5032
- class AuthenticationError extends UiPathError {
5033
- constructor(params = {}) {
5034
- super(ErrorType.AUTHENTICATION, {
5035
- message: params.message || ErrorMessages.AUTHENTICATION_FAILED,
5036
- statusCode: params.statusCode ?? HttpStatus.UNAUTHORIZED,
5037
- requestId: params.requestId
4780
+ sessionStorage.setItem('uipath_sdk_oauth_context', JSON.stringify(oauthContext));
4781
+ sessionStorage.setItem('uipath_sdk_code_verifier', codeVerifier);
4782
+ const authUrl = this.getAuthorizationUrl({
4783
+ clientId,
4784
+ redirectUri,
4785
+ codeChallenge,
4786
+ scope
5038
4787
  });
4788
+ window.location.href = authUrl;
5039
4789
  }
5040
- }
5041
-
5042
- /**
5043
- * Error thrown when authorization fails (403 errors)
5044
- * Common scenarios:
5045
- * - Insufficient permissions
5046
- * - Access denied to resource
5047
- * - Invalid scope
5048
- */
5049
- class AuthorizationError extends UiPathError {
5050
- constructor(params = {}) {
5051
- super(ErrorType.AUTHORIZATION, {
5052
- message: params.message || ErrorMessages.ACCESS_DENIED,
5053
- statusCode: params.statusCode ?? HttpStatus.FORBIDDEN,
5054
- requestId: params.requestId
4790
+ async _handleOAuthCallback(code, clientId, redirectUri) {
4791
+ const codeVerifier = sessionStorage.getItem('uipath_sdk_code_verifier');
4792
+ if (!codeVerifier) {
4793
+ throw new Error('Code verifier not found in session storage. Authentication may have been interrupted.');
4794
+ }
4795
+ await this._getAccessToken({
4796
+ clientId,
4797
+ redirectUri,
4798
+ code,
4799
+ codeVerifier
5055
4800
  });
4801
+ // Clear OAuth context and code verifier after successful token exchange
4802
+ sessionStorage.removeItem('uipath_sdk_oauth_context');
4803
+ sessionStorage.removeItem('uipath_sdk_code_verifier');
4804
+ const url = new URL(window.location.href);
4805
+ url.searchParams.delete('code');
4806
+ url.searchParams.delete('state');
4807
+ window.history.replaceState({}, '', url.toString());
5056
4808
  }
5057
4809
  }
5058
4810
 
5059
- /**
5060
- * Error thrown when validation fails (400 errors or client-side validation)
5061
- * Common scenarios:
5062
- * - Invalid input parameters
5063
- * - Missing required fields
5064
- * - Invalid data format
5065
- */
5066
- class ValidationError extends UiPathError {
5067
- constructor(params = {}) {
5068
- super(ErrorType.VALIDATION, {
5069
- message: params.message || ErrorMessages.VALIDATION_FAILED,
5070
- statusCode: params.statusCode ?? HttpStatus.BAD_REQUEST,
5071
- requestId: params.requestId
5072
- });
4811
+ function validateConfig(config) {
4812
+ if (!config.baseUrl || !config.orgName || !config.tenantName) {
4813
+ throw new Error('Missing required configuration: baseUrl, orgName, and tenantName are required');
5073
4814
  }
4815
+ if (!hasSecretConfig(config) && !hasOAuthConfig(config)) {
4816
+ throw new Error('Invalid configuration: must provide either secret or (clientId, redirectUri, and scope)');
4817
+ }
4818
+ }
4819
+ function normalizeBaseUrl(url) {
4820
+ return url.endsWith('/') ? url.slice(0, -1) : url;
5074
4821
  }
5075
4822
 
5076
4823
  /**
5077
- * Error thrown when a resource is not found (404 errors)
5078
- * Common scenarios:
5079
- * - Resource doesn't exist
5080
- * - Invalid ID provided
5081
- * - Resource deleted
4824
+ * SDK Telemetry constants
5082
4825
  */
5083
- class NotFoundError extends UiPathError {
5084
- constructor(params = {}) {
5085
- super(ErrorType.NOT_FOUND, {
5086
- message: params.message || ErrorMessages.RESOURCE_NOT_FOUND,
5087
- statusCode: params.statusCode ?? HttpStatus.NOT_FOUND,
5088
- requestId: params.requestId
5089
- });
5090
- }
5091
- }
4826
+ // Connection string placeholder that will be replaced during build
4827
+ const CONNECTION_STRING = "InstrumentationKey=a6efa11d-1feb-4508-9738-e13e12dcae5e;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=7c58eb1c-9581-4ba6-839e-11725848a037";
4828
+ // SDK Version placeholder
4829
+ const SDK_VERSION = "1.1.0";
4830
+ const VERSION = "Version";
4831
+ const SERVICE = "Service";
4832
+ const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
4833
+ const CLOUD_TENANT_NAME = "CloudTenantName";
4834
+ const CLOUD_URL = "CloudUrl";
4835
+ const CLOUD_CLIENT_ID = "CloudClientId";
4836
+ const CLOUD_REDIRECT_URI = "CloudRedirectUri";
4837
+ const APP_NAME = "ApplicationName";
4838
+ const CLOUD_ROLE_NAME = "uipath-ts-sdk";
4839
+ // Service and logger names
4840
+ const SDK_SERVICE_NAME = "UiPath.TypeScript.Sdk";
4841
+ const SDK_LOGGER_NAME = "uipath-ts-sdk-telemetry";
4842
+ // Event names
4843
+ const SDK_RUN_EVENT = "Sdk.Run";
4844
+ // Default value for unknown/empty attributes
4845
+ const UNKNOWN = "";
5092
4846
 
5093
4847
  /**
5094
- * Error thrown when rate limit is exceeded (429 errors)
5095
- * Common scenarios:
5096
- * - Too many requests in a time window
5097
- * - API throttling
4848
+ * Log exporter that sends ALL logs as Application Insights custom events
5098
4849
  */
5099
- class RateLimitError extends UiPathError {
5100
- constructor(params = {}) {
5101
- super(ErrorType.RATE_LIMIT, {
5102
- message: params.message || ErrorMessages.RATE_LIMIT_EXCEEDED,
5103
- statusCode: params.statusCode ?? HttpStatus.TOO_MANY_REQUESTS,
5104
- requestId: params.requestId
4850
+ class ApplicationInsightsEventExporter {
4851
+ constructor(connectionString) {
4852
+ this.connectionString = connectionString;
4853
+ }
4854
+ export(logs, resultCallback) {
4855
+ try {
4856
+ logs.forEach(logRecord => {
4857
+ this.sendAsCustomEvent(logRecord);
4858
+ });
4859
+ resultCallback({ code: 0 });
4860
+ }
4861
+ catch (error) {
4862
+ console.debug('Failed to export logs to Application Insights:', error);
4863
+ resultCallback({ code: 2, error });
4864
+ }
4865
+ }
4866
+ shutdown() {
4867
+ return Promise.resolve();
4868
+ }
4869
+ sendAsCustomEvent(logRecord) {
4870
+ // Get event name from body or attributes
4871
+ const eventName = logRecord.body || SDK_RUN_EVENT;
4872
+ const payload = {
4873
+ name: 'Microsoft.ApplicationInsights.Event',
4874
+ time: new Date().toISOString(),
4875
+ iKey: this.extractInstrumentationKey(),
4876
+ data: {
4877
+ baseType: 'EventData',
4878
+ baseData: {
4879
+ ver: 2,
4880
+ name: eventName,
4881
+ properties: this.convertAttributesToProperties(logRecord.attributes || {})
4882
+ }
4883
+ },
4884
+ tags: {
4885
+ 'ai.cloud.role': CLOUD_ROLE_NAME,
4886
+ 'ai.cloud.roleInstance': SDK_VERSION
4887
+ }
4888
+ };
4889
+ this.sendToApplicationInsights(payload);
4890
+ }
4891
+ extractInstrumentationKey() {
4892
+ const match = this.connectionString.match(/InstrumentationKey=([^;]+)/);
4893
+ return match ? match[1] : '';
4894
+ }
4895
+ convertAttributesToProperties(attributes) {
4896
+ const properties = {};
4897
+ Object.entries(attributes || {}).forEach(([key, value]) => {
4898
+ properties[key] = String(value);
5105
4899
  });
4900
+ return properties;
4901
+ }
4902
+ async sendToApplicationInsights(payload) {
4903
+ try {
4904
+ const ingestionEndpoint = this.extractIngestionEndpoint();
4905
+ if (!ingestionEndpoint) {
4906
+ console.debug('No ingestion endpoint found in connection string');
4907
+ return;
4908
+ }
4909
+ const url = `${ingestionEndpoint}/v2/track`;
4910
+ const response = await fetch(url, {
4911
+ method: 'POST',
4912
+ headers: {
4913
+ 'Content-Type': 'application/json',
4914
+ },
4915
+ body: JSON.stringify(payload)
4916
+ });
4917
+ if (!response.ok) {
4918
+ console.debug(`Failed to send event telemetry: ${response.status} ${response.statusText}`);
4919
+ }
4920
+ }
4921
+ catch (error) {
4922
+ console.debug('Error sending event telemetry to Application Insights:', error);
4923
+ }
4924
+ }
4925
+ extractIngestionEndpoint() {
4926
+ const match = this.connectionString.match(/IngestionEndpoint=([^;]+)/);
4927
+ return match ? match[1] : '';
5106
4928
  }
5107
4929
  }
5108
-
5109
4930
  /**
5110
- * Error thrown when server encounters an error (5xx errors)
5111
- * Common scenarios:
5112
- * - Internal server error
5113
- * - Service unavailable
5114
- * - Gateway timeout
4931
+ * Singleton telemetry client
5115
4932
  */
5116
- class ServerError extends UiPathError {
5117
- constructor(params = {}) {
5118
- super(ErrorType.SERVER, {
5119
- message: params.message || ErrorMessages.INTERNAL_SERVER_ERROR,
5120
- statusCode: params.statusCode ?? HttpStatus.INTERNAL_SERVER_ERROR,
5121
- requestId: params.requestId
5122
- });
4933
+ class TelemetryClient {
4934
+ constructor() {
4935
+ this.isInitialized = false;
4936
+ }
4937
+ static getInstance() {
4938
+ if (!TelemetryClient.instance) {
4939
+ TelemetryClient.instance = new TelemetryClient();
4940
+ }
4941
+ return TelemetryClient.instance;
5123
4942
  }
5124
4943
  /**
5125
- * Checks if this is a temporary error that might succeed on retry
4944
+ * Initialize telemetry
5126
4945
  */
5127
- get isRetryable() {
5128
- return this.statusCode === HttpStatus.BAD_GATEWAY ||
5129
- this.statusCode === HttpStatus.SERVICE_UNAVAILABLE ||
5130
- this.statusCode === HttpStatus.GATEWAY_TIMEOUT;
4946
+ initialize(config) {
4947
+ if (this.isInitialized) {
4948
+ return;
4949
+ }
4950
+ this.isInitialized = true;
4951
+ if (config) {
4952
+ this.telemetryContext = config;
4953
+ }
4954
+ try {
4955
+ const connectionString = this.getConnectionString();
4956
+ if (!connectionString) {
4957
+ return;
4958
+ }
4959
+ this.setupTelemetryProvider(connectionString);
4960
+ }
4961
+ catch (error) {
4962
+ // Silent failure - telemetry errors shouldn't break functionality
4963
+ console.debug('Failed to initialize OpenTelemetry:', error);
4964
+ }
5131
4965
  }
5132
- }
5133
-
5134
- /**
5135
- * Error thrown when network/connection issues occur
5136
- * Common scenarios:
5137
- * - Connection timeout
5138
- * - DNS resolution failure
5139
- * - Network unreachable
5140
- * - Request aborted
5141
- */
5142
- class NetworkError extends UiPathError {
5143
- constructor(params = {}) {
5144
- super(ErrorType.NETWORK, {
5145
- message: params.message || ErrorMessages.NETWORK_ERROR,
5146
- statusCode: params.statusCode, // Network errors typically don't have HTTP status codes
5147
- requestId: params.requestId
4966
+ getConnectionString() {
4967
+ const connectionString = CONNECTION_STRING;
4968
+ return connectionString;
4969
+ }
4970
+ setupTelemetryProvider(connectionString) {
4971
+ const exporter = new ApplicationInsightsEventExporter(connectionString);
4972
+ const processor = new sdkLogs.BatchLogRecordProcessor(exporter);
4973
+ this.logProvider = new sdkLogs.LoggerProvider({
4974
+ processors: [processor]
5148
4975
  });
4976
+ this.logger = this.logProvider.getLogger(SDK_LOGGER_NAME);
4977
+ }
4978
+ /**
4979
+ * Track a telemetry event
4980
+ */
4981
+ track(eventName, name, extraAttributes = {}) {
4982
+ try {
4983
+ // Skip if logger not initialized
4984
+ if (!this.logger) {
4985
+ return;
4986
+ }
4987
+ const finalDisplayName = name || eventName;
4988
+ const attributes = this.getEnrichedAttributes(extraAttributes, eventName);
4989
+ // Emit as log
4990
+ this.logger.emit({
4991
+ body: finalDisplayName,
4992
+ attributes: attributes,
4993
+ timestamp: Date.now(),
4994
+ });
4995
+ }
4996
+ catch (error) {
4997
+ // Silent failure
4998
+ console.debug('Failed to track telemetry event:', error);
4999
+ }
5000
+ }
5001
+ /**
5002
+ * Get enriched attributes for telemetry events
5003
+ */
5004
+ getEnrichedAttributes(extraAttributes, eventName) {
5005
+ const attributes = {
5006
+ [APP_NAME]: SDK_SERVICE_NAME,
5007
+ [VERSION]: SDK_VERSION,
5008
+ [SERVICE]: eventName,
5009
+ [CLOUD_URL]: this.createCloudUrl(),
5010
+ [CLOUD_ORGANIZATION_NAME]: this.telemetryContext?.orgName || UNKNOWN,
5011
+ [CLOUD_TENANT_NAME]: this.telemetryContext?.tenantName || UNKNOWN,
5012
+ [CLOUD_REDIRECT_URI]: this.telemetryContext?.redirectUri || UNKNOWN,
5013
+ [CLOUD_CLIENT_ID]: this.telemetryContext?.clientId || UNKNOWN,
5014
+ ...extraAttributes,
5015
+ };
5016
+ return attributes;
5017
+ }
5018
+ /**
5019
+ * Create cloud URL from base URL, organization ID, and tenant ID
5020
+ */
5021
+ createCloudUrl() {
5022
+ const baseUrl = this.telemetryContext?.baseUrl;
5023
+ const orgId = this.telemetryContext?.orgName;
5024
+ const tenantId = this.telemetryContext?.tenantName;
5025
+ if (!baseUrl || !orgId || !tenantId) {
5026
+ return UNKNOWN;
5027
+ }
5028
+ return `${baseUrl}/${orgId}/${tenantId}`;
5149
5029
  }
5150
5030
  }
5151
-
5152
- /**
5153
- * Type guard to check if an error is a UiPathError
5154
- */
5155
- function isUiPathError(error) {
5156
- return error instanceof UiPathError;
5157
- }
5158
- /**
5159
- * Type guard to check if an error is an AuthenticationError
5160
- */
5161
- function isAuthenticationError(error) {
5162
- return error instanceof AuthenticationError;
5163
- }
5164
- /**
5165
- * Type guard to check if an error is an AuthorizationError
5166
- */
5167
- function isAuthorizationError(error) {
5168
- return error instanceof AuthorizationError;
5169
- }
5170
- /**
5171
- * Type guard to check if an error is a ValidationError
5172
- */
5173
- function isValidationError(error) {
5174
- return error instanceof ValidationError;
5175
- }
5031
+ // Export singleton instance
5032
+ const telemetryClient = TelemetryClient.getInstance();
5033
+
5176
5034
  /**
5177
- * Type guard to check if an error is a NotFoundError
5035
+ * SDK Track decorator and function for telemetry
5178
5036
  */
5179
- function isNotFoundError(error) {
5180
- return error instanceof NotFoundError;
5181
- }
5182
5037
  /**
5183
- * Type guard to check if an error is a RateLimitError
5038
+ * Direct tracking function
5184
5039
  */
5185
- function isRateLimitError(error) {
5186
- return error instanceof RateLimitError;
5040
+ function trackEvent(eventName, name, attributes) {
5041
+ telemetryClient.track(eventName, name, attributes);
5187
5042
  }
5043
+
5188
5044
  /**
5189
- * Type guard to check if an error is a ServerError
5045
+ * SDK Internals Registry - Internal registry for SDK instances
5046
+ *
5047
+ * This class is NOT exported in the public API.
5048
+ * It provides a secure way to share SDK internals between
5049
+ * the UiPath class and service classes without exposing them publicly.
5050
+ *
5051
+ * @internal
5190
5052
  */
5191
- function isServerError(error) {
5192
- return error instanceof ServerError;
5193
- }
5053
+ // Global symbol key to ensure WeakMap is shared across module instances
5054
+ // This prevents issues when core and service modules are bundled separately
5055
+ const REGISTRY_KEY = Symbol.for('@uipath/sdk-internals-registry');
5056
+ // Get or create the global WeakMap store
5057
+ const getGlobalStore = () => {
5058
+ const globalObj = globalThis;
5059
+ if (!globalObj[REGISTRY_KEY]) {
5060
+ globalObj[REGISTRY_KEY] = new WeakMap();
5061
+ }
5062
+ return globalObj[REGISTRY_KEY];
5063
+ };
5194
5064
  /**
5195
- * Type guard to check if an error is a NetworkError
5065
+ * Internal registry for SDK private components.
5066
+ * Uses WeakMap to prevent memory leaks - entries are automatically
5067
+ * garbage collected when the SDK instance is no longer referenced.
5068
+ *
5069
+ * Uses a global singleton pattern to ensure the same WeakMap is shared
5070
+ * across separately bundled modules (core, entities, tasks, etc.).
5071
+ *
5072
+ * @internal - Not exported in public API
5196
5073
  */
5197
- function isNetworkError(error) {
5198
- return error instanceof NetworkError;
5074
+ class SDKInternalsRegistry {
5075
+ // Use global store to ensure sharing across module bundles
5076
+ static get store() {
5077
+ return getGlobalStore();
5078
+ }
5079
+ /**
5080
+ * Register SDK instance internals
5081
+ * Called by UiPath constructor
5082
+ */
5083
+ static set(instance, internals) {
5084
+ this.store.set(instance, internals);
5085
+ }
5086
+ /**
5087
+ * Retrieve SDK instance internals
5088
+ * Called by BaseService constructor
5089
+ */
5090
+ static get(instance) {
5091
+ const internals = this.store.get(instance);
5092
+ if (!internals) {
5093
+ throw new Error('Invalid SDK instance. Make sure to pass a valid UiPath instance to the service constructor.');
5094
+ }
5095
+ return internals;
5096
+ }
5199
5097
  }
5098
+
5099
+ var _UiPath_config, _UiPath_authService, _UiPath_initialized;
5200
5100
  /**
5201
- * Helper to get error details in a safe way
5101
+ * UiPath - Core SDK class for authentication and configuration management.
5102
+ *
5103
+ * Handles authentication, configuration, and provides access to SDK internals
5104
+ * for service instantiation in the modular pattern.
5105
+ *
5106
+ * @example
5107
+ * ```typescript
5108
+ * // Modular pattern
5109
+ * import { UiPath } from '@uipath/uipath-typescript/core';
5110
+ * import { Entities } from '@uipath/uipath-typescript/entities';
5111
+ *
5112
+ * const sdk = new UiPath({
5113
+ * baseUrl: 'https://cloud.uipath.com',
5114
+ * orgName: 'myorg',
5115
+ * tenantName: 'mytenant',
5116
+ * clientId: 'xxx',
5117
+ * redirectUri: 'http://localhost:3000/callback',
5118
+ * scope: 'OR.Users OR.Robots'
5119
+ * });
5120
+ *
5121
+ * await sdk.initialize();
5122
+ *
5123
+ * const entitiesService = new Entities(sdk);
5124
+ * const allEntities = await entitiesService.getAll();
5125
+ * ```
5202
5126
  */
5203
- function getErrorDetails(error) {
5204
- if (isUiPathError(error)) {
5205
- return {
5206
- message: error.message,
5207
- statusCode: error.statusCode
5127
+ class UiPath {
5128
+ constructor(config) {
5129
+ // Private fields - true runtime privacy, not visible via Object.keys()
5130
+ _UiPath_config.set(this, void 0);
5131
+ _UiPath_authService.set(this, void 0);
5132
+ _UiPath_initialized.set(this, false);
5133
+ // Validate and normalize the configuration
5134
+ validateConfig(config);
5135
+ const hasSecretAuth = hasSecretConfig(config);
5136
+ const hasOAuthAuth = hasOAuthConfig(config);
5137
+ // Initialize core components
5138
+ const internalConfig = new UiPathConfig({
5139
+ baseUrl: normalizeBaseUrl(config.baseUrl),
5140
+ orgName: config.orgName,
5141
+ tenantName: config.tenantName,
5142
+ secret: hasSecretAuth ? config.secret : undefined,
5143
+ clientId: hasOAuthAuth ? config.clientId : undefined,
5144
+ redirectUri: hasOAuthAuth ? config.redirectUri : undefined,
5145
+ scope: hasOAuthAuth ? config.scope : undefined
5146
+ });
5147
+ const executionContext = new ExecutionContext();
5148
+ __classPrivateFieldSet(this, _UiPath_authService, new AuthService(internalConfig, executionContext), "f");
5149
+ __classPrivateFieldSet(this, _UiPath_config, internalConfig, "f");
5150
+ // Store internals in SDKInternalsRegistry (not visible on instance)
5151
+ SDKInternalsRegistry.set(this, {
5152
+ config: internalConfig,
5153
+ context: executionContext,
5154
+ tokenManager: __classPrivateFieldGet(this, _UiPath_authService, "f").getTokenManager()
5155
+ });
5156
+ // Expose read-only config for user convenience
5157
+ this.config = {
5158
+ baseUrl: internalConfig.baseUrl,
5159
+ orgName: internalConfig.orgName,
5160
+ tenantName: internalConfig.tenantName
5208
5161
  };
5162
+ // Initialize telemetry with SDK configuration
5163
+ telemetryClient.initialize({
5164
+ baseUrl: config.baseUrl,
5165
+ orgName: config.orgName,
5166
+ tenantName: config.tenantName,
5167
+ clientId: hasOAuthAuth ? config.clientId : undefined,
5168
+ redirectUri: hasOAuthAuth ? config.redirectUri : undefined
5169
+ });
5170
+ // Track SDK initialization
5171
+ trackEvent('Sdk.Auth');
5172
+ // Auto-initialize for secret-based auth
5173
+ if (hasSecretAuth) {
5174
+ __classPrivateFieldGet(this, _UiPath_authService, "f").authenticateWithSecret(config.secret);
5175
+ __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5176
+ }
5209
5177
  }
5210
- if (error instanceof Error) {
5211
- return {
5212
- message: error.message
5213
- };
5178
+ /**
5179
+ * Initialize the SDK based on the provided configuration.
5180
+ * This method handles both OAuth flow initiation and completion automatically.
5181
+ * For secret-based authentication, initialization is automatic and this returns immediately.
5182
+ */
5183
+ async initialize() {
5184
+ // For secret-based auth, it's already initialized in constructor
5185
+ if (hasSecretConfig(__classPrivateFieldGet(this, _UiPath_config, "f"))) {
5186
+ return;
5187
+ }
5188
+ try {
5189
+ // Check for OAuth callback first
5190
+ if (AuthService.isInOAuthCallback()) {
5191
+ if (await this.completeOAuth()) {
5192
+ return;
5193
+ }
5194
+ }
5195
+ // Check if already authenticated
5196
+ if (this.isAuthenticated()) {
5197
+ __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5198
+ return;
5199
+ }
5200
+ // Start new OAuth flow
5201
+ await __classPrivateFieldGet(this, _UiPath_authService, "f").authenticate(__classPrivateFieldGet(this, _UiPath_config, "f"));
5202
+ if (this.isAuthenticated()) {
5203
+ __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5204
+ }
5205
+ }
5206
+ catch (error) {
5207
+ const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
5208
+ throw new Error(`Failed to initialize UiPath SDK: ${errorMessage}`);
5209
+ }
5210
+ }
5211
+ /**
5212
+ * Check if the SDK has been initialized
5213
+ */
5214
+ isInitialized() {
5215
+ return __classPrivateFieldGet(this, _UiPath_initialized, "f");
5216
+ }
5217
+ /**
5218
+ * Check if we're in an OAuth callback state
5219
+ */
5220
+ isInOAuthCallback() {
5221
+ return AuthService.isInOAuthCallback();
5222
+ }
5223
+ /**
5224
+ * Complete OAuth authentication flow (only call if isInOAuthCallback() is true)
5225
+ */
5226
+ async completeOAuth() {
5227
+ if (!AuthService.isInOAuthCallback()) {
5228
+ throw new Error('Not in OAuth callback state. Call initialize() first to start OAuth flow.');
5229
+ }
5230
+ try {
5231
+ const success = await __classPrivateFieldGet(this, _UiPath_authService, "f").authenticate(__classPrivateFieldGet(this, _UiPath_config, "f"));
5232
+ if (success && this.isAuthenticated()) {
5233
+ __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5234
+ return true;
5235
+ }
5236
+ return false;
5237
+ }
5238
+ catch (error) {
5239
+ const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
5240
+ throw new Error(`Failed to complete OAuth: ${errorMessage}`);
5241
+ }
5242
+ }
5243
+ /**
5244
+ * Check if the user is authenticated (has valid token)
5245
+ */
5246
+ isAuthenticated() {
5247
+ return __classPrivateFieldGet(this, _UiPath_authService, "f").hasValidToken();
5248
+ }
5249
+ /**
5250
+ * Get the current authentication token
5251
+ */
5252
+ getToken() {
5253
+ return __classPrivateFieldGet(this, _UiPath_authService, "f").getToken();
5214
5254
  }
5215
- return {
5216
- message: String(error)
5217
- };
5218
5255
  }
5256
+ _UiPath_config = new WeakMap(), _UiPath_authService = new WeakMap(), _UiPath_initialized = new WeakMap();
5219
5257
 
5220
5258
  /**
5221
5259
  * Constants used throughout the pagination system