@uipath/uipath-typescript 1.1.1 → 1.1.3

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.
@@ -3876,6 +3876,7 @@ class ExecutionContext {
3876
3876
  * Checks if code is running in a browser environment
3877
3877
  */
3878
3878
  const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
3879
+ const isInActionCenter = isBrowser && window.self != window.top && window.location.href.includes('source=ActionCenter');
3879
3880
 
3880
3881
  /**
3881
3882
  * Session storage keys used by the auth module
@@ -4178,6 +4179,102 @@ function getErrorDetails(error) {
4178
4179
  };
4179
4180
  }
4180
4181
 
4182
+ var ActionCenterEventNames;
4183
+ (function (ActionCenterEventNames) {
4184
+ ActionCenterEventNames["TOKENREFRESHED"] = "AC.tokenRefreshed";
4185
+ ActionCenterEventNames["REFRESHTOKEN"] = "AC.refreshToken";
4186
+ })(ActionCenterEventNames || (ActionCenterEventNames = {}));
4187
+
4188
+ const AUTHENTICATION_TIMEOUT = 8000;
4189
+ class ActionCenterTokenManager {
4190
+ constructor(config, onTokenRefreshed) {
4191
+ this.config = config;
4192
+ this.onTokenRefreshed = onTokenRefreshed;
4193
+ this.parentOrigin = new URLSearchParams(window.location.search).get('basedomain');
4194
+ this.refreshPromise = null;
4195
+ }
4196
+ async refreshAccessToken(tokenInfo) {
4197
+ if (!this.isTokenExpired(tokenInfo)) {
4198
+ return tokenInfo.token;
4199
+ }
4200
+ if (this.refreshPromise) {
4201
+ return this.refreshPromise;
4202
+ }
4203
+ this.refreshPromise = new Promise((resolve, reject) => {
4204
+ const content = {
4205
+ clientId: this.config.clientId,
4206
+ scope: this.config.scope,
4207
+ };
4208
+ this.sendMessageToParent(ActionCenterEventNames.REFRESHTOKEN, content);
4209
+ const messageListener = (event) => {
4210
+ if (event.origin !== this.parentOrigin)
4211
+ return;
4212
+ if (event.data?.eventType !== ActionCenterEventNames.TOKENREFRESHED)
4213
+ return;
4214
+ clearTimeout(timer);
4215
+ if (event.data?.content?.token) {
4216
+ const { accessToken, expiresAt } = event.data.content.token;
4217
+ this.onTokenRefreshed({ token: accessToken, type: 'secret', expiresAt });
4218
+ resolve(accessToken);
4219
+ }
4220
+ else {
4221
+ reject(new AuthenticationError({
4222
+ message: 'Failed to fetch access token',
4223
+ statusCode: HttpStatus.UNAUTHORIZED,
4224
+ }));
4225
+ }
4226
+ this.refreshPromise = null;
4227
+ this.cleanup(messageListener);
4228
+ };
4229
+ const timer = setTimeout(() => {
4230
+ reject(new AuthenticationError({
4231
+ message: 'Failed to fetch access token',
4232
+ statusCode: HttpStatus.UNAUTHORIZED,
4233
+ }));
4234
+ this.refreshPromise = null;
4235
+ this.cleanup(messageListener);
4236
+ }, AUTHENTICATION_TIMEOUT);
4237
+ window.addEventListener('message', messageListener);
4238
+ });
4239
+ return this.refreshPromise;
4240
+ }
4241
+ isTokenExpired(tokenInfo) {
4242
+ if (!tokenInfo?.expiresAt) {
4243
+ return true;
4244
+ }
4245
+ return new Date() >= tokenInfo.expiresAt;
4246
+ }
4247
+ sendMessageToParent(eventType, content) {
4248
+ if (window.parent && this.isValidOrigin(this.parentOrigin)) {
4249
+ try {
4250
+ window.parent.postMessage({ eventType, content }, this.parentOrigin);
4251
+ }
4252
+ catch (error) {
4253
+ console.warn('Failed to send message to Action Center', JSON.stringify(error));
4254
+ }
4255
+ }
4256
+ }
4257
+ cleanup(messageListener) {
4258
+ window.removeEventListener('message', messageListener);
4259
+ }
4260
+ isValidOrigin(origin) {
4261
+ const ALLOWED_ORIGINS = ['https://alpha.uipath.com', 'https://staging.uipath.com', 'https://cloud.uipath.com'];
4262
+ if (!origin) {
4263
+ return false;
4264
+ }
4265
+ if (ALLOWED_ORIGINS.includes(origin)) {
4266
+ return true;
4267
+ }
4268
+ try {
4269
+ const url = new URL(origin);
4270
+ return url.hostname === 'localhost';
4271
+ }
4272
+ catch {
4273
+ return false;
4274
+ }
4275
+ }
4276
+ }
4277
+
4181
4278
  /**
4182
4279
  * TokenManager is responsible for managing authentication tokens.
4183
4280
  * It provides token operations for a specific client ID.
@@ -4196,6 +4293,11 @@ class TokenManager {
4196
4293
  this.config = config;
4197
4294
  this.isOAuth = isOAuth;
4198
4295
  this.refreshPromise = null;
4296
+ this.actionCenterTokenManager = null;
4297
+ if (isInActionCenter) {
4298
+ this.actionCenterTokenManager = new ActionCenterTokenManager(config, (tokenInfo) => this.setToken(tokenInfo));
4299
+ this.isOAuth = false;
4300
+ }
4199
4301
  }
4200
4302
  /**
4201
4303
  * Checks if a token is expired
@@ -4223,6 +4325,9 @@ class TokenManager {
4223
4325
  message: 'No authentication token available. Make sure to initialize the SDK first.'
4224
4326
  });
4225
4327
  }
4328
+ if (this.actionCenterTokenManager) {
4329
+ return await this.actionCenterTokenManager.refreshAccessToken(tokenInfo);
4330
+ }
4226
4331
  // For secret-based tokens, they never expire
4227
4332
  if (tokenInfo.type === 'secret') {
4228
4333
  return tokenInfo.token;
@@ -4367,9 +4472,6 @@ class TokenManager {
4367
4472
  clearToken() {
4368
4473
  this.currentToken = undefined;
4369
4474
  this.executionContext.set('tokenInfo', undefined);
4370
- const headers = this.executionContext.getHeaders();
4371
- delete headers['Authorization'];
4372
- this.executionContext.setHeaders(headers);
4373
4475
  // Remove from session storage if this is an OAuth token
4374
4476
  if (isBrowser && this.isOAuth) {
4375
4477
  try {
@@ -4385,10 +4487,6 @@ class TokenManager {
4385
4487
  */
4386
4488
  _updateExecutionContext(tokenInfo) {
4387
4489
  this.executionContext.set('tokenInfo', tokenInfo);
4388
- // Update authorization header
4389
- this.executionContext.setHeaders({
4390
- 'Authorization': `Bearer ${tokenInfo.token}`
4391
- });
4392
4490
  }
4393
4491
  /**
4394
4492
  * Refreshes the access token using the stored refresh token.
@@ -4476,8 +4574,15 @@ const IDENTITY_ENDPOINTS = {
4476
4574
 
4477
4575
  class AuthService {
4478
4576
  constructor(config, executionContext) {
4479
- // Check if we should use stored OAuth context instead of provided config
4480
- const storedContext = AuthService.getStoredOAuthContext();
4577
+ // Only use stored OAuth context when completing an active callback (URL has ?code=).
4578
+ // If stored context exists but we're NOT in a callback, it's stale from a
4579
+ // failed/abandoned flow (e.g. scope mismatch, invalid redirect URI) and must
4580
+ // be cleared so the fresh config takes effect.
4581
+ const isCallback = AuthService.isInOAuthCallback();
4582
+ const storedContext = isCallback ? AuthService.getStoredOAuthContext() : null;
4583
+ if (!isCallback) {
4584
+ AuthService._clearStoredOAuthContext();
4585
+ }
4481
4586
  const effectiveConfig = storedContext ? AuthService._mergeConfigWithContext(config, storedContext) : config;
4482
4587
  this.config = effectiveConfig;
4483
4588
  const isOAuth = hasOAuthConfig(effectiveConfig);
@@ -4524,6 +4629,22 @@ class AuthService {
4524
4629
  return null;
4525
4630
  }
4526
4631
  }
4632
+ /**
4633
+ * Clear stale OAuth context from session storage.
4634
+ * Called when there is no active OAuth callback, meaning any stored context
4635
+ * is left over from a failed or abandoned flow.
4636
+ */
4637
+ static _clearStoredOAuthContext() {
4638
+ if (!isBrowser)
4639
+ return;
4640
+ try {
4641
+ sessionStorage.removeItem(AUTH_STORAGE_KEYS.OAUTH_CONTEXT);
4642
+ sessionStorage.removeItem(AUTH_STORAGE_KEYS.CODE_VERIFIER);
4643
+ }
4644
+ catch {
4645
+ // Ignore storage errors
4646
+ }
4647
+ }
4527
4648
  /**
4528
4649
  * Merges provided config with stored OAuth context, prioritizing stored values
4529
4650
  */
@@ -4832,14 +4953,42 @@ class AuthService {
4832
4953
  }
4833
4954
  }
4834
4955
 
4956
+ /**
4957
+ * Check if config has all required base fields
4958
+ */
4959
+ function hasRequiredBaseFields(config) {
4960
+ return Boolean(config.baseUrl && config.orgName && config.tenantName);
4961
+ }
4962
+ /**
4963
+ * Check if config has exactly one authentication method (secret XOR oauth)
4964
+ * Returns true if exactly one auth method is present, false otherwise
4965
+ */
4966
+ function hasValidAuthConfig(config) {
4967
+ const hasSecret = hasSecretConfig(config);
4968
+ const hasOAuth = hasOAuthConfig(config);
4969
+ // XOR: exactly one auth method, not both, not neither
4970
+ return hasSecret !== hasOAuth;
4971
+ }
4835
4972
  function validateConfig(config) {
4836
- if (!config.baseUrl || !config.orgName || !config.tenantName) {
4973
+ if (!hasRequiredBaseFields(config)) {
4837
4974
  throw new Error('Missing required configuration: baseUrl, orgName, and tenantName are required');
4838
4975
  }
4839
- if (!hasSecretConfig(config) && !hasOAuthConfig(config)) {
4840
- throw new Error('Invalid configuration: must provide either secret or (clientId, redirectUri, and scope)');
4976
+ const hasSecret = hasSecretConfig(config);
4977
+ const hasOAuth = hasOAuthConfig(config);
4978
+ if (hasSecret && hasOAuth) {
4979
+ throw new Error('Invalid configuration: cannot provide both secret and OAuth credentials. Choose one authentication method.');
4980
+ }
4981
+ if (!hasSecret && !hasOAuth) {
4982
+ throw new Error('Invalid configuration: must provide either secret or OAuth credentials (clientId, redirectUri, and scope)');
4841
4983
  }
4842
4984
  }
4985
+ /**
4986
+ * Check if partial config has all required fields for a complete SDK config
4987
+ * Requires base fields and exactly one authentication method (secret XOR oauth)
4988
+ */
4989
+ function isCompleteConfig(config) {
4990
+ return hasRequiredBaseFields(config) && hasValidAuthConfig(config);
4991
+ }
4843
4992
  function normalizeBaseUrl(url) {
4844
4993
  return url.endsWith('/') ? url.slice(0, -1) : url;
4845
4994
  }
@@ -4850,7 +4999,7 @@ function normalizeBaseUrl(url) {
4850
4999
  // Connection string placeholder that will be replaced during build
4851
5000
  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";
4852
5001
  // SDK Version placeholder
4853
- const SDK_VERSION = "1.1.1";
5002
+ const SDK_VERSION = "1.1.3";
4854
5003
  const VERSION = "Version";
4855
5004
  const SERVICE = "Service";
4856
5005
  const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
@@ -5179,19 +5328,71 @@ class SDKInternalsRegistry {
5179
5328
  }
5180
5329
  }
5181
5330
 
5182
- var _UiPath_config, _UiPath_authService, _UiPath_initialized;
5331
+ /**
5332
+ * UiPath meta tag names for runtime configuration.
5333
+ *
5334
+ * These meta tags are injected at deployment time by the Apps Service
5335
+ * to configure SDK authentication and asset resolution in production.
5336
+ */
5337
+ var UiPathMetaTags;
5338
+ (function (UiPathMetaTags) {
5339
+ // SDK/OAuth configuration
5340
+ UiPathMetaTags["CLIENT_ID"] = "uipath:client-id";
5341
+ UiPathMetaTags["SCOPE"] = "uipath:scope";
5342
+ UiPathMetaTags["ORG_NAME"] = "uipath:org-name";
5343
+ UiPathMetaTags["TENANT_NAME"] = "uipath:tenant-name";
5344
+ UiPathMetaTags["BASE_URL"] = "uipath:base-url";
5345
+ UiPathMetaTags["REDIRECT_URI"] = "uipath:redirect-uri";
5346
+ // Asset resolution and routing
5347
+ UiPathMetaTags["CDN_BASE"] = "uipath:cdn-base";
5348
+ UiPathMetaTags["APP_BASE"] = "uipath:app-base";
5349
+ })(UiPathMetaTags || (UiPathMetaTags = {}));
5350
+
5351
+ /**
5352
+ * Get the content of a meta tag by name.
5353
+ * Returns undefined if not in browser environment or meta tag is not found.
5354
+ */
5355
+ function getMetaTagContent(name) {
5356
+ if (!isBrowser)
5357
+ return undefined;
5358
+ return document.querySelector(`meta[name="${name}"]`)?.content;
5359
+ }
5360
+ /**
5361
+ * Load configuration from HTML meta tags injected at runtime.
5362
+ * These meta tags are injected by @uipath/coded-apps during build
5363
+ * or by the Apps service during deployment.
5364
+ *
5365
+ * Returns partial config with values found, or null if no meta tags present.
5366
+ */
5367
+ function loadFromMetaTags() {
5368
+ if (!isBrowser)
5369
+ return null;
5370
+ const config = {
5371
+ clientId: getMetaTagContent(UiPathMetaTags.CLIENT_ID),
5372
+ scope: getMetaTagContent(UiPathMetaTags.SCOPE),
5373
+ orgName: getMetaTagContent(UiPathMetaTags.ORG_NAME),
5374
+ tenantName: getMetaTagContent(UiPathMetaTags.TENANT_NAME),
5375
+ baseUrl: getMetaTagContent(UiPathMetaTags.BASE_URL),
5376
+ redirectUri: getMetaTagContent(UiPathMetaTags.REDIRECT_URI),
5377
+ };
5378
+ const hasAnyValue = Object.values(config).some(Boolean);
5379
+ return hasAnyValue ? config : null;
5380
+ }
5381
+
5382
+ var _UiPath_instances, _UiPath_config, _UiPath_authService, _UiPath_initialized, _UiPath_partialConfig, _UiPath_initializeWithConfig, _UiPath_loadConfig;
5183
5383
  /**
5184
5384
  * UiPath - Core SDK class for authentication and configuration management.
5185
5385
  *
5186
5386
  * Handles authentication, configuration, and provides access to SDK internals
5187
5387
  * for service instantiation in the modular pattern.
5188
5388
  *
5389
+ * Supports two usage patterns:
5390
+ * 1. Full config in constructor — for server-side or explicit configuration
5391
+ * 2. No config / partial config — loads from meta tags injected by @uipath/coded-apps plugin
5392
+ *
5189
5393
  * @example
5190
5394
  * ```typescript
5191
- * // Modular pattern
5192
- * import { UiPath } from '@uipath/uipath-typescript/core';
5193
- * import { Entities } from '@uipath/uipath-typescript/entities';
5194
- *
5395
+ * // Explicit config
5195
5396
  * const sdk = new UiPath({
5196
5397
  * baseUrl: 'https://cloud.uipath.com',
5197
5398
  * orgName: 'myorg',
@@ -5200,70 +5401,47 @@ var _UiPath_config, _UiPath_authService, _UiPath_initialized;
5200
5401
  * redirectUri: 'http://localhost:3000/callback',
5201
5402
  * scope: 'OR.Users OR.Robots'
5202
5403
  * });
5203
- *
5204
5404
  * await sdk.initialize();
5405
+ * ```
5205
5406
  *
5206
- * const entitiesService = new Entities(sdk);
5207
- * const allEntities = await entitiesService.getAll();
5407
+ * @example
5408
+ * ```typescript
5409
+ * // Auto-load from meta tags (coded apps)
5410
+ * const sdk = new UiPath();
5411
+ * await sdk.initialize();
5208
5412
  * ```
5209
5413
  */
5210
5414
  class UiPath {
5211
5415
  constructor(config) {
5416
+ _UiPath_instances.add(this);
5212
5417
  // Private fields - true runtime privacy, not visible via Object.keys()
5213
5418
  _UiPath_config.set(this, void 0);
5214
5419
  _UiPath_authService.set(this, void 0);
5215
5420
  _UiPath_initialized.set(this, false);
5216
- // Validate and normalize the configuration
5217
- validateConfig(config);
5218
- const hasSecretAuth = hasSecretConfig(config);
5219
- const hasOAuthAuth = hasOAuthConfig(config);
5220
- // Initialize core components
5221
- const internalConfig = new UiPathConfig({
5222
- baseUrl: normalizeBaseUrl(config.baseUrl),
5223
- orgName: config.orgName,
5224
- tenantName: config.tenantName,
5225
- secret: hasSecretAuth ? config.secret : undefined,
5226
- clientId: hasOAuthAuth ? config.clientId : undefined,
5227
- redirectUri: hasOAuthAuth ? config.redirectUri : undefined,
5228
- scope: hasOAuthAuth ? config.scope : undefined
5229
- });
5230
- const executionContext = new ExecutionContext();
5231
- __classPrivateFieldSet(this, _UiPath_authService, new AuthService(internalConfig, executionContext), "f");
5232
- __classPrivateFieldSet(this, _UiPath_config, internalConfig, "f");
5233
- // Store internals in SDKInternalsRegistry (not visible on instance)
5234
- SDKInternalsRegistry.set(this, {
5235
- config: internalConfig,
5236
- context: executionContext,
5237
- tokenManager: __classPrivateFieldGet(this, _UiPath_authService, "f").getTokenManager()
5238
- });
5239
- // Expose read-only config for user convenience
5240
- this.config = {
5241
- baseUrl: internalConfig.baseUrl,
5242
- orgName: internalConfig.orgName,
5243
- tenantName: internalConfig.tenantName
5244
- };
5245
- // Initialize telemetry with SDK configuration
5246
- telemetryClient.initialize({
5247
- baseUrl: config.baseUrl,
5248
- orgName: config.orgName,
5249
- tenantName: config.tenantName,
5250
- clientId: hasOAuthAuth ? config.clientId : undefined,
5251
- redirectUri: hasOAuthAuth ? config.redirectUri : undefined
5252
- });
5253
- // Track SDK initialization
5254
- trackEvent('Sdk.Auth');
5255
- // Auto-initialize for secret-based auth
5256
- if (hasSecretAuth) {
5257
- __classPrivateFieldGet(this, _UiPath_authService, "f").authenticateWithSecret(config.secret);
5258
- __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5421
+ _UiPath_partialConfig.set(this, void 0);
5422
+ // Load configuration from meta tags
5423
+ const configFromMetaTags = loadFromMetaTags();
5424
+ // Merge configuration: constructor config overrides meta tags
5425
+ const mergedConfig = config ? { ...configFromMetaTags, ...config } : configFromMetaTags;
5426
+ if (mergedConfig && isCompleteConfig(mergedConfig)) {
5427
+ __classPrivateFieldGet(this, _UiPath_instances, "m", _UiPath_initializeWithConfig).call(this, mergedConfig);
5428
+ }
5429
+ else if (config) {
5430
+ __classPrivateFieldSet(this, _UiPath_partialConfig, config, "f");
5259
5431
  }
5260
5432
  }
5261
5433
  /**
5262
5434
  * Initialize the SDK based on the provided configuration.
5263
5435
  * This method handles both OAuth flow initiation and completion automatically.
5264
5436
  * For secret-based authentication, initialization is automatic and this returns immediately.
5437
+ * If no config was provided in constructor, loads from meta tags.
5265
5438
  */
5266
5439
  async initialize() {
5440
+ // Load config from meta tags if not provided in constructor
5441
+ if (!__classPrivateFieldGet(this, _UiPath_config, "f")) {
5442
+ const loadedConfig = __classPrivateFieldGet(this, _UiPath_instances, "m", _UiPath_loadConfig).call(this);
5443
+ __classPrivateFieldGet(this, _UiPath_instances, "m", _UiPath_initializeWithConfig).call(this, loadedConfig);
5444
+ }
5267
5445
  // For secret-based auth, it's already initialized in constructor
5268
5446
  if (hasSecretConfig(__classPrivateFieldGet(this, _UiPath_config, "f"))) {
5269
5447
  return;
@@ -5310,6 +5488,11 @@ class UiPath {
5310
5488
  if (!AuthService.isInOAuthCallback()) {
5311
5489
  throw new Error('Not in OAuth callback state. Call initialize() first to start OAuth flow.');
5312
5490
  }
5491
+ // Load config if not yet initialized
5492
+ if (!__classPrivateFieldGet(this, _UiPath_config, "f")) {
5493
+ const loadedConfig = __classPrivateFieldGet(this, _UiPath_instances, "m", _UiPath_loadConfig).call(this);
5494
+ __classPrivateFieldGet(this, _UiPath_instances, "m", _UiPath_initializeWithConfig).call(this, loadedConfig);
5495
+ }
5313
5496
  try {
5314
5497
  const success = await __classPrivateFieldGet(this, _UiPath_authService, "f").authenticate(__classPrivateFieldGet(this, _UiPath_config, "f"));
5315
5498
  if (success && this.isAuthenticated()) {
@@ -5327,13 +5510,13 @@ class UiPath {
5327
5510
  * Check if the user is authenticated (has valid token)
5328
5511
  */
5329
5512
  isAuthenticated() {
5330
- return __classPrivateFieldGet(this, _UiPath_authService, "f").hasValidToken();
5513
+ return __classPrivateFieldGet(this, _UiPath_authService, "f")?.hasValidToken() ?? false;
5331
5514
  }
5332
5515
  /**
5333
5516
  * Get the current authentication token
5334
5517
  */
5335
5518
  getToken() {
5336
- return __classPrivateFieldGet(this, _UiPath_authService, "f").getToken();
5519
+ return __classPrivateFieldGet(this, _UiPath_authService, "f")?.getToken();
5337
5520
  }
5338
5521
  /**
5339
5522
  * Logout from the SDK, clearing all authentication state.
@@ -5341,14 +5524,71 @@ class UiPath {
5341
5524
  */
5342
5525
  logout() {
5343
5526
  // Secret-based auth has no session to end — skip silently
5344
- if (hasSecretConfig(__classPrivateFieldGet(this, _UiPath_config, "f"))) {
5527
+ if (__classPrivateFieldGet(this, _UiPath_config, "f") && hasSecretConfig(__classPrivateFieldGet(this, _UiPath_config, "f"))) {
5345
5528
  return;
5346
5529
  }
5347
- __classPrivateFieldGet(this, _UiPath_authService, "f").logout();
5530
+ __classPrivateFieldGet(this, _UiPath_authService, "f")?.logout();
5348
5531
  __classPrivateFieldSet(this, _UiPath_initialized, false, "f");
5349
5532
  }
5350
5533
  }
5351
- _UiPath_config = new WeakMap(), _UiPath_authService = new WeakMap(), _UiPath_initialized = new WeakMap();
5534
+ _UiPath_config = new WeakMap(), _UiPath_authService = new WeakMap(), _UiPath_initialized = new WeakMap(), _UiPath_partialConfig = new WeakMap(), _UiPath_instances = new WeakSet(), _UiPath_initializeWithConfig = function _UiPath_initializeWithConfig(config) {
5535
+ // Validate and normalize the configuration
5536
+ validateConfig(config);
5537
+ const hasSecretAuth = hasSecretConfig(config);
5538
+ const hasOAuthAuth = hasOAuthConfig(config);
5539
+ // Initialize core components
5540
+ const internalConfig = new UiPathConfig({
5541
+ baseUrl: normalizeBaseUrl(config.baseUrl),
5542
+ orgName: config.orgName,
5543
+ tenantName: config.tenantName,
5544
+ secret: hasSecretAuth ? config.secret : undefined,
5545
+ clientId: hasOAuthAuth ? config.clientId : undefined,
5546
+ redirectUri: hasOAuthAuth ? config.redirectUri : undefined,
5547
+ scope: hasOAuthAuth ? config.scope : undefined
5548
+ });
5549
+ const executionContext = new ExecutionContext();
5550
+ __classPrivateFieldSet(this, _UiPath_authService, new AuthService(internalConfig, executionContext), "f");
5551
+ __classPrivateFieldSet(this, _UiPath_config, internalConfig, "f");
5552
+ // Store internals in SDKInternalsRegistry (not visible on instance)
5553
+ SDKInternalsRegistry.set(this, {
5554
+ config: internalConfig,
5555
+ context: executionContext,
5556
+ tokenManager: __classPrivateFieldGet(this, _UiPath_authService, "f").getTokenManager()
5557
+ });
5558
+ // Expose read-only config for user convenience
5559
+ this.config = {
5560
+ baseUrl: internalConfig.baseUrl,
5561
+ orgName: internalConfig.orgName,
5562
+ tenantName: internalConfig.tenantName
5563
+ };
5564
+ // Initialize telemetry with SDK configuration
5565
+ telemetryClient.initialize({
5566
+ baseUrl: config.baseUrl,
5567
+ orgName: config.orgName,
5568
+ tenantName: config.tenantName,
5569
+ clientId: hasOAuthAuth ? config.clientId : undefined,
5570
+ redirectUri: hasOAuthAuth ? config.redirectUri : undefined
5571
+ });
5572
+ // Track SDK initialization
5573
+ trackEvent('Sdk.Auth');
5574
+ /** Auto-initialize for secret-based auth
5575
+ * When viewed in Action Center, initialize tokenInfo with empty token. When an sdk call is made Action Center passes the token to sdk.
5576
+ */
5577
+ if (hasSecretAuth || isInActionCenter) {
5578
+ __classPrivateFieldGet(this, _UiPath_authService, "f").authenticateWithSecret(config.secret ?? '');
5579
+ __classPrivateFieldSet(this, _UiPath_initialized, true, "f");
5580
+ }
5581
+ }, _UiPath_loadConfig = function _UiPath_loadConfig() {
5582
+ // Load from meta tags
5583
+ const metaConfig = loadFromMetaTags();
5584
+ // Merge with any partial config from constructor (constructor overrides meta tags)
5585
+ const merged = { ...metaConfig, ...__classPrivateFieldGet(this, _UiPath_partialConfig, "f") };
5586
+ if (!isCompleteConfig(merged)) {
5587
+ throw new Error('UiPath SDK configuration not found. ' +
5588
+ 'Ensure @uipath/coded-apps plugin is set up in your bundler to inject configuration during development and build.');
5589
+ }
5590
+ return merged;
5591
+ };
5352
5592
 
5353
5593
  /**
5354
5594
  * Constants used throughout the pagination system
@@ -548,15 +548,6 @@ class ApiClient {
548
548
  async getDefaultHeaders() {
549
549
  // Get headers from execution context first
550
550
  const contextHeaders = this.executionContext.getHeaders();
551
- // If Authorization header is already set in context, use that
552
- if (contextHeaders['Authorization']) {
553
- return {
554
- ...contextHeaders,
555
- 'Content-Type': CONTENT_TYPES.JSON,
556
- ...this.defaultHeaders,
557
- ...this.clientConfig.headers
558
- };
559
- }
560
551
  const token = await this.getValidToken();
561
552
  return {
562
553
  ...contextHeaders,
@@ -571,8 +562,13 @@ class ApiClient {
571
562
  const normalizedPath = path.startsWith('/') ? path.substring(1) : path;
572
563
  // Construct URL with org and tenant names
573
564
  const url = new URL(`${this.config.orgName}/${this.config.tenantName}/${normalizedPath}`, this.config.baseUrl).toString();
565
+ const isFormData = options.body instanceof FormData;
566
+ const defaultHeaders = await this.getDefaultHeaders();
567
+ if (isFormData) {
568
+ delete defaultHeaders['Content-Type'];
569
+ }
574
570
  const headers = {
575
- ...await this.getDefaultHeaders(),
571
+ ...defaultHeaders,
576
572
  ...options.headers
577
573
  };
578
574
  // Convert params to URLSearchParams
@@ -583,11 +579,15 @@ class ApiClient {
583
579
  });
584
580
  }
585
581
  const fullUrl = searchParams.toString() ? `${url}?${searchParams.toString()}` : url;
582
+ let body = undefined;
583
+ if (options.body) {
584
+ body = isFormData ? options.body : JSON.stringify(options.body);
585
+ }
586
586
  try {
587
587
  const response = await fetch(fullUrl, {
588
588
  method,
589
589
  headers,
590
- body: options.body ? JSON.stringify(options.body) : undefined,
590
+ body,
591
591
  signal: options.signal
592
592
  });
593
593
  if (!response.ok) {
@@ -683,6 +683,7 @@ function filterUndefined(obj) {
683
683
  * Checks if code is running in a browser environment
684
684
  */
685
685
  const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
686
+ isBrowser && window.self != window.top && window.location.href.includes('source=ActionCenter');
686
687
 
687
688
  /**
688
689
  * Base64 encoding/decoding
@@ -1682,6 +1683,17 @@ function createEntityMethods(entityData, service) {
1682
1683
  fieldName
1683
1684
  });
1684
1685
  },
1686
+ async uploadAttachment(recordId, fieldName, file, expansionLevel) {
1687
+ if (!entityData.name)
1688
+ throw new Error('Entity name is undefined');
1689
+ return service.uploadAttachment({
1690
+ entityName: entityData.name,
1691
+ recordId,
1692
+ fieldName,
1693
+ file,
1694
+ expansionLevel
1695
+ });
1696
+ },
1685
1697
  async insert(data, options) {
1686
1698
  return this.insertRecord(data, options);
1687
1699
  },
@@ -1733,6 +1745,7 @@ const DATA_FABRIC_ENDPOINTS = {
1733
1745
  UPDATE_BY_ID: (entityId) => `${DATAFABRIC_BASE}/api/EntityService/entity/${entityId}/update-batch`,
1734
1746
  DELETE_BY_ID: (entityId) => `${DATAFABRIC_BASE}/api/EntityService/entity/${entityId}/delete-batch`,
1735
1747
  DOWNLOAD_ATTACHMENT: (entityName, recordId, fieldName) => `${DATAFABRIC_BASE}/api/Attachment/${entityName}/${recordId}/${fieldName}`,
1748
+ UPLOAD_ATTACHMENT: (entityName, recordId, fieldName) => `${DATAFABRIC_BASE}/api/Attachment/${entityName}/${recordId}/${fieldName}`,
1736
1749
  },
1737
1750
  CHOICESETS: {
1738
1751
  GET_ALL: `${DATAFABRIC_BASE}/api/Entity/choiceset`,
@@ -1889,7 +1902,7 @@ const EntityFieldTypeMap = {
1889
1902
  // Connection string placeholder that will be replaced during build
1890
1903
  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";
1891
1904
  // SDK Version placeholder
1892
- const SDK_VERSION = "1.1.1";
1905
+ const SDK_VERSION = "1.1.3";
1893
1906
  const VERSION = "Version";
1894
1907
  const SERVICE = "Service";
1895
1908
  const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
@@ -2488,6 +2501,42 @@ class EntityService extends BaseService {
2488
2501
  });
2489
2502
  return response.data;
2490
2503
  }
2504
+ /**
2505
+ * Uploads an attachment to a File-type field of an entity record
2506
+ *
2507
+ * @param options - Options containing entityName, recordId, fieldName, file, and optional expansionLevel
2508
+ * @returns Promise resolving to the upload response
2509
+ *
2510
+ * @example
2511
+ * ```typescript
2512
+ * import { Entities } from '@uipath/uipath-typescript/entities';
2513
+ *
2514
+ * const entities = new Entities(sdk);
2515
+ *
2516
+ * // Upload a file attachment
2517
+ * const response = await entities.uploadAttachment({
2518
+ * entityName: 'Invoice',
2519
+ * recordId: '<record-uuid>',
2520
+ * fieldName: 'Documents',
2521
+ * file: file
2522
+ * });
2523
+ * ```
2524
+ */
2525
+ async uploadAttachment(options) {
2526
+ const { entityName, recordId, fieldName, file, expansionLevel } = options;
2527
+ const formData = new FormData();
2528
+ if (file instanceof Uint8Array) {
2529
+ formData.append('file', new Blob([file.buffer]));
2530
+ }
2531
+ else {
2532
+ formData.append('file', file);
2533
+ }
2534
+ const params = createParams({ expansionLevel });
2535
+ const response = await this.post(DATA_FABRIC_ENDPOINTS.ENTITY.UPLOAD_ATTACHMENT(entityName, recordId, fieldName), formData, { params });
2536
+ // Convert PascalCase response to camelCase
2537
+ const camelResponse = pascalToCamelCaseKeys(response.data);
2538
+ return camelResponse;
2539
+ }
2491
2540
  /**
2492
2541
  * @hidden
2493
2542
  * @deprecated Use {@link getAllRecords} instead.
@@ -2621,6 +2670,9 @@ __decorate([
2621
2670
  __decorate([
2622
2671
  track('Entities.DownloadAttachment')
2623
2672
  ], EntityService.prototype, "downloadAttachment", null);
2673
+ __decorate([
2674
+ track('Entities.UploadAttachment')
2675
+ ], EntityService.prototype, "uploadAttachment", null);
2624
2676
 
2625
2677
  class ChoiceSetService extends BaseService {
2626
2678
  /**