@uipath/uipath-typescript 1.2.1 → 1.3.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.
Files changed (40) hide show
  1. package/dist/assets/index.cjs +1 -1
  2. package/dist/assets/index.d.ts +2 -1
  3. package/dist/assets/index.mjs +1 -1
  4. package/dist/attachments/index.cjs +1944 -0
  5. package/dist/attachments/index.d.ts +399 -0
  6. package/dist/attachments/index.mjs +1941 -0
  7. package/dist/buckets/index.cjs +1 -1
  8. package/dist/buckets/index.d.ts +4 -2
  9. package/dist/buckets/index.mjs +1 -1
  10. package/dist/cases/index.cjs +95 -48
  11. package/dist/cases/index.d.ts +31 -2
  12. package/dist/cases/index.mjs +95 -48
  13. package/dist/conversational-agent/index.cjs +1 -1
  14. package/dist/conversational-agent/index.d.ts +10 -5
  15. package/dist/conversational-agent/index.mjs +1 -1
  16. package/dist/core/index.cjs +109 -17
  17. package/dist/core/index.d.ts +1 -1
  18. package/dist/core/index.mjs +109 -17
  19. package/dist/entities/index.cjs +11 -27
  20. package/dist/entities/index.d.ts +38 -26
  21. package/dist/entities/index.mjs +11 -27
  22. package/dist/index.cjs +683 -284
  23. package/dist/index.d.ts +549 -75
  24. package/dist/index.mjs +683 -285
  25. package/dist/index.umd.js +680 -281
  26. package/dist/jobs/index.cjs +2264 -0
  27. package/dist/jobs/index.d.ts +860 -0
  28. package/dist/jobs/index.mjs +2260 -0
  29. package/dist/maestro-processes/index.cjs +1 -1
  30. package/dist/maestro-processes/index.mjs +1 -1
  31. package/dist/processes/index.cjs +67 -1
  32. package/dist/processes/index.d.ts +80 -15
  33. package/dist/processes/index.mjs +68 -2
  34. package/dist/queues/index.cjs +1 -1
  35. package/dist/queues/index.d.ts +2 -1
  36. package/dist/queues/index.mjs +1 -1
  37. package/dist/tasks/index.cjs +1319 -1272
  38. package/dist/tasks/index.d.ts +331 -287
  39. package/dist/tasks/index.mjs +1319 -1272
  40. package/package.json +23 -2
@@ -45,31 +45,43 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
45
45
  };
46
46
 
47
47
  /**
48
- * Type guards for error response types
48
+ * Base error class for all UiPath SDK errors
49
+ * Extends Error for standard error handling compatibility
49
50
  */
50
- function isOrchestratorError(error) {
51
- return typeof error === 'object' &&
52
- error !== null &&
53
- 'message' in error &&
54
- 'errorCode' in error &&
55
- typeof error.message === 'string' &&
56
- typeof error.errorCode === 'number';
57
- }
58
- function isEntityError(error) {
59
- return typeof error === 'object' &&
60
- error !== null &&
61
- 'error' in error &&
62
- typeof error.error === 'string';
63
- }
64
- function isPimsError(error) {
65
- return typeof error === 'object' &&
66
- error !== null &&
67
- 'type' in error &&
68
- 'title' in error &&
69
- 'status' in error &&
70
- typeof error.type === 'string' &&
71
- typeof error.title === 'string' &&
72
- typeof error.status === 'number';
51
+ class UiPathError extends Error {
52
+ constructor(type, params) {
53
+ super(params.message);
54
+ this.name = type;
55
+ this.type = type;
56
+ this.statusCode = params.statusCode;
57
+ this.requestId = params.requestId;
58
+ this.timestamp = new Date();
59
+ // Maintains proper stack trace for where our error was thrown
60
+ if (Error.captureStackTrace) {
61
+ Error.captureStackTrace(this, this.constructor);
62
+ }
63
+ }
64
+ /**
65
+ * Returns a clean JSON representation of the error
66
+ */
67
+ toJSON() {
68
+ return {
69
+ type: this.type,
70
+ message: this.message,
71
+ statusCode: this.statusCode,
72
+ requestId: this.requestId,
73
+ timestamp: this.timestamp
74
+ };
75
+ }
76
+ /**
77
+ * Returns detailed debug information including stack trace
78
+ */
79
+ getDebugInfo() {
80
+ return {
81
+ ...this.toJSON(),
82
+ stack: this.stack
83
+ };
84
+ }
73
85
  }
74
86
 
75
87
  /**
@@ -133,196 +145,6 @@ const ErrorMessages = {
133
145
  const ErrorNames = {
134
146
  ABORT_ERROR: 'AbortError'};
135
147
 
136
- /**
137
- * Parser for Orchestrator/Task error format
138
- */
139
- class OrchestratorErrorParser {
140
- canParse(errorBody) {
141
- return isOrchestratorError(errorBody);
142
- }
143
- parse(errorBody, response) {
144
- const error = errorBody;
145
- return {
146
- message: error.message,
147
- code: response?.status?.toString(),
148
- details: {
149
- errorCode: error.errorCode,
150
- traceId: error.traceId,
151
- originalResponse: error
152
- },
153
- requestId: error.traceId
154
- };
155
- }
156
- }
157
- /**
158
- * Parser for Entity (Data Fabric) error format
159
- */
160
- class EntityErrorParser {
161
- canParse(errorBody) {
162
- return isEntityError(errorBody);
163
- }
164
- parse(errorBody, response) {
165
- const error = errorBody;
166
- return {
167
- message: error.error,
168
- code: response?.status?.toString(),
169
- details: {
170
- error: error.error,
171
- traceId: error.traceId,
172
- originalResponse: error
173
- },
174
- requestId: error.traceId
175
- };
176
- }
177
- }
178
- /**
179
- * Parser for PIMS error format
180
- */
181
- class PimsErrorParser {
182
- canParse(errorBody) {
183
- return isPimsError(errorBody);
184
- }
185
- parse(errorBody, response) {
186
- const error = errorBody;
187
- let message = error.title;
188
- // If there are validation errors, append them to the message for better visibility
189
- if (error.errors && Object.keys(error.errors).length > 0) {
190
- const errorMessages = Object.entries(error.errors)
191
- .map(([field, messages]) => `${field}: ${messages.join(', ')}`)
192
- .join('; ');
193
- message += `. Validation errors: ${errorMessages}`;
194
- }
195
- return {
196
- message,
197
- code: response?.status?.toString(),
198
- details: {
199
- type: error.type,
200
- title: error.title,
201
- status: error.status,
202
- errors: error.errors,
203
- traceId: error.traceId,
204
- originalResponse: error
205
- },
206
- requestId: error.traceId
207
- };
208
- }
209
- }
210
- /**
211
- * Fallback parser for unrecognized formats
212
- */
213
- class GenericErrorParser {
214
- canParse(_errorBody) {
215
- return true; // Always can parse as last resort
216
- }
217
- parse(errorBody, response) {
218
- // For unknown error formats, just pass through the raw error with fallback message
219
- const message = response?.statusText || 'An error occurred';
220
- return {
221
- message,
222
- code: response?.status?.toString(),
223
- details: {
224
- originalResponse: errorBody
225
- },
226
- };
227
- }
228
- }
229
- /**
230
- * Main error response parser using Chain of Responsibility pattern
231
- *
232
- * This parser standardizes error responses from different UiPath services into a
233
- * consistent format, regardless of the original error structure.
234
- *
235
- * Supported formats:
236
- * 1. Orchestrator/Task: { message, errorCode, traceId }
237
- * 2. Entity (Data Fabric): { error, traceId }
238
- * 3. PIMS/Maestro: { type, title, status, errors?, traceId? }
239
- * 4. Generic: Fallback for any other format
240
- *
241
- * @example
242
- * const parser = new ErrorResponseParser();
243
- * const errorInfo = await parser.parse(response);
244
- * // errorInfo will have consistent structure regardless of service
245
- */
246
- class ErrorResponseParser {
247
- constructor() {
248
- this.strategies = [
249
- new OrchestratorErrorParser(),
250
- new EntityErrorParser(),
251
- new PimsErrorParser(),
252
- new GenericErrorParser() // Must be last
253
- ];
254
- }
255
- /**
256
- * Parses error response body into standardized format
257
- * @param response - The HTTP response object
258
- * @returns Standardized error information
259
- */
260
- async parse(response) {
261
- try {
262
- const errorBody = await response.json();
263
- // Find the first strategy that can parse this error format
264
- const strategy = this.strategies.find(s => s.canParse(errorBody));
265
- // GenericErrorParser always returns true, so this will never be null
266
- return strategy.parse(errorBody, response);
267
- }
268
- catch {
269
- // Handle non-JSON responses
270
- const responseText = await response.text().catch(() => '');
271
- return {
272
- message: response.statusText,
273
- code: response.status.toString(),
274
- details: {
275
- parseError: 'Failed to parse error response as JSON',
276
- responseText
277
- },
278
- requestId: response.headers.get(HttpHeaders.X_REQUEST_ID) || undefined
279
- };
280
- }
281
- }
282
- }
283
- // Export singleton instance
284
- const errorResponseParser = new ErrorResponseParser();
285
-
286
- /**
287
- * Base error class for all UiPath SDK errors
288
- * Extends Error for standard error handling compatibility
289
- */
290
- class UiPathError extends Error {
291
- constructor(type, params) {
292
- super(params.message);
293
- this.name = type;
294
- this.type = type;
295
- this.statusCode = params.statusCode;
296
- this.requestId = params.requestId;
297
- this.timestamp = new Date();
298
- // Maintains proper stack trace for where our error was thrown
299
- if (Error.captureStackTrace) {
300
- Error.captureStackTrace(this, this.constructor);
301
- }
302
- }
303
- /**
304
- * Returns a clean JSON representation of the error
305
- */
306
- toJSON() {
307
- return {
308
- type: this.type,
309
- message: this.message,
310
- statusCode: this.statusCode,
311
- requestId: this.requestId,
312
- timestamp: this.timestamp
313
- };
314
- }
315
- /**
316
- * Returns detailed debug information including stack trace
317
- */
318
- getDebugInfo() {
319
- return {
320
- ...this.toJSON(),
321
- stack: this.stack
322
- };
323
- }
324
- }
325
-
326
148
  /**
327
149
  * Error thrown when authentication fails (401 errors)
328
150
  * Common scenarios:
@@ -451,414 +273,469 @@ class NetworkError extends UiPathError {
451
273
  }
452
274
 
453
275
  /**
454
- * Factory for creating typed errors based on HTTP status codes
455
- * Follows the Factory pattern for clean error instantiation
276
+ * SDK Telemetry constants
456
277
  */
457
- class ErrorFactory {
458
- /**
459
- * Creates appropriate error instance based on HTTP status code
460
- */
461
- static createFromHttpStatus(statusCode, errorInfo) {
462
- const { message, requestId } = errorInfo;
463
- // Map status codes to error types
464
- switch (statusCode) {
465
- case HttpStatus.BAD_REQUEST:
466
- return new ValidationError({ message, statusCode, requestId });
467
- case HttpStatus.UNAUTHORIZED:
468
- return new AuthenticationError({ message, statusCode, requestId });
469
- case HttpStatus.FORBIDDEN:
470
- return new AuthorizationError({ message, statusCode, requestId });
471
- case HttpStatus.NOT_FOUND:
472
- return new NotFoundError({ message, statusCode, requestId });
473
- case HttpStatus.TOO_MANY_REQUESTS:
474
- return new RateLimitError({ message, statusCode, requestId });
475
- default:
476
- // For 5xx errors or any other status code
477
- if (statusCode >= HttpStatus.INTERNAL_SERVER_ERROR) {
478
- return new ServerError({ message, statusCode, requestId });
479
- }
480
- // For unknown client errors, treat as validation error
481
- return new ValidationError({
482
- message: `${message} (HTTP ${statusCode})`,
483
- statusCode,
484
- requestId
485
- });
278
+ // Connection string placeholder that will be replaced during build
279
+ 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";
280
+ // SDK Version placeholder
281
+ const SDK_VERSION = "1.3.0";
282
+ const VERSION = "Version";
283
+ const SERVICE = "Service";
284
+ const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
285
+ const CLOUD_TENANT_NAME = "CloudTenantName";
286
+ const CLOUD_URL = "CloudUrl";
287
+ const CLOUD_CLIENT_ID = "CloudClientId";
288
+ const CLOUD_REDIRECT_URI = "CloudRedirectUri";
289
+ const APP_NAME = "ApplicationName";
290
+ const CLOUD_ROLE_NAME = "uipath-ts-sdk";
291
+ // Service and logger names
292
+ const SDK_SERVICE_NAME = "UiPath.TypeScript.Sdk";
293
+ const SDK_LOGGER_NAME = "uipath-ts-sdk-telemetry";
294
+ // Event names
295
+ const SDK_RUN_EVENT = "Sdk.Run";
296
+ // Default value for unknown/empty attributes
297
+ const UNKNOWN = "";
298
+
299
+ /**
300
+ * Log exporter that sends ALL logs as Application Insights custom events
301
+ */
302
+ class ApplicationInsightsEventExporter {
303
+ constructor(connectionString) {
304
+ this.connectionString = connectionString;
305
+ }
306
+ export(logs, resultCallback) {
307
+ try {
308
+ logs.forEach(logRecord => {
309
+ this.sendAsCustomEvent(logRecord);
310
+ });
311
+ resultCallback({ code: 0 });
312
+ }
313
+ catch (error) {
314
+ console.debug('Failed to export logs to Application Insights:', error);
315
+ resultCallback({ code: 2, error });
486
316
  }
487
317
  }
488
- /**
489
- * Creates a NetworkError from a fetch/network error
490
- */
491
- static createNetworkError(error) {
492
- let message = ErrorMessages.NETWORK_ERROR;
493
- if (error instanceof Error) {
494
- if (error.name === ErrorNames.ABORT_ERROR) {
495
- message = ErrorMessages.REQUEST_ABORTED;
318
+ shutdown() {
319
+ return Promise.resolve();
320
+ }
321
+ sendAsCustomEvent(logRecord) {
322
+ // Get event name from body or attributes
323
+ const eventName = logRecord.body || SDK_RUN_EVENT;
324
+ const payload = {
325
+ name: 'Microsoft.ApplicationInsights.Event',
326
+ time: new Date().toISOString(),
327
+ iKey: this.extractInstrumentationKey(),
328
+ data: {
329
+ baseType: 'EventData',
330
+ baseData: {
331
+ ver: 2,
332
+ name: eventName,
333
+ properties: this.convertAttributesToProperties(logRecord.attributes || {})
334
+ }
335
+ },
336
+ tags: {
337
+ 'ai.cloud.role': CLOUD_ROLE_NAME,
338
+ 'ai.cloud.roleInstance': SDK_VERSION
496
339
  }
497
- else if (error.message.includes('timeout')) {
498
- message = ErrorMessages.REQUEST_TIMEOUT;
340
+ };
341
+ this.sendToApplicationInsights(payload);
342
+ }
343
+ extractInstrumentationKey() {
344
+ const match = this.connectionString.match(/InstrumentationKey=([^;]+)/);
345
+ return match ? match[1] : '';
346
+ }
347
+ convertAttributesToProperties(attributes) {
348
+ const properties = {};
349
+ Object.entries(attributes || {}).forEach(([key, value]) => {
350
+ properties[key] = String(value);
351
+ });
352
+ return properties;
353
+ }
354
+ async sendToApplicationInsights(payload) {
355
+ try {
356
+ const ingestionEndpoint = this.extractIngestionEndpoint();
357
+ if (!ingestionEndpoint) {
358
+ console.debug('No ingestion endpoint found in connection string');
359
+ return;
499
360
  }
500
- else {
501
- message = error.message;
361
+ const url = `${ingestionEndpoint}/v2/track`;
362
+ const response = await fetch(url, {
363
+ method: 'POST',
364
+ headers: {
365
+ 'Content-Type': 'application/json',
366
+ },
367
+ body: JSON.stringify(payload)
368
+ });
369
+ if (!response.ok) {
370
+ console.debug(`Failed to send event telemetry: ${response.status} ${response.statusText}`);
502
371
  }
503
372
  }
504
- return new NetworkError({ message });
373
+ catch (error) {
374
+ console.debug('Error sending event telemetry to Application Insights:', error);
375
+ }
376
+ }
377
+ extractIngestionEndpoint() {
378
+ const match = this.connectionString.match(/IngestionEndpoint=([^;]+)/);
379
+ return match ? match[1] : '';
505
380
  }
506
381
  }
507
-
508
- const FOLDER_ID = 'X-UIPATH-OrganizationUnitId';
509
- /**
510
- * Content type constants for HTTP requests/responses
511
- */
512
- const CONTENT_TYPES = {
513
- JSON: 'application/json',
514
- XML: 'application/xml',
515
- OCTET_STREAM: 'application/octet-stream'
516
- };
517
382
  /**
518
- * Response type constants for HTTP requests
383
+ * Singleton telemetry client
519
384
  */
520
- const RESPONSE_TYPES = {
521
- JSON: 'json',
522
- TEXT: 'text',
523
- BLOB: 'blob',
524
- ARRAYBUFFER: 'arraybuffer'
525
- };
526
-
527
- class ApiClient {
528
- constructor(config, executionContext, tokenManager, clientConfig = {}) {
529
- this.defaultHeaders = {};
530
- this.config = config;
531
- this.executionContext = executionContext;
532
- this.clientConfig = clientConfig;
533
- this.tokenManager = tokenManager;
385
+ class TelemetryClient {
386
+ constructor() {
387
+ this.isInitialized = false;
534
388
  }
535
- setDefaultHeaders(headers) {
536
- this.defaultHeaders = { ...this.defaultHeaders, ...headers };
389
+ static getInstance() {
390
+ if (!TelemetryClient.instance) {
391
+ TelemetryClient.instance = new TelemetryClient();
392
+ }
393
+ return TelemetryClient.instance;
537
394
  }
538
395
  /**
539
- * Gets a valid authentication token, refreshing if necessary.
540
- * Used internally for API requests and exposed for services that need manual auth headers.
541
- *
542
- * @returns The valid token
543
- * @throws AuthenticationError if no token available or refresh fails
396
+ * Initialize telemetry
544
397
  */
545
- async getValidToken() {
546
- return this.tokenManager.getValidToken();
547
- }
548
- async getDefaultHeaders() {
549
- const token = await this.getValidToken();
550
- return {
551
- 'Authorization': `Bearer ${token}`,
552
- 'Content-Type': CONTENT_TYPES.JSON,
553
- ...this.defaultHeaders,
554
- ...this.clientConfig.headers
555
- };
556
- }
557
- async request(method, path, options = {}) {
558
- // Ensure path starts with a forward slash
559
- const normalizedPath = path.startsWith('/') ? path.substring(1) : path;
560
- // Construct URL with org and tenant names
561
- const url = new URL(`${this.config.orgName}/${this.config.tenantName}/${normalizedPath}`, this.config.baseUrl).toString();
562
- const isFormData = options.body instanceof FormData;
563
- const defaultHeaders = await this.getDefaultHeaders();
564
- if (isFormData) {
565
- delete defaultHeaders['Content-Type'];
566
- }
567
- const headers = {
568
- ...defaultHeaders,
569
- ...options.headers
570
- };
571
- // Convert params to URLSearchParams
572
- const searchParams = new URLSearchParams();
573
- if (options.params) {
574
- Object.entries(options.params).forEach(([key, value]) => {
575
- searchParams.append(key, value.toString());
576
- });
398
+ initialize(config) {
399
+ if (this.isInitialized) {
400
+ return;
577
401
  }
578
- const fullUrl = searchParams.toString() ? `${url}?${searchParams.toString()}` : url;
579
- let body = undefined;
580
- if (options.body) {
581
- body = isFormData ? options.body : JSON.stringify(options.body);
402
+ this.isInitialized = true;
403
+ if (config) {
404
+ this.telemetryContext = config;
582
405
  }
583
406
  try {
584
- const response = await fetch(fullUrl, {
585
- method,
586
- headers,
587
- body,
588
- signal: options.signal
589
- });
590
- if (!response.ok) {
591
- const errorInfo = await errorResponseParser.parse(response);
592
- throw ErrorFactory.createFromHttpStatus(response.status, errorInfo);
593
- }
594
- if (response.status === 204) {
595
- return undefined;
596
- }
597
- // Handle blob response type for binary data (e.g., file downloads)
598
- if (options.responseType === RESPONSE_TYPES.BLOB) {
599
- const blob = await response.blob();
600
- return blob;
601
- }
602
- // Check if we're expecting XML
603
- const acceptHeader = headers['Accept'] || headers['accept'];
604
- if (acceptHeader === CONTENT_TYPES.XML) {
605
- const text = await response.text();
606
- return text;
407
+ const connectionString = this.getConnectionString();
408
+ if (!connectionString) {
409
+ return;
607
410
  }
608
- return response.json();
411
+ this.setupTelemetryProvider(connectionString);
609
412
  }
610
413
  catch (error) {
611
- // If it's already one of our errors, re-throw it
612
- if (error.type && error.type.includes('Error')) {
613
- throw error;
614
- }
615
- // Otherwise, it's likely a network error
616
- throw ErrorFactory.createNetworkError(error);
414
+ // Silent failure - telemetry errors shouldn't break functionality
415
+ console.debug('Failed to initialize OpenTelemetry:', error);
617
416
  }
618
417
  }
619
- async get(path, options = {}) {
620
- return this.request('GET', path, options);
418
+ getConnectionString() {
419
+ const connectionString = CONNECTION_STRING;
420
+ return connectionString;
621
421
  }
622
- async post(path, data, options = {}) {
623
- return this.request('POST', path, { ...options, body: data });
422
+ setupTelemetryProvider(connectionString) {
423
+ const exporter = new ApplicationInsightsEventExporter(connectionString);
424
+ const processor = new sdkLogs.BatchLogRecordProcessor(exporter);
425
+ this.logProvider = new sdkLogs.LoggerProvider({
426
+ processors: [processor]
427
+ });
428
+ this.logger = this.logProvider.getLogger(SDK_LOGGER_NAME);
624
429
  }
625
- async put(path, data, options = {}) {
626
- return this.request('PUT', path, { ...options, body: data });
430
+ /**
431
+ * Track a telemetry event
432
+ */
433
+ track(eventName, name, extraAttributes = {}) {
434
+ try {
435
+ // Skip if logger not initialized
436
+ if (!this.logger) {
437
+ return;
438
+ }
439
+ const finalDisplayName = name || eventName;
440
+ const attributes = this.getEnrichedAttributes(extraAttributes, eventName);
441
+ // Emit as log
442
+ this.logger.emit({
443
+ body: finalDisplayName,
444
+ attributes: attributes,
445
+ timestamp: Date.now(),
446
+ });
447
+ }
448
+ catch (error) {
449
+ // Silent failure
450
+ console.debug('Failed to track telemetry event:', error);
451
+ }
627
452
  }
628
- async patch(path, data, options = {}) {
629
- return this.request('PATCH', path, { ...options, body: data });
453
+ /**
454
+ * Get enriched attributes for telemetry events
455
+ */
456
+ getEnrichedAttributes(extraAttributes, eventName) {
457
+ const attributes = {
458
+ [APP_NAME]: SDK_SERVICE_NAME,
459
+ [VERSION]: SDK_VERSION,
460
+ [SERVICE]: eventName,
461
+ [CLOUD_URL]: this.createCloudUrl(),
462
+ [CLOUD_ORGANIZATION_NAME]: this.telemetryContext?.orgName || UNKNOWN,
463
+ [CLOUD_TENANT_NAME]: this.telemetryContext?.tenantName || UNKNOWN,
464
+ [CLOUD_REDIRECT_URI]: this.telemetryContext?.redirectUri || UNKNOWN,
465
+ [CLOUD_CLIENT_ID]: this.telemetryContext?.clientId || UNKNOWN,
466
+ ...extraAttributes,
467
+ };
468
+ return attributes;
630
469
  }
631
- async delete(path, options = {}) {
632
- return this.request('DELETE', path, options);
470
+ /**
471
+ * Create cloud URL from base URL, organization ID, and tenant ID
472
+ */
473
+ createCloudUrl() {
474
+ const baseUrl = this.telemetryContext?.baseUrl;
475
+ const orgId = this.telemetryContext?.orgName;
476
+ const tenantId = this.telemetryContext?.tenantName;
477
+ if (!baseUrl || !orgId || !tenantId) {
478
+ return UNKNOWN;
479
+ }
480
+ return `${baseUrl}/${orgId}/${tenantId}`;
633
481
  }
634
482
  }
483
+ // Export singleton instance
484
+ const telemetryClient = TelemetryClient.getInstance();
635
485
 
636
486
  /**
637
- * Pagination types supported by the SDK
487
+ * SDK Track decorator and function for telemetry
638
488
  */
639
- var PaginationType;
640
- (function (PaginationType) {
641
- PaginationType["OFFSET"] = "offset";
642
- PaginationType["TOKEN"] = "token";
643
- })(PaginationType || (PaginationType = {}));
644
-
645
489
  /**
646
- * Collection of utility functions for working with objects
490
+ * Common tracking logic shared between method and function decorators
647
491
  */
492
+ function createTrackedFunction(originalFunction, nameOrOptions, fallbackName, opts) {
493
+ return function (...args) {
494
+ // Determine if we should track this call
495
+ let shouldTrack = true;
496
+ if (opts.condition !== undefined) {
497
+ if (typeof opts.condition === 'function') {
498
+ shouldTrack = opts.condition.apply(this, args);
499
+ }
500
+ else {
501
+ shouldTrack = opts.condition;
502
+ }
503
+ }
504
+ // Track the event if enabled
505
+ if (shouldTrack) {
506
+ // Use the full name provided in the decorator (e.g., "Queue.GetAll")
507
+ const serviceMethod = typeof nameOrOptions === 'string'
508
+ ? nameOrOptions
509
+ : fallbackName;
510
+ // Use 'Sdk.Run' as the name and serviceMethod as the service
511
+ telemetryClient.track(serviceMethod, SDK_RUN_EVENT, opts.attributes);
512
+ }
513
+ // Execute the original function
514
+ return originalFunction.apply(this, args);
515
+ };
516
+ }
648
517
  /**
649
- * Filters out undefined values from an object
650
- * @param obj The source object
651
- * @returns A new object without undefined values
518
+ * Track decorator that can be used to automatically track function calls
652
519
  *
653
- * @example
654
- * ```typescript
655
- * // Object with undefined values
656
- * const options = {
657
- * name: 'test',
658
- * count: 5,
659
- * prefix: undefined,
660
- * suffix: null
661
- * };
662
- * const result = filterUndefined(options);
663
- * // result = { name: 'test', count: 5, suffix: null }
664
- * ```
520
+ * Usage:
521
+ * @track("Service.Method")
522
+ * function myFunction() { ... }
523
+ *
524
+ * @track("Queue.GetAll")
525
+ * async getAll() { ... }
526
+ *
527
+ * @track("Tasks.Create")
528
+ * async create() { ... }
529
+ *
530
+ * @track("Assets.Update", { condition: false })
531
+ * function myFunction() { ... }
532
+ *
533
+ * @track("Processes.Start", { attributes: { customProp: "value" } })
534
+ * function myFunction() { ... }
665
535
  */
666
- function filterUndefined(obj) {
667
- const result = {};
668
- for (const [key, value] of Object.entries(obj)) {
669
- if (value !== undefined) {
670
- result[key] = value;
536
+ function track(nameOrOptions, options) {
537
+ return function decorator(_target, propertyKey, descriptor) {
538
+ const opts = typeof nameOrOptions === 'object' ? nameOrOptions : {};
539
+ if (descriptor && typeof descriptor.value === 'function') {
540
+ // Method decorator
541
+ descriptor.value = createTrackedFunction(descriptor.value, nameOrOptions, propertyKey || 'unknown_method', opts);
542
+ return descriptor;
671
543
  }
672
- }
673
- return result;
544
+ // Function decorator
545
+ return (originalFunction) => createTrackedFunction(originalFunction, nameOrOptions, originalFunction.name || 'unknown_function', opts);
546
+ };
674
547
  }
548
+
675
549
  /**
676
- * Helper function for OData responses that ALWAYS return 200 with array indication
677
- * Empty array = success, Non-empty array = error
678
- * Used for task assignment APIs that don't use HTTP status codes for errors
550
+ * Types of tasks available in Action Center.
551
+ * Each type determines the task's behavior, UI rendering, and completion requirements.
679
552
  */
680
- function processODataArrayResponse(oDataResponse, successData) {
681
- // Empty array = success
682
- if (oDataResponse.value.length === 0) {
683
- return {
684
- success: true,
685
- data: successData
686
- };
687
- }
688
- // Non-empty array = error details
689
- return {
690
- success: false,
691
- data: oDataResponse.value
692
- };
693
- }
553
+ exports.TaskType = void 0;
554
+ (function (TaskType) {
555
+ /** A form-based task that renders a UiPath form layout for user input */
556
+ TaskType["Form"] = "FormTask";
557
+ /** An externally managed task handled outside of Action Center */
558
+ TaskType["External"] = "ExternalTask";
559
+ /** A task powered by a UiPath App */
560
+ TaskType["App"] = "AppTask";
561
+ /** A document validation task for reviewing and correcting extracted document data */
562
+ TaskType["DocumentValidation"] = "DocumentValidationTask";
563
+ /** A document classification task for categorizing documents */
564
+ TaskType["DocumentClassification"] = "DocumentClassificationTask";
565
+ /** A data labeling task for annotating training data */
566
+ TaskType["DataLabeling"] = "DataLabelingTask";
567
+ })(exports.TaskType || (exports.TaskType = {}));
568
+ exports.TaskPriority = void 0;
569
+ (function (TaskPriority) {
570
+ TaskPriority["Low"] = "Low";
571
+ TaskPriority["Medium"] = "Medium";
572
+ TaskPriority["High"] = "High";
573
+ TaskPriority["Critical"] = "Critical";
574
+ })(exports.TaskPriority || (exports.TaskPriority = {}));
575
+ exports.TaskStatus = void 0;
576
+ (function (TaskStatus) {
577
+ TaskStatus["Unassigned"] = "Unassigned";
578
+ TaskStatus["Pending"] = "Pending";
579
+ TaskStatus["Completed"] = "Completed";
580
+ })(exports.TaskStatus || (exports.TaskStatus = {}));
581
+ exports.TaskSlaCriteria = void 0;
582
+ (function (TaskSlaCriteria) {
583
+ TaskSlaCriteria["TaskCreated"] = "TaskCreated";
584
+ TaskSlaCriteria["TaskAssigned"] = "TaskAssigned";
585
+ TaskSlaCriteria["TaskCompleted"] = "TaskCompleted";
586
+ })(exports.TaskSlaCriteria || (exports.TaskSlaCriteria = {}));
587
+ exports.TaskSlaStatus = void 0;
588
+ (function (TaskSlaStatus) {
589
+ TaskSlaStatus["OverdueLater"] = "OverdueLater";
590
+ TaskSlaStatus["OverdueSoon"] = "OverdueSoon";
591
+ TaskSlaStatus["Overdue"] = "Overdue";
592
+ TaskSlaStatus["CompletedInTime"] = "CompletedInTime";
593
+ })(exports.TaskSlaStatus || (exports.TaskSlaStatus = {}));
594
+ exports.TaskSourceName = void 0;
595
+ (function (TaskSourceName) {
596
+ TaskSourceName["Agent"] = "Agent";
597
+ TaskSourceName["Workflow"] = "Workflow";
598
+ TaskSourceName["Maestro"] = "Maestro";
599
+ TaskSourceName["Default"] = "Default";
600
+ })(exports.TaskSourceName || (exports.TaskSourceName = {}));
601
+ /**
602
+ * Task activity types
603
+ */
604
+ exports.TaskActivityType = void 0;
605
+ (function (TaskActivityType) {
606
+ TaskActivityType["Created"] = "Created";
607
+ TaskActivityType["Assigned"] = "Assigned";
608
+ TaskActivityType["Reassigned"] = "Reassigned";
609
+ TaskActivityType["Unassigned"] = "Unassigned";
610
+ TaskActivityType["Saved"] = "Saved";
611
+ TaskActivityType["Forwarded"] = "Forwarded";
612
+ TaskActivityType["Completed"] = "Completed";
613
+ TaskActivityType["Commented"] = "Commented";
614
+ TaskActivityType["Deleted"] = "Deleted";
615
+ TaskActivityType["BulkSaved"] = "BulkSaved";
616
+ TaskActivityType["BulkCompleted"] = "BulkCompleted";
617
+ TaskActivityType["FirstOpened"] = "FirstOpened";
618
+ })(exports.TaskActivityType || (exports.TaskActivityType = {}));
694
619
 
695
620
  /**
696
- * Utility functions for platform detection
621
+ * Maps numeric TaskStatus values (from API) to TaskStatus enum values.
622
+ * Extend this file with additional field mappings as needed.
697
623
  */
624
+ const TaskStatusMap = {
625
+ 0: exports.TaskStatus.Unassigned,
626
+ 1: exports.TaskStatus.Pending,
627
+ 2: exports.TaskStatus.Completed,
628
+ };
629
+ // Field mapping for time-related fields to ensure consistent naming
630
+ const TaskMap = {
631
+ completionTime: 'completedTime',
632
+ deletionTime: 'deletedTime',
633
+ lastModificationTime: 'lastModifiedTime',
634
+ creationTime: 'createdTime',
635
+ organizationUnitId: 'folderId'
636
+ };
698
637
  /**
699
- * Checks if code is running in a browser environment
638
+ * Default expand parameters
700
639
  */
701
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
702
- isBrowser && window.self != window.top && window.location.href.includes('source=ActionCenter');
640
+ const DEFAULT_TASK_EXPAND = 'AssignedToUser,CreatorUser,LastModifierUser';
703
641
 
704
642
  /**
705
- * Base64 encoding/decoding
643
+ * Base path constants for different services
706
644
  */
645
+ const ORCHESTRATOR_BASE = 'orchestrator_';
646
+
707
647
  /**
708
- * Encodes a string to base64
709
- * @param str - The string to encode
710
- * @returns Base64 encoded string
648
+ * Orchestrator Service Endpoints
711
649
  */
712
- function encodeBase64(str) {
713
- // TextEncoder for UTF-8 encoding (works in both browser and Node.js)
714
- const encoder = new TextEncoder();
715
- const data = encoder.encode(str);
716
- // Convert Uint8Array to base64
717
- if (isBrowser) {
718
- // Browser environment
719
- // Convert Uint8Array to binary string then to base64
720
- const binaryString = Array.from(data, byte => String.fromCharCode(byte)).join('');
721
- return btoa(binaryString);
722
- }
723
- else {
724
- // Node.js environment
725
- return Buffer.from(data).toString('base64');
726
- }
727
- }
728
650
  /**
729
- * Decodes a base64 string
730
- * @param base64 - The base64 string to decode
731
- * @returns Decoded string
651
+ * Task Service (Action Center) Endpoints
732
652
  */
733
- function decodeBase64(base64) {
734
- let bytes;
735
- if (isBrowser) {
736
- // Browser environment
737
- const binaryString = atob(base64);
738
- bytes = new Uint8Array(binaryString.length);
739
- for (let i = 0; i < binaryString.length; i++) {
740
- bytes[i] = binaryString.charCodeAt(i);
741
- }
742
- }
743
- else {
744
- // Node.js environment
745
- bytes = new Uint8Array(Buffer.from(base64, 'base64'));
746
- }
747
- // TextDecoder for UTF-8 decoding (works in both browser and Node.js)
748
- const decoder = new TextDecoder();
749
- return decoder.decode(bytes);
750
- }
653
+ const TASK_ENDPOINTS = {
654
+ CREATE_GENERIC_TASK: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/CreateTask`,
655
+ GET_TASK_USERS: (folderId) => `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTaskUsers(organizationUnitId=${folderId})`,
656
+ GET_TASKS_ACROSS_FOLDERS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTasksAcrossFolders`,
657
+ GET_TASKS_ACROSS_FOLDERS_ADMIN: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTasksAcrossFoldersForAdmin`,
658
+ GET_BY_ID: (id) => `${ORCHESTRATOR_BASE}/odata/Tasks(${id})`,
659
+ ASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.AssignTasks`,
660
+ REASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.ReassignTasks`,
661
+ UNASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.UnassignTasks`,
662
+ COMPLETE_FORM_TASK: `${ORCHESTRATOR_BASE}/forms/TaskForms/CompleteTask`,
663
+ COMPLETE_APP_TASK: `${ORCHESTRATOR_BASE}/tasks/AppTasks/CompleteAppTask`,
664
+ COMPLETE_GENERIC_TASK: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/CompleteTask`,
665
+ GET_TASK_FORM_BY_ID: `${ORCHESTRATOR_BASE}/forms/TaskForms/GetTaskFormById`,
666
+ GET_GENERIC_TASK_BY_ID: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/GetTaskDataById`,
667
+ GET_APP_TASK_BY_ID: `${ORCHESTRATOR_BASE}/tasks/AppTasks/GetAppTaskById`,
668
+ };
669
+
670
+ const TASK_TYPE_ENDPOINTS = {
671
+ [exports.TaskType.Form]: TASK_ENDPOINTS.GET_TASK_FORM_BY_ID,
672
+ [exports.TaskType.App]: TASK_ENDPOINTS.GET_APP_TASK_BY_ID,
673
+ [exports.TaskType.DocumentValidation]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
674
+ [exports.TaskType.DocumentClassification]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
675
+ [exports.TaskType.External]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
676
+ [exports.TaskType.DataLabeling]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
677
+ };
678
+ var ActionCenterEventNames;
679
+ (function (ActionCenterEventNames) {
680
+ ActionCenterEventNames["TOKENREFRESHED"] = "AC.tokenRefreshed";
681
+ ActionCenterEventNames["REFRESHTOKEN"] = "AC.refreshToken";
682
+ })(ActionCenterEventNames || (ActionCenterEventNames = {}));
751
683
 
752
684
  /**
753
- * PaginationManager handles the conversion between uniform cursor-based pagination
754
- * and the specific pagination type for each service
685
+ * Creates methods for a task
686
+ *
687
+ * @param taskData - The task data (response from API)
688
+ * @param service - The task service instance
689
+ * @returns Object containing task methods
755
690
  */
756
- class PaginationManager {
757
- /**
758
- * Create a pagination cursor for subsequent page requests
759
- */
760
- static createCursor({ pageInfo, type }) {
761
- if (!pageInfo.hasMore) {
762
- return undefined;
763
- }
764
- const cursorData = {
765
- type,
766
- pageSize: pageInfo.pageSize,
767
- };
768
- switch (type) {
769
- case PaginationType.OFFSET:
770
- if (pageInfo.currentPage) {
771
- cursorData.pageNumber = pageInfo.currentPage + 1;
772
- }
773
- break;
774
- case PaginationType.TOKEN:
775
- if (pageInfo.continuationToken) {
776
- cursorData.continuationToken = pageInfo.continuationToken;
777
- }
778
- else {
779
- return undefined; // No continuation token, can't continue
780
- }
781
- break;
782
- }
783
- return {
784
- value: encodeBase64(JSON.stringify(cursorData))
785
- };
786
- }
787
- /**
788
- * Create a paginated response with navigation cursors
789
- */
790
- static createPaginatedResponse({ pageInfo, type }, items) {
791
- const nextCursor = PaginationManager.createCursor({ pageInfo, type });
792
- // Create previous page cursor if applicable
793
- let previousCursor = undefined;
794
- if (pageInfo.currentPage && pageInfo.currentPage > 1) {
795
- const prevCursorData = {
796
- type,
797
- pageNumber: pageInfo.currentPage - 1,
798
- pageSize: pageInfo.pageSize,
799
- };
800
- previousCursor = {
801
- value: encodeBase64(JSON.stringify(prevCursorData))
802
- };
803
- }
804
- // Calculate total pages if we have totalCount and pageSize
805
- let totalPages = undefined;
806
- if (pageInfo.totalCount !== undefined && pageInfo.pageSize) {
807
- totalPages = Math.ceil(pageInfo.totalCount / pageInfo.pageSize);
691
+ function createTaskMethods(taskData, service) {
692
+ return {
693
+ async assign(options) {
694
+ if (!taskData.id)
695
+ throw new Error('Task ID is undefined');
696
+ const assignmentOptions = 'userId' in options && options.userId !== undefined
697
+ ? { taskId: taskData.id, userId: options.userId }
698
+ : { taskId: taskData.id, userNameOrEmail: options.userNameOrEmail };
699
+ return service.assign(assignmentOptions);
700
+ },
701
+ async reassign(options) {
702
+ if (!taskData.id)
703
+ throw new Error('Task ID is undefined');
704
+ const assignmentOptions = 'userId' in options && options.userId !== undefined
705
+ ? { taskId: taskData.id, userId: options.userId }
706
+ : { taskId: taskData.id, userNameOrEmail: options.userNameOrEmail };
707
+ return service.reassign(assignmentOptions);
708
+ },
709
+ async unassign() {
710
+ if (!taskData.id)
711
+ throw new Error('Task ID is undefined');
712
+ return service.unassign(taskData.id);
713
+ },
714
+ async complete(options) {
715
+ if (!taskData.id)
716
+ throw new Error('Task ID is undefined');
717
+ const folderId = taskData.folderId;
718
+ if (!folderId)
719
+ throw new Error('Folder ID is required');
720
+ return service.complete({
721
+ type: options.type,
722
+ taskId: taskData.id,
723
+ data: options.data,
724
+ action: options.action
725
+ }, folderId);
808
726
  }
809
- // Determine if this pagination type supports page jumping
810
- const supportsPageJump = type === PaginationType.OFFSET;
811
- // Create the result object with all fields, then filter out undefined values
812
- const result = filterUndefined({
813
- items,
814
- totalCount: pageInfo.totalCount,
815
- hasNextPage: pageInfo.hasMore,
816
- nextCursor: nextCursor,
817
- previousCursor: previousCursor,
818
- currentPage: pageInfo.currentPage,
819
- totalPages,
820
- supportsPageJump
821
- });
822
- return result;
823
- }
727
+ };
824
728
  }
825
-
826
729
  /**
827
- * Creates headers object from key-value pairs
828
- * @param headersObj - Object containing header key-value pairs
829
- * @returns Headers object with all values converted to strings
830
- *
831
- * @example
832
- * ```typescript
833
- * // Single header
834
- * const headers = createHeaders({ 'X-UIPATH-FolderKey': '1234567890' });
835
- *
836
- * // Multiple headers
837
- * const headers = createHeaders({
838
- * 'X-UIPATH-FolderKey': '1234567890',
839
- * 'X-UIPATH-OrganizationUnitId': 123,
840
- * 'Accept': 'application/json'
841
- * });
842
- *
843
- * // Using constants
844
- * import { FOLDER_KEY, FOLDER_ID } from '../constants/headers';
845
- * const headers = createHeaders({
846
- * [FOLDER_KEY]: 'abc-123',
847
- * [FOLDER_ID]: 456
848
- * });
730
+ * Creates an actionable task by combining API task data with operational methods.
849
731
  *
850
- * // Empty headers
851
- * const headers = createHeaders();
852
- * ```
732
+ * @param taskData - The task data from API
733
+ * @param service - The task service instance
734
+ * @returns A task object with added methods
853
735
  */
854
- function createHeaders(headersObj) {
855
- const headers = {};
856
- for (const [key, value] of Object.entries(headersObj)) {
857
- if (value !== undefined && value !== null) {
858
- headers[key] = value.toString();
859
- }
860
- }
861
- return headers;
736
+ function createTaskWithMethods(taskData, service) {
737
+ const methods = createTaskMethods(taskData, service);
738
+ return Object.assign({}, taskData, methods);
862
739
  }
863
740
 
864
741
  /**
@@ -904,38 +781,154 @@ const BUCKET_TOKEN_PARAMS = {
904
781
  TOKEN_PARAM: 'continuationToken'
905
782
  };
906
783
 
784
+ const FOLDER_ID = 'X-UIPATH-OrganizationUnitId';
907
785
  /**
908
- * Transforms data by mapping fields according to the provided field mapping
909
- * @param data The source data to transform
910
- * @param fieldMapping Object mapping source field names to target field names
911
- * @returns Transformed data with mapped field names
786
+ * Content type constants for HTTP requests/responses
787
+ */
788
+ const CONTENT_TYPES = {
789
+ JSON: 'application/json',
790
+ XML: 'application/xml',
791
+ OCTET_STREAM: 'application/octet-stream'
792
+ };
793
+ /**
794
+ * Response type constants for HTTP requests
795
+ */
796
+ const RESPONSE_TYPES = {
797
+ JSON: 'json',
798
+ TEXT: 'text',
799
+ BLOB: 'blob',
800
+ ARRAYBUFFER: 'arraybuffer'
801
+ };
802
+
803
+ /**
804
+ * Creates headers object from key-value pairs
805
+ * @param headersObj - Object containing header key-value pairs
806
+ * @returns Headers object with all values converted to strings
912
807
  *
913
808
  * @example
914
809
  * ```typescript
915
- * // Single object transformation
916
- * const data = { id: '123', userName: 'john' };
917
- * const mapping = { id: 'userId', userName: 'name' };
918
- * const result = transformData(data, mapping);
919
- * // result = { userId: '123', name: 'john' }
810
+ * // Single header
811
+ * const headers = createHeaders({ 'X-UIPATH-FolderKey': '1234567890' });
920
812
  *
921
- * // Array transformation
922
- * const dataArray = [
923
- * { id: '123', userName: 'john' },
924
- * { id: '456', userName: 'jane' }
925
- * ];
926
- * const result = transformData(dataArray, mapping);
927
- * // result = [
928
- * // { userId: '123', name: 'john' },
929
- * // { userId: '456', name: 'jane' }
930
- * // ]
931
- * ```
932
- */
933
- function transformData(data, fieldMapping) {
934
- // Handle array of objects
935
- if (Array.isArray(data)) {
936
- return data.map(item => transformData(item, fieldMapping));
937
- }
938
- // Handle single object
813
+ * // Multiple headers
814
+ * const headers = createHeaders({
815
+ * 'X-UIPATH-FolderKey': '1234567890',
816
+ * 'X-UIPATH-OrganizationUnitId': 123,
817
+ * 'Accept': 'application/json'
818
+ * });
819
+ *
820
+ * // Using constants
821
+ * import { FOLDER_KEY, FOLDER_ID } from '../constants/headers';
822
+ * const headers = createHeaders({
823
+ * [FOLDER_KEY]: 'abc-123',
824
+ * [FOLDER_ID]: 456
825
+ * });
826
+ *
827
+ * // Empty headers
828
+ * const headers = createHeaders();
829
+ * ```
830
+ */
831
+ function createHeaders(headersObj) {
832
+ const headers = {};
833
+ for (const [key, value] of Object.entries(headersObj)) {
834
+ if (value !== undefined && value !== null) {
835
+ headers[key] = value.toString();
836
+ }
837
+ }
838
+ return headers;
839
+ }
840
+
841
+ /**
842
+ * Collection of utility functions for working with objects
843
+ */
844
+ /**
845
+ * Filters out undefined values from an object
846
+ * @param obj The source object
847
+ * @returns A new object without undefined values
848
+ *
849
+ * @example
850
+ * ```typescript
851
+ * // Object with undefined values
852
+ * const options = {
853
+ * name: 'test',
854
+ * count: 5,
855
+ * prefix: undefined,
856
+ * suffix: null
857
+ * };
858
+ * const result = filterUndefined(options);
859
+ * // result = { name: 'test', count: 5, suffix: null }
860
+ * ```
861
+ */
862
+ function filterUndefined(obj) {
863
+ const result = {};
864
+ for (const [key, value] of Object.entries(obj)) {
865
+ if (value !== undefined) {
866
+ result[key] = value;
867
+ }
868
+ }
869
+ return result;
870
+ }
871
+ /**
872
+ * Helper function for OData responses that ALWAYS return 200 with array indication
873
+ * Empty array = success, Non-empty array = error
874
+ * Used for task assignment APIs that don't use HTTP status codes for errors
875
+ */
876
+ function processODataArrayResponse(oDataResponse, successData) {
877
+ // Empty array = success
878
+ if (oDataResponse.value.length === 0) {
879
+ return {
880
+ success: true,
881
+ data: successData
882
+ };
883
+ }
884
+ // Non-empty array = error details
885
+ return {
886
+ success: false,
887
+ data: oDataResponse.value
888
+ };
889
+ }
890
+
891
+ /**
892
+ * Pagination types supported by the SDK
893
+ */
894
+ var PaginationType;
895
+ (function (PaginationType) {
896
+ PaginationType["OFFSET"] = "offset";
897
+ PaginationType["TOKEN"] = "token";
898
+ })(PaginationType || (PaginationType = {}));
899
+
900
+ /**
901
+ * Transforms data by mapping fields according to the provided field mapping
902
+ * @param data The source data to transform
903
+ * @param fieldMapping Object mapping source field names to target field names
904
+ * @returns Transformed data with mapped field names
905
+ *
906
+ * @example
907
+ * ```typescript
908
+ * // Single object transformation
909
+ * const data = { id: '123', userName: 'john' };
910
+ * const mapping = { id: 'userId', userName: 'name' };
911
+ * const result = transformData(data, mapping);
912
+ * // result = { userId: '123', name: 'john' }
913
+ *
914
+ * // Array transformation
915
+ * const dataArray = [
916
+ * { id: '123', userName: 'john' },
917
+ * { id: '456', userName: 'jane' }
918
+ * ];
919
+ * const result = transformData(dataArray, mapping);
920
+ * // result = [
921
+ * // { userId: '123', name: 'john' },
922
+ * // { userId: '456', name: 'jane' }
923
+ * // ]
924
+ * ```
925
+ */
926
+ function transformData(data, fieldMapping) {
927
+ // Handle array of objects
928
+ if (Array.isArray(data)) {
929
+ return data.map(item => transformData(item, fieldMapping));
930
+ }
931
+ // Handle single object
939
932
  const result = { ...data };
940
933
  for (const [sourceField, targetField] of Object.entries(fieldMapping)) {
941
934
  if (sourceField in result) {
@@ -1181,6 +1174,63 @@ function getLimitedPageSize(pageSize) {
1181
1174
  return Math.max(1, Math.min(pageSize, MAX_PAGE_SIZE));
1182
1175
  }
1183
1176
 
1177
+ /**
1178
+ * Utility functions for platform detection
1179
+ */
1180
+ /**
1181
+ * Checks if code is running in a browser environment
1182
+ */
1183
+ const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
1184
+ isBrowser && window.self != window.top && window.location.href.includes('source=ActionCenter');
1185
+
1186
+ /**
1187
+ * Base64 encoding/decoding
1188
+ */
1189
+ /**
1190
+ * Encodes a string to base64
1191
+ * @param str - The string to encode
1192
+ * @returns Base64 encoded string
1193
+ */
1194
+ function encodeBase64(str) {
1195
+ // TextEncoder for UTF-8 encoding (works in both browser and Node.js)
1196
+ const encoder = new TextEncoder();
1197
+ const data = encoder.encode(str);
1198
+ // Convert Uint8Array to base64
1199
+ if (isBrowser) {
1200
+ // Browser environment
1201
+ // Convert Uint8Array to binary string then to base64
1202
+ const binaryString = Array.from(data, byte => String.fromCharCode(byte)).join('');
1203
+ return btoa(binaryString);
1204
+ }
1205
+ else {
1206
+ // Node.js environment
1207
+ return Buffer.from(data).toString('base64');
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Decodes a base64 string
1212
+ * @param base64 - The base64 string to decode
1213
+ * @returns Decoded string
1214
+ */
1215
+ function decodeBase64(base64) {
1216
+ let bytes;
1217
+ if (isBrowser) {
1218
+ // Browser environment
1219
+ const binaryString = atob(base64);
1220
+ bytes = new Uint8Array(binaryString.length);
1221
+ for (let i = 0; i < binaryString.length; i++) {
1222
+ bytes[i] = binaryString.charCodeAt(i);
1223
+ }
1224
+ }
1225
+ else {
1226
+ // Node.js environment
1227
+ bytes = new Uint8Array(Buffer.from(base64, 'base64'));
1228
+ }
1229
+ // TextDecoder for UTF-8 decoding (works in both browser and Node.js)
1230
+ const decoder = new TextDecoder();
1231
+ return decoder.decode(bytes);
1232
+ }
1233
+
1184
1234
  /**
1185
1235
  * Helper functions for pagination that can be used across services
1186
1236
  */
@@ -1434,741 +1484,720 @@ class PaginationHelpers {
1434
1484
  }
1435
1485
 
1436
1486
  /**
1437
- * SDK Internals Registry - Internal registry for SDK instances
1438
- *
1439
- * This class is NOT exported in the public API.
1440
- * It provides a secure way to share SDK internals between
1441
- * the UiPath class and service classes without exposing them publicly.
1442
- *
1443
- * @internal
1487
+ * Type guards for error response types
1444
1488
  */
1445
- // Global symbol key to ensure WeakMap is shared across module instances
1446
- // This prevents issues when core and service modules are bundled separately
1447
- const REGISTRY_KEY = Symbol.for('@uipath/sdk-internals-registry');
1448
- // Get or create the global WeakMap store
1449
- const getGlobalStore = () => {
1450
- const globalObj = globalThis;
1451
- if (!globalObj[REGISTRY_KEY]) {
1452
- globalObj[REGISTRY_KEY] = new WeakMap();
1453
- }
1454
- return globalObj[REGISTRY_KEY];
1455
- };
1489
+ function isOrchestratorError(error) {
1490
+ return typeof error === 'object' &&
1491
+ error !== null &&
1492
+ 'message' in error &&
1493
+ 'errorCode' in error &&
1494
+ typeof error.message === 'string' &&
1495
+ typeof error.errorCode === 'number';
1496
+ }
1497
+ function isEntityError(error) {
1498
+ return typeof error === 'object' &&
1499
+ error !== null &&
1500
+ 'error' in error &&
1501
+ typeof error.error === 'string';
1502
+ }
1503
+ function isPimsError(error) {
1504
+ return typeof error === 'object' &&
1505
+ error !== null &&
1506
+ 'type' in error &&
1507
+ 'title' in error &&
1508
+ 'status' in error &&
1509
+ typeof error.type === 'string' &&
1510
+ typeof error.title === 'string' &&
1511
+ typeof error.status === 'number';
1512
+ }
1513
+
1456
1514
  /**
1457
- * Internal registry for SDK private components.
1458
- * Uses WeakMap to prevent memory leaks - entries are automatically
1459
- * garbage collected when the SDK instance is no longer referenced.
1460
- *
1461
- * Uses a global singleton pattern to ensure the same WeakMap is shared
1462
- * across separately bundled modules (core, entities, tasks, etc.).
1463
- *
1464
- * @internal - Not exported in public API
1515
+ * Parser for Orchestrator/Task error format
1465
1516
  */
1466
- class SDKInternalsRegistry {
1467
- // Use global store to ensure sharing across module bundles
1468
- static get store() {
1469
- return getGlobalStore();
1517
+ class OrchestratorErrorParser {
1518
+ canParse(errorBody) {
1519
+ return isOrchestratorError(errorBody);
1470
1520
  }
1471
- /**
1472
- * Register SDK instance internals
1473
- * Called by UiPath constructor
1474
- */
1475
- static set(instance, internals) {
1476
- this.store.set(instance, internals);
1477
- }
1478
- /**
1479
- * Retrieve SDK instance internals
1480
- * Called by BaseService constructor
1481
- */
1482
- static get(instance) {
1483
- const internals = this.store.get(instance);
1484
- if (!internals) {
1485
- throw new Error('Invalid SDK instance. Make sure to pass a valid UiPath instance to the service constructor.');
1486
- }
1487
- return internals;
1521
+ parse(errorBody, response) {
1522
+ const error = errorBody;
1523
+ return {
1524
+ message: error.message,
1525
+ code: response?.status?.toString(),
1526
+ details: {
1527
+ errorCode: error.errorCode,
1528
+ traceId: error.traceId,
1529
+ originalResponse: error
1530
+ },
1531
+ requestId: error.traceId
1532
+ };
1488
1533
  }
1489
1534
  }
1490
-
1491
- var _BaseService_apiClient;
1492
1535
  /**
1493
- * Base class for all UiPath SDK services.
1494
- *
1495
- * Provides common functionality for authentication, configuration, and API communication.
1496
- * All service classes extend this base to inherit dependency injection and HTTP client access.
1497
- *
1498
- * This class implements the dependency injection pattern where services receive a configured
1499
- * UiPath instance. The ApiClient is created internally and handles all HTTP operations
1500
- * including authentication token management.
1501
- *
1502
- * @remarks
1503
- * Service classes should extend this base and call `super(uiPath)` in their constructor.
1504
- * Protected HTTP methods (get, post, put, patch, delete) are available to all subclasses.
1505
- *
1536
+ * Parser for Entity (Data Fabric) error format
1506
1537
  */
1507
- class BaseService {
1508
- /**
1509
- * Creates a base service instance with dependency injection.
1510
- *
1511
- * Extracts configuration, execution context, and token manager from the UiPath instance
1512
- * to initialize an authenticated API client. The ApiClient handles all HTTP operations
1513
- * and token management internally.
1514
- *
1515
- * @param instance - UiPath SDK instance providing authentication and configuration.
1516
- * Services receive this via dependency injection in the modular pattern.
1517
- *
1518
- * @example
1519
- * ```typescript
1520
- * // Services automatically call this via super()
1521
- * export class EntityService extends BaseService {
1522
- * constructor(instance: IUiPath) {
1523
- * super(instance); // Initializes the internal ApiClient
1524
- * }
1525
- * }
1526
- *
1527
- * // Usage in modular pattern
1528
- * import { UiPath } from '@uipath/uipath-typescript/core';
1529
- * import { Entities } from '@uipath/uipath-typescript/entities';
1530
- *
1531
- * const sdk = new UiPath(config);
1532
- * await sdk.initialize();
1533
- * const entities = new Entities(sdk);
1534
- * ```
1535
- */
1536
- constructor(instance) {
1537
- // Private field - not visible via Object.keys() or any reflection
1538
- _BaseService_apiClient.set(this, void 0);
1539
- const { config, context, tokenManager } = SDKInternalsRegistry.get(instance);
1540
- __classPrivateFieldSet(this, _BaseService_apiClient, new ApiClient(config, context, tokenManager), "f");
1541
- }
1542
- /**
1543
- * Gets a valid authentication token, refreshing if necessary.
1544
- * Use this when you need to manually add Authorization headers (e.g., direct uploads).
1545
- *
1546
- * @returns Promise resolving to a valid access token string
1547
- * @throws AuthenticationError if no token is available or refresh fails
1548
- */
1549
- async getValidAuthToken() {
1550
- return __classPrivateFieldGet(this, _BaseService_apiClient, "f").getValidToken();
1538
+ class EntityErrorParser {
1539
+ canParse(errorBody) {
1540
+ return isEntityError(errorBody);
1551
1541
  }
1552
- /**
1553
- * Creates a service accessor for pagination helpers
1554
- * This allows pagination helpers to access protected methods without making them public
1555
- */
1556
- createPaginationServiceAccess() {
1542
+ parse(errorBody, response) {
1543
+ const error = errorBody;
1557
1544
  return {
1558
- get: (path, options) => this.get(path, options || {}),
1559
- post: (path, body, options) => this.post(path, body, options || {}),
1560
- requestWithPagination: (method, path, paginationOptions, options) => this.requestWithPagination(method, path, paginationOptions, options)
1545
+ message: error.error,
1546
+ code: response?.status?.toString(),
1547
+ details: {
1548
+ error: error.error,
1549
+ traceId: error.traceId,
1550
+ originalResponse: error
1551
+ },
1552
+ requestId: error.traceId
1561
1553
  };
1562
1554
  }
1563
- async request(method, path, options = {}) {
1564
- switch (method.toUpperCase()) {
1565
- case 'GET':
1566
- return this.get(path, options);
1567
- case 'POST':
1568
- return this.post(path, options.body, options);
1569
- case 'PUT':
1570
- return this.put(path, options.body, options);
1571
- case 'PATCH':
1572
- return this.patch(path, options.body, options);
1573
- case 'DELETE':
1574
- return this.delete(path, options);
1575
- default:
1576
- throw new Error(`Unsupported HTTP method: ${method}`);
1577
- }
1555
+ }
1556
+ /**
1557
+ * Parser for PIMS error format
1558
+ */
1559
+ class PimsErrorParser {
1560
+ canParse(errorBody) {
1561
+ return isPimsError(errorBody);
1578
1562
  }
1579
- async requestWithSpec(spec) {
1580
- if (!spec.method || !spec.url) {
1581
- throw new Error('Request spec must include method and url');
1563
+ parse(errorBody, response) {
1564
+ const error = errorBody;
1565
+ let message = error.title;
1566
+ // If there are validation errors, append them to the message for better visibility
1567
+ if (error.errors && Object.keys(error.errors).length > 0) {
1568
+ const errorMessages = Object.entries(error.errors)
1569
+ .map(([field, messages]) => `${field}: ${messages.join(', ')}`)
1570
+ .join('; ');
1571
+ message += `. Validation errors: ${errorMessages}`;
1582
1572
  }
1583
- return this.request(spec.method, spec.url, spec);
1584
- }
1585
- async get(path, options = {}) {
1586
- const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").get(path, options);
1587
- return { data: response };
1588
- }
1589
- async post(path, data, options = {}) {
1590
- const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").post(path, data, options);
1591
- return { data: response };
1573
+ return {
1574
+ message,
1575
+ code: response?.status?.toString(),
1576
+ details: {
1577
+ type: error.type,
1578
+ title: error.title,
1579
+ status: error.status,
1580
+ errors: error.errors,
1581
+ traceId: error.traceId,
1582
+ originalResponse: error
1583
+ },
1584
+ requestId: error.traceId
1585
+ };
1592
1586
  }
1593
- async put(path, data, options = {}) {
1594
- const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").put(path, data, options);
1595
- return { data: response };
1587
+ }
1588
+ /**
1589
+ * Fallback parser for unrecognized formats
1590
+ */
1591
+ class GenericErrorParser {
1592
+ canParse(_errorBody) {
1593
+ return true; // Always can parse as last resort
1596
1594
  }
1597
- async patch(path, data, options = {}) {
1598
- const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").patch(path, data, options);
1599
- return { data: response };
1595
+ parse(errorBody, response) {
1596
+ // For unknown error formats, just pass through the raw error with fallback message
1597
+ const message = response?.statusText || 'An error occurred';
1598
+ return {
1599
+ message,
1600
+ code: response?.status?.toString(),
1601
+ details: {
1602
+ originalResponse: errorBody
1603
+ },
1604
+ };
1600
1605
  }
1601
- async delete(path, options = {}) {
1602
- const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").delete(path, options);
1603
- return { data: response };
1606
+ }
1607
+ /**
1608
+ * Main error response parser using Chain of Responsibility pattern
1609
+ *
1610
+ * This parser standardizes error responses from different UiPath services into a
1611
+ * consistent format, regardless of the original error structure.
1612
+ *
1613
+ * Supported formats:
1614
+ * 1. Orchestrator/Task: { message, errorCode, traceId }
1615
+ * 2. Entity (Data Fabric): { error, traceId }
1616
+ * 3. PIMS/Maestro: { type, title, status, errors?, traceId? }
1617
+ * 4. Generic: Fallback for any other format
1618
+ *
1619
+ * @example
1620
+ * const parser = new ErrorResponseParser();
1621
+ * const errorInfo = await parser.parse(response);
1622
+ * // errorInfo will have consistent structure regardless of service
1623
+ */
1624
+ class ErrorResponseParser {
1625
+ constructor() {
1626
+ this.strategies = [
1627
+ new OrchestratorErrorParser(),
1628
+ new EntityErrorParser(),
1629
+ new PimsErrorParser(),
1630
+ new GenericErrorParser() // Must be last
1631
+ ];
1604
1632
  }
1605
1633
  /**
1606
- * Execute a request with cursor-based pagination
1634
+ * Parses error response body into standardized format
1635
+ * @param response - The HTTP response object
1636
+ * @returns Standardized error information
1607
1637
  */
1608
- async requestWithPagination(method, path, paginationOptions, options) {
1609
- const paginationType = options.pagination.paginationType;
1610
- // Validate and prepare pagination parameters
1611
- const params = this.validateAndPreparePaginationParams(paginationType, paginationOptions);
1612
- // Prepare request parameters based on pagination type
1613
- const requestParams = this.preparePaginationRequestParams(paginationType, params, options.pagination);
1614
- // For POST requests, merge pagination params into body; for GET, use query params
1615
- if (method.toUpperCase() === 'POST') {
1616
- const existingBody = (options.body && typeof options.body === 'object') ? options.body : {};
1617
- options.body = {
1618
- ...existingBody,
1619
- ...options.params,
1620
- ...requestParams
1621
- };
1638
+ async parse(response) {
1639
+ try {
1640
+ const errorBody = await response.json();
1641
+ // Find the first strategy that can parse this error format
1642
+ const strategy = this.strategies.find(s => s.canParse(errorBody));
1643
+ // GenericErrorParser always returns true, so this will never be null
1644
+ return strategy.parse(errorBody, response);
1622
1645
  }
1623
- else {
1624
- // Merge pagination parameters with existing parameters
1625
- options.params = {
1626
- ...options.params,
1627
- ...requestParams
1646
+ catch {
1647
+ // Handle non-JSON responses
1648
+ const responseText = await response.text().catch(() => '');
1649
+ return {
1650
+ message: response.statusText,
1651
+ code: response.status.toString(),
1652
+ details: {
1653
+ parseError: 'Failed to parse error response as JSON',
1654
+ responseText
1655
+ },
1656
+ requestId: response.headers.get(HttpHeaders.X_REQUEST_ID) || undefined
1628
1657
  };
1629
1658
  }
1630
- // Make the request
1631
- const response = await this.request(method, path, options);
1632
- // Extract data from the response and create page result
1633
- return this.createPaginatedResponseFromResponse(response, params, paginationType, {
1634
- itemsField: options.pagination.itemsField,
1635
- totalCountField: options.pagination.totalCountField,
1636
- continuationTokenField: options.pagination.continuationTokenField
1637
- });
1638
1659
  }
1660
+ }
1661
+ // Export singleton instance
1662
+ const errorResponseParser = new ErrorResponseParser();
1663
+
1664
+ /**
1665
+ * Factory for creating typed errors based on HTTP status codes
1666
+ * Follows the Factory pattern for clean error instantiation
1667
+ */
1668
+ class ErrorFactory {
1639
1669
  /**
1640
- * Validates and prepares pagination parameters from options
1641
- */
1642
- validateAndPreparePaginationParams(paginationType, paginationOptions) {
1643
- return PaginationHelpers.validatePaginationOptions(paginationOptions, paginationType);
1644
- }
1645
- /**
1646
- * Prepares request parameters for pagination based on pagination type
1670
+ * Creates appropriate error instance based on HTTP status code
1647
1671
  */
1648
- preparePaginationRequestParams(paginationType, params, paginationConfig) {
1649
- const requestParams = {};
1650
- let limitedPageSize;
1651
- const paginationParams = paginationConfig?.paginationParams;
1652
- switch (paginationType) {
1653
- case PaginationType.OFFSET:
1654
- limitedPageSize = getLimitedPageSize(params.pageSize);
1655
- const pageSizeParam = paginationParams?.pageSizeParam || ODATA_OFFSET_PARAMS.PAGE_SIZE_PARAM;
1656
- const offsetParam = paginationParams?.offsetParam || ODATA_OFFSET_PARAMS.OFFSET_PARAM;
1657
- const countParam = paginationParams?.countParam || ODATA_OFFSET_PARAMS.COUNT_PARAM;
1658
- requestParams[pageSizeParam] = limitedPageSize;
1659
- if (params.pageNumber && params.pageNumber > 1) {
1660
- requestParams[offsetParam] = (params.pageNumber - 1) * limitedPageSize;
1661
- }
1662
- // Include total count for ODATA APIs
1663
- {
1664
- requestParams[countParam] = true;
1665
- }
1666
- break;
1667
- case PaginationType.TOKEN:
1668
- const tokenPageSizeParam = paginationParams?.pageSizeParam || BUCKET_TOKEN_PARAMS.PAGE_SIZE_PARAM;
1669
- const tokenParam = paginationParams?.tokenParam || BUCKET_TOKEN_PARAMS.TOKEN_PARAM;
1670
- if (params.pageSize) {
1671
- requestParams[tokenPageSizeParam] = getLimitedPageSize(params.pageSize);
1672
- }
1673
- if (params.continuationToken) {
1674
- requestParams[tokenParam] = params.continuationToken;
1672
+ static createFromHttpStatus(statusCode, errorInfo) {
1673
+ const { message, requestId } = errorInfo;
1674
+ // Map status codes to error types
1675
+ switch (statusCode) {
1676
+ case HttpStatus.BAD_REQUEST:
1677
+ return new ValidationError({ message, statusCode, requestId });
1678
+ case HttpStatus.UNAUTHORIZED:
1679
+ return new AuthenticationError({ message, statusCode, requestId });
1680
+ case HttpStatus.FORBIDDEN:
1681
+ return new AuthorizationError({ message, statusCode, requestId });
1682
+ case HttpStatus.NOT_FOUND:
1683
+ return new NotFoundError({ message, statusCode, requestId });
1684
+ case HttpStatus.TOO_MANY_REQUESTS:
1685
+ return new RateLimitError({ message, statusCode, requestId });
1686
+ default:
1687
+ // For 5xx errors or any other status code
1688
+ if (statusCode >= HttpStatus.INTERNAL_SERVER_ERROR) {
1689
+ return new ServerError({ message, statusCode, requestId });
1675
1690
  }
1676
- break;
1691
+ // For unknown client errors, treat as validation error
1692
+ return new ValidationError({
1693
+ message: `${message} (HTTP ${statusCode})`,
1694
+ statusCode,
1695
+ requestId
1696
+ });
1677
1697
  }
1678
- return requestParams;
1679
1698
  }
1680
1699
  /**
1681
- * Creates a paginated response from API response
1700
+ * Creates a NetworkError from a fetch/network error
1682
1701
  */
1683
- createPaginatedResponseFromResponse(response, params, paginationType, fields) {
1684
- // Extract fields from response
1685
- const itemsField = fields.itemsField ||
1686
- (paginationType === PaginationType.TOKEN ? 'items' : 'value');
1687
- const totalCountField = fields.totalCountField || 'totalRecordCount';
1688
- const continuationTokenField = fields.continuationTokenField || 'continuationToken';
1689
- // Extract items and metadata
1690
- const items = response.data[itemsField] || [];
1691
- const totalCount = response.data[totalCountField];
1692
- const continuationToken = response.data[continuationTokenField];
1693
- // Determine if there are more pages
1694
- const hasMore = this.determineHasMorePages(paginationType, {
1695
- totalCount,
1696
- pageSize: params.pageSize,
1697
- currentPage: params.pageNumber || 1,
1698
- itemsCount: items.length,
1699
- continuationToken
1700
- });
1701
- // Create and return the page result
1702
- return PaginationManager.createPaginatedResponse({
1703
- pageInfo: {
1704
- hasMore,
1705
- totalCount,
1706
- currentPage: params.pageNumber,
1707
- pageSize: params.pageSize,
1708
- continuationToken
1709
- },
1710
- type: paginationType,
1711
- }, items);
1702
+ static createNetworkError(error) {
1703
+ let message = ErrorMessages.NETWORK_ERROR;
1704
+ if (error instanceof Error) {
1705
+ if (error.name === ErrorNames.ABORT_ERROR) {
1706
+ message = ErrorMessages.REQUEST_ABORTED;
1707
+ }
1708
+ else if (error.message.includes('timeout')) {
1709
+ message = ErrorMessages.REQUEST_TIMEOUT;
1710
+ }
1711
+ else {
1712
+ message = error.message;
1713
+ }
1714
+ }
1715
+ return new NetworkError({ message });
1716
+ }
1717
+ }
1718
+
1719
+ class ApiClient {
1720
+ constructor(config, executionContext, tokenManager, clientConfig = {}) {
1721
+ this.defaultHeaders = {};
1722
+ this.config = config;
1723
+ this.executionContext = executionContext;
1724
+ this.clientConfig = clientConfig;
1725
+ this.tokenManager = tokenManager;
1726
+ }
1727
+ setDefaultHeaders(headers) {
1728
+ this.defaultHeaders = { ...this.defaultHeaders, ...headers };
1712
1729
  }
1713
1730
  /**
1714
- * Determines if there are more pages based on pagination type and metadata
1731
+ * Gets a valid authentication token, refreshing if necessary.
1732
+ * Used internally for API requests and exposed for services that need manual auth headers.
1733
+ *
1734
+ * @returns The valid token
1735
+ * @throws AuthenticationError if no token available or refresh fails
1715
1736
  */
1716
- determineHasMorePages(paginationType, info) {
1717
- switch (paginationType) {
1718
- case PaginationType.OFFSET:
1719
- const effectivePageSize = info.pageSize ?? DEFAULT_PAGE_SIZE;
1720
- // If totalCount is available, use it for precise calculation
1721
- if (info.totalCount !== undefined) {
1722
- return (info.currentPage * effectivePageSize) < info.totalCount;
1723
- }
1724
- // Fallback when totalCount is not available
1725
- // NOTE: This code path should rarely be executed as the APIs typically return totalCount
1726
- return info.itemsCount === effectivePageSize;
1727
- case PaginationType.TOKEN:
1728
- return !!info.continuationToken;
1729
- default:
1730
- return false;
1737
+ async getValidToken() {
1738
+ return this.tokenManager.getValidToken();
1739
+ }
1740
+ async getDefaultHeaders() {
1741
+ const token = await this.getValidToken();
1742
+ return {
1743
+ 'Authorization': `Bearer ${token}`,
1744
+ 'Content-Type': CONTENT_TYPES.JSON,
1745
+ ...this.defaultHeaders,
1746
+ ...this.clientConfig.headers
1747
+ };
1748
+ }
1749
+ async request(method, path, options = {}) {
1750
+ // Ensure path starts with a forward slash
1751
+ const normalizedPath = path.startsWith('/') ? path.substring(1) : path;
1752
+ // Construct URL with org and tenant names
1753
+ const url = new URL(`${this.config.orgName}/${this.config.tenantName}/${normalizedPath}`, this.config.baseUrl).toString();
1754
+ const isFormData = options.body instanceof FormData;
1755
+ const defaultHeaders = await this.getDefaultHeaders();
1756
+ if (isFormData) {
1757
+ delete defaultHeaders['Content-Type'];
1758
+ }
1759
+ const headers = {
1760
+ ...defaultHeaders,
1761
+ ...options.headers
1762
+ };
1763
+ // Convert params to URLSearchParams
1764
+ const searchParams = new URLSearchParams();
1765
+ if (options.params) {
1766
+ Object.entries(options.params).forEach(([key, value]) => {
1767
+ searchParams.append(key, value.toString());
1768
+ });
1731
1769
  }
1770
+ const fullUrl = searchParams.toString() ? `${url}?${searchParams.toString()}` : url;
1771
+ let body = undefined;
1772
+ if (options.body) {
1773
+ body = isFormData ? options.body : JSON.stringify(options.body);
1774
+ }
1775
+ try {
1776
+ const response = await fetch(fullUrl, {
1777
+ method,
1778
+ headers,
1779
+ body,
1780
+ signal: options.signal
1781
+ });
1782
+ if (!response.ok) {
1783
+ const errorInfo = await errorResponseParser.parse(response);
1784
+ throw ErrorFactory.createFromHttpStatus(response.status, errorInfo);
1785
+ }
1786
+ if (response.status === 204) {
1787
+ return undefined;
1788
+ }
1789
+ // Handle blob response type for binary data (e.g., file downloads)
1790
+ if (options.responseType === RESPONSE_TYPES.BLOB) {
1791
+ const blob = await response.blob();
1792
+ return blob;
1793
+ }
1794
+ // Check if we're expecting XML
1795
+ const acceptHeader = headers['Accept'] || headers['accept'];
1796
+ if (acceptHeader === CONTENT_TYPES.XML) {
1797
+ const text = await response.text();
1798
+ return text;
1799
+ }
1800
+ return response.json();
1801
+ }
1802
+ catch (error) {
1803
+ // If it's already one of our errors, re-throw it
1804
+ if (error.type && error.type.includes('Error')) {
1805
+ throw error;
1806
+ }
1807
+ // Otherwise, it's likely a network error
1808
+ throw ErrorFactory.createNetworkError(error);
1809
+ }
1810
+ }
1811
+ async get(path, options = {}) {
1812
+ return this.request('GET', path, options);
1813
+ }
1814
+ async post(path, data, options = {}) {
1815
+ return this.request('POST', path, { ...options, body: data });
1816
+ }
1817
+ async put(path, data, options = {}) {
1818
+ return this.request('PUT', path, { ...options, body: data });
1819
+ }
1820
+ async patch(path, data, options = {}) {
1821
+ return this.request('PATCH', path, { ...options, body: data });
1822
+ }
1823
+ async delete(path, options = {}) {
1824
+ return this.request('DELETE', path, options);
1732
1825
  }
1733
1826
  }
1734
- _BaseService_apiClient = new WeakMap();
1735
-
1736
- exports.TaskType = void 0;
1737
- (function (TaskType) {
1738
- TaskType["Form"] = "FormTask";
1739
- TaskType["External"] = "ExternalTask";
1740
- TaskType["App"] = "AppTask";
1741
- })(exports.TaskType || (exports.TaskType = {}));
1742
- exports.TaskPriority = void 0;
1743
- (function (TaskPriority) {
1744
- TaskPriority["Low"] = "Low";
1745
- TaskPriority["Medium"] = "Medium";
1746
- TaskPriority["High"] = "High";
1747
- TaskPriority["Critical"] = "Critical";
1748
- })(exports.TaskPriority || (exports.TaskPriority = {}));
1749
- exports.TaskStatus = void 0;
1750
- (function (TaskStatus) {
1751
- TaskStatus["Unassigned"] = "Unassigned";
1752
- TaskStatus["Pending"] = "Pending";
1753
- TaskStatus["Completed"] = "Completed";
1754
- })(exports.TaskStatus || (exports.TaskStatus = {}));
1755
- exports.TaskSlaCriteria = void 0;
1756
- (function (TaskSlaCriteria) {
1757
- TaskSlaCriteria["TaskCreated"] = "TaskCreated";
1758
- TaskSlaCriteria["TaskAssigned"] = "TaskAssigned";
1759
- TaskSlaCriteria["TaskCompleted"] = "TaskCompleted";
1760
- })(exports.TaskSlaCriteria || (exports.TaskSlaCriteria = {}));
1761
- exports.TaskSlaStatus = void 0;
1762
- (function (TaskSlaStatus) {
1763
- TaskSlaStatus["OverdueLater"] = "OverdueLater";
1764
- TaskSlaStatus["OverdueSoon"] = "OverdueSoon";
1765
- TaskSlaStatus["Overdue"] = "Overdue";
1766
- TaskSlaStatus["CompletedInTime"] = "CompletedInTime";
1767
- })(exports.TaskSlaStatus || (exports.TaskSlaStatus = {}));
1768
- exports.TaskSourceName = void 0;
1769
- (function (TaskSourceName) {
1770
- TaskSourceName["Agent"] = "Agent";
1771
- TaskSourceName["Workflow"] = "Workflow";
1772
- TaskSourceName["Maestro"] = "Maestro";
1773
- TaskSourceName["Default"] = "Default";
1774
- })(exports.TaskSourceName || (exports.TaskSourceName = {}));
1775
- /**
1776
- * Task activity types
1777
- */
1778
- exports.TaskActivityType = void 0;
1779
- (function (TaskActivityType) {
1780
- TaskActivityType["Created"] = "Created";
1781
- TaskActivityType["Assigned"] = "Assigned";
1782
- TaskActivityType["Reassigned"] = "Reassigned";
1783
- TaskActivityType["Unassigned"] = "Unassigned";
1784
- TaskActivityType["Saved"] = "Saved";
1785
- TaskActivityType["Forwarded"] = "Forwarded";
1786
- TaskActivityType["Completed"] = "Completed";
1787
- TaskActivityType["Commented"] = "Commented";
1788
- TaskActivityType["Deleted"] = "Deleted";
1789
- TaskActivityType["BulkSaved"] = "BulkSaved";
1790
- TaskActivityType["BulkCompleted"] = "BulkCompleted";
1791
- TaskActivityType["FirstOpened"] = "FirstOpened";
1792
- })(exports.TaskActivityType || (exports.TaskActivityType = {}));
1793
1827
 
1794
1828
  /**
1795
- * Creates methods for a task
1796
- *
1797
- * @param taskData - The task data (response from API)
1798
- * @param service - The task service instance
1799
- * @returns Object containing task methods
1829
+ * PaginationManager handles the conversion between uniform cursor-based pagination
1830
+ * and the specific pagination type for each service
1800
1831
  */
1801
- function createTaskMethods(taskData, service) {
1802
- return {
1803
- async assign(options) {
1804
- if (!taskData.id)
1805
- throw new Error('Task ID is undefined');
1806
- const assignmentOptions = 'userId' in options && options.userId !== undefined
1807
- ? { taskId: taskData.id, userId: options.userId }
1808
- : { taskId: taskData.id, userNameOrEmail: options.userNameOrEmail };
1809
- return service.assign(assignmentOptions);
1810
- },
1811
- async reassign(options) {
1812
- if (!taskData.id)
1813
- throw new Error('Task ID is undefined');
1814
- const assignmentOptions = 'userId' in options && options.userId !== undefined
1815
- ? { taskId: taskData.id, userId: options.userId }
1816
- : { taskId: taskData.id, userNameOrEmail: options.userNameOrEmail };
1817
- return service.reassign(assignmentOptions);
1818
- },
1819
- async unassign() {
1820
- if (!taskData.id)
1821
- throw new Error('Task ID is undefined');
1822
- return service.unassign(taskData.id);
1823
- },
1824
- async complete(options) {
1825
- if (!taskData.id)
1826
- throw new Error('Task ID is undefined');
1827
- const folderId = taskData.folderId;
1828
- if (!folderId)
1829
- throw new Error('Folder ID is required');
1830
- return service.complete({
1831
- type: options.type,
1832
- taskId: taskData.id,
1833
- data: options.data,
1834
- action: options.action
1835
- }, folderId);
1832
+ class PaginationManager {
1833
+ /**
1834
+ * Create a pagination cursor for subsequent page requests
1835
+ */
1836
+ static createCursor({ pageInfo, type }) {
1837
+ if (!pageInfo.hasMore) {
1838
+ return undefined;
1836
1839
  }
1837
- };
1838
- }
1839
- /**
1840
- * Creates an actionable task by combining API task data with operational methods.
1841
- *
1842
- * @param taskData - The task data from API
1843
- * @param service - The task service instance
1844
- * @returns A task object with added methods
1845
- */
1846
- function createTaskWithMethods(taskData, service) {
1847
- const methods = createTaskMethods(taskData, service);
1848
- return Object.assign({}, taskData, methods);
1849
- }
1850
-
1851
- /**
1852
- * Maps numeric TaskStatus values (from API) to TaskStatus enum values.
1853
- * Extend this file with additional field mappings as needed.
1854
- */
1855
- const TaskStatusMap = {
1856
- 0: exports.TaskStatus.Unassigned,
1857
- 1: exports.TaskStatus.Pending,
1858
- 2: exports.TaskStatus.Completed,
1859
- };
1860
- // Field mapping for time-related fields to ensure consistent naming
1861
- const TaskMap = {
1862
- completionTime: 'completedTime',
1863
- deletionTime: 'deletedTime',
1864
- lastModificationTime: 'lastModifiedTime',
1865
- creationTime: 'createdTime',
1866
- organizationUnitId: 'folderId'
1867
- };
1868
- /**
1869
- * Default expand parameters
1870
- */
1871
- const DEFAULT_TASK_EXPAND = 'AssignedToUser,CreatorUser,LastModifierUser';
1872
-
1873
- /**
1874
- * Base path constants for different services
1875
- */
1876
- const ORCHESTRATOR_BASE = 'orchestrator_';
1877
-
1878
- /**
1879
- * Orchestrator Service Endpoints
1880
- */
1881
- /**
1882
- * Task Service (Action Center) Endpoints
1883
- */
1884
- const TASK_ENDPOINTS = {
1885
- CREATE_GENERIC_TASK: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/CreateTask`,
1886
- GET_TASK_USERS: (folderId) => `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTaskUsers(organizationUnitId=${folderId})`,
1887
- GET_TASKS_ACROSS_FOLDERS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTasksAcrossFolders`,
1888
- GET_TASKS_ACROSS_FOLDERS_ADMIN: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.GetTasksAcrossFoldersForAdmin`,
1889
- GET_BY_ID: (id) => `${ORCHESTRATOR_BASE}/odata/Tasks(${id})`,
1890
- ASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.AssignTasks`,
1891
- REASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.ReassignTasks`,
1892
- UNASSIGN_TASKS: `${ORCHESTRATOR_BASE}/odata/Tasks/UiPath.Server.Configuration.OData.UnassignTasks`,
1893
- COMPLETE_FORM_TASK: `${ORCHESTRATOR_BASE}/forms/TaskForms/CompleteTask`,
1894
- COMPLETE_APP_TASK: `${ORCHESTRATOR_BASE}/tasks/AppTasks/CompleteAppTask`,
1895
- COMPLETE_GENERIC_TASK: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/CompleteTask`,
1896
- GET_TASK_FORM_BY_ID: `${ORCHESTRATOR_BASE}/forms/TaskForms/GetTaskFormById`,
1897
- };
1898
-
1899
- /**
1900
- * SDK Telemetry constants
1901
- */
1902
- // Connection string placeholder that will be replaced during build
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";
1904
- // SDK Version placeholder
1905
- const SDK_VERSION = "1.2.1";
1906
- const VERSION = "Version";
1907
- const SERVICE = "Service";
1908
- const CLOUD_ORGANIZATION_NAME = "CloudOrganizationName";
1909
- const CLOUD_TENANT_NAME = "CloudTenantName";
1910
- const CLOUD_URL = "CloudUrl";
1911
- const CLOUD_CLIENT_ID = "CloudClientId";
1912
- const CLOUD_REDIRECT_URI = "CloudRedirectUri";
1913
- const APP_NAME = "ApplicationName";
1914
- const CLOUD_ROLE_NAME = "uipath-ts-sdk";
1915
- // Service and logger names
1916
- const SDK_SERVICE_NAME = "UiPath.TypeScript.Sdk";
1917
- const SDK_LOGGER_NAME = "uipath-ts-sdk-telemetry";
1918
- // Event names
1919
- const SDK_RUN_EVENT = "Sdk.Run";
1920
- // Default value for unknown/empty attributes
1921
- const UNKNOWN = "";
1922
-
1923
- /**
1924
- * Log exporter that sends ALL logs as Application Insights custom events
1925
- */
1926
- class ApplicationInsightsEventExporter {
1927
- constructor(connectionString) {
1928
- this.connectionString = connectionString;
1840
+ const cursorData = {
1841
+ type,
1842
+ pageSize: pageInfo.pageSize,
1843
+ };
1844
+ switch (type) {
1845
+ case PaginationType.OFFSET:
1846
+ if (pageInfo.currentPage) {
1847
+ cursorData.pageNumber = pageInfo.currentPage + 1;
1848
+ }
1849
+ break;
1850
+ case PaginationType.TOKEN:
1851
+ if (pageInfo.continuationToken) {
1852
+ cursorData.continuationToken = pageInfo.continuationToken;
1853
+ }
1854
+ else {
1855
+ return undefined; // No continuation token, can't continue
1856
+ }
1857
+ break;
1858
+ }
1859
+ return {
1860
+ value: encodeBase64(JSON.stringify(cursorData))
1861
+ };
1929
1862
  }
1930
- export(logs, resultCallback) {
1931
- try {
1932
- logs.forEach(logRecord => {
1933
- this.sendAsCustomEvent(logRecord);
1934
- });
1935
- resultCallback({ code: 0 });
1863
+ /**
1864
+ * Create a paginated response with navigation cursors
1865
+ */
1866
+ static createPaginatedResponse({ pageInfo, type }, items) {
1867
+ const nextCursor = PaginationManager.createCursor({ pageInfo, type });
1868
+ // Create previous page cursor if applicable
1869
+ let previousCursor = undefined;
1870
+ if (pageInfo.currentPage && pageInfo.currentPage > 1) {
1871
+ const prevCursorData = {
1872
+ type,
1873
+ pageNumber: pageInfo.currentPage - 1,
1874
+ pageSize: pageInfo.pageSize,
1875
+ };
1876
+ previousCursor = {
1877
+ value: encodeBase64(JSON.stringify(prevCursorData))
1878
+ };
1936
1879
  }
1937
- catch (error) {
1938
- console.debug('Failed to export logs to Application Insights:', error);
1939
- resultCallback({ code: 2, error });
1880
+ // Calculate total pages if we have totalCount and pageSize
1881
+ let totalPages = undefined;
1882
+ if (pageInfo.totalCount !== undefined && pageInfo.pageSize) {
1883
+ totalPages = Math.ceil(pageInfo.totalCount / pageInfo.pageSize);
1940
1884
  }
1885
+ // Determine if this pagination type supports page jumping
1886
+ const supportsPageJump = type === PaginationType.OFFSET;
1887
+ // Create the result object with all fields, then filter out undefined values
1888
+ const result = filterUndefined({
1889
+ items,
1890
+ totalCount: pageInfo.totalCount,
1891
+ hasNextPage: pageInfo.hasMore,
1892
+ nextCursor: nextCursor,
1893
+ previousCursor: previousCursor,
1894
+ currentPage: pageInfo.currentPage,
1895
+ totalPages,
1896
+ supportsPageJump
1897
+ });
1898
+ return result;
1941
1899
  }
1942
- shutdown() {
1943
- return Promise.resolve();
1944
- }
1945
- sendAsCustomEvent(logRecord) {
1946
- // Get event name from body or attributes
1947
- const eventName = logRecord.body || SDK_RUN_EVENT;
1948
- const payload = {
1949
- name: 'Microsoft.ApplicationInsights.Event',
1950
- time: new Date().toISOString(),
1951
- iKey: this.extractInstrumentationKey(),
1952
- data: {
1953
- baseType: 'EventData',
1954
- baseData: {
1955
- ver: 2,
1956
- name: eventName,
1957
- properties: this.convertAttributesToProperties(logRecord.attributes || {})
1958
- }
1959
- },
1960
- tags: {
1961
- 'ai.cloud.role': CLOUD_ROLE_NAME,
1962
- 'ai.cloud.roleInstance': SDK_VERSION
1963
- }
1964
- };
1965
- this.sendToApplicationInsights(payload);
1900
+ }
1901
+
1902
+ /**
1903
+ * SDK Internals Registry - Internal registry for SDK instances
1904
+ *
1905
+ * This class is NOT exported in the public API.
1906
+ * It provides a secure way to share SDK internals between
1907
+ * the UiPath class and service classes without exposing them publicly.
1908
+ *
1909
+ * @internal
1910
+ */
1911
+ // Global symbol key to ensure WeakMap is shared across module instances
1912
+ // This prevents issues when core and service modules are bundled separately
1913
+ const REGISTRY_KEY = Symbol.for('@uipath/sdk-internals-registry');
1914
+ // Get or create the global WeakMap store
1915
+ const getGlobalStore = () => {
1916
+ const globalObj = globalThis;
1917
+ if (!globalObj[REGISTRY_KEY]) {
1918
+ globalObj[REGISTRY_KEY] = new WeakMap();
1966
1919
  }
1967
- extractInstrumentationKey() {
1968
- const match = this.connectionString.match(/InstrumentationKey=([^;]+)/);
1969
- return match ? match[1] : '';
1920
+ return globalObj[REGISTRY_KEY];
1921
+ };
1922
+ /**
1923
+ * Internal registry for SDK private components.
1924
+ * Uses WeakMap to prevent memory leaks - entries are automatically
1925
+ * garbage collected when the SDK instance is no longer referenced.
1926
+ *
1927
+ * Uses a global singleton pattern to ensure the same WeakMap is shared
1928
+ * across separately bundled modules (core, entities, tasks, etc.).
1929
+ *
1930
+ * @internal - Not exported in public API
1931
+ */
1932
+ class SDKInternalsRegistry {
1933
+ // Use global store to ensure sharing across module bundles
1934
+ static get store() {
1935
+ return getGlobalStore();
1970
1936
  }
1971
- convertAttributesToProperties(attributes) {
1972
- const properties = {};
1973
- Object.entries(attributes || {}).forEach(([key, value]) => {
1974
- properties[key] = String(value);
1975
- });
1976
- return properties;
1937
+ /**
1938
+ * Register SDK instance internals
1939
+ * Called by UiPath constructor
1940
+ */
1941
+ static set(instance, internals) {
1942
+ this.store.set(instance, internals);
1977
1943
  }
1978
- async sendToApplicationInsights(payload) {
1979
- try {
1980
- const ingestionEndpoint = this.extractIngestionEndpoint();
1981
- if (!ingestionEndpoint) {
1982
- console.debug('No ingestion endpoint found in connection string');
1983
- return;
1984
- }
1985
- const url = `${ingestionEndpoint}/v2/track`;
1986
- const response = await fetch(url, {
1987
- method: 'POST',
1988
- headers: {
1989
- 'Content-Type': 'application/json',
1990
- },
1991
- body: JSON.stringify(payload)
1992
- });
1993
- if (!response.ok) {
1994
- console.debug(`Failed to send event telemetry: ${response.status} ${response.statusText}`);
1995
- }
1996
- }
1997
- catch (error) {
1998
- console.debug('Error sending event telemetry to Application Insights:', error);
1944
+ /**
1945
+ * Retrieve SDK instance internals
1946
+ * Called by BaseService constructor
1947
+ */
1948
+ static get(instance) {
1949
+ const internals = this.store.get(instance);
1950
+ if (!internals) {
1951
+ throw new Error('Invalid SDK instance. Make sure to pass a valid UiPath instance to the service constructor.');
1999
1952
  }
2000
- }
2001
- extractIngestionEndpoint() {
2002
- const match = this.connectionString.match(/IngestionEndpoint=([^;]+)/);
2003
- return match ? match[1] : '';
1953
+ return internals;
2004
1954
  }
2005
1955
  }
1956
+
1957
+ var _BaseService_apiClient;
2006
1958
  /**
2007
- * Singleton telemetry client
1959
+ * Base class for all UiPath SDK services.
1960
+ *
1961
+ * Provides common functionality for authentication, configuration, and API communication.
1962
+ * All service classes extend this base to inherit dependency injection and HTTP client access.
1963
+ *
1964
+ * This class implements the dependency injection pattern where services receive a configured
1965
+ * UiPath instance. The ApiClient is created internally and handles all HTTP operations
1966
+ * including authentication token management.
1967
+ *
1968
+ * @remarks
1969
+ * Service classes should extend this base and call `super(uiPath)` in their constructor.
1970
+ * Protected HTTP methods (get, post, put, patch, delete) are available to all subclasses.
1971
+ *
2008
1972
  */
2009
- class TelemetryClient {
2010
- constructor() {
2011
- this.isInitialized = false;
1973
+ class BaseService {
1974
+ /**
1975
+ * Creates a base service instance with dependency injection.
1976
+ *
1977
+ * Extracts configuration, execution context, and token manager from the UiPath instance
1978
+ * to initialize an authenticated API client. The ApiClient handles all HTTP operations
1979
+ * and token management internally.
1980
+ *
1981
+ * @param instance - UiPath SDK instance providing authentication and configuration.
1982
+ * Services receive this via dependency injection in the modular pattern.
1983
+ *
1984
+ * @example
1985
+ * ```typescript
1986
+ * // Services automatically call this via super()
1987
+ * export class EntityService extends BaseService {
1988
+ * constructor(instance: IUiPath) {
1989
+ * super(instance); // Initializes the internal ApiClient
1990
+ * }
1991
+ * }
1992
+ *
1993
+ * // Usage in modular pattern
1994
+ * import { UiPath } from '@uipath/uipath-typescript/core';
1995
+ * import { Entities } from '@uipath/uipath-typescript/entities';
1996
+ *
1997
+ * const sdk = new UiPath(config);
1998
+ * await sdk.initialize();
1999
+ * const entities = new Entities(sdk);
2000
+ * ```
2001
+ */
2002
+ constructor(instance) {
2003
+ // Private field - not visible via Object.keys() or any reflection
2004
+ _BaseService_apiClient.set(this, void 0);
2005
+ const { config, context, tokenManager } = SDKInternalsRegistry.get(instance);
2006
+ __classPrivateFieldSet(this, _BaseService_apiClient, new ApiClient(config, context, tokenManager), "f");
2012
2007
  }
2013
- static getInstance() {
2014
- if (!TelemetryClient.instance) {
2015
- TelemetryClient.instance = new TelemetryClient();
2016
- }
2017
- return TelemetryClient.instance;
2008
+ /**
2009
+ * Gets a valid authentication token, refreshing if necessary.
2010
+ * Use this when you need to manually add Authorization headers (e.g., direct uploads).
2011
+ *
2012
+ * @returns Promise resolving to a valid access token string
2013
+ * @throws AuthenticationError if no token is available or refresh fails
2014
+ */
2015
+ async getValidAuthToken() {
2016
+ return __classPrivateFieldGet(this, _BaseService_apiClient, "f").getValidToken();
2018
2017
  }
2019
2018
  /**
2020
- * Initialize telemetry
2019
+ * Creates a service accessor for pagination helpers
2020
+ * This allows pagination helpers to access protected methods without making them public
2021
2021
  */
2022
- initialize(config) {
2023
- if (this.isInitialized) {
2024
- return;
2025
- }
2026
- this.isInitialized = true;
2027
- if (config) {
2028
- this.telemetryContext = config;
2029
- }
2030
- try {
2031
- const connectionString = this.getConnectionString();
2032
- if (!connectionString) {
2033
- return;
2034
- }
2035
- this.setupTelemetryProvider(connectionString);
2022
+ createPaginationServiceAccess() {
2023
+ return {
2024
+ get: (path, options) => this.get(path, options || {}),
2025
+ post: (path, body, options) => this.post(path, body, options || {}),
2026
+ requestWithPagination: (method, path, paginationOptions, options) => this.requestWithPagination(method, path, paginationOptions, options)
2027
+ };
2028
+ }
2029
+ async request(method, path, options = {}) {
2030
+ switch (method.toUpperCase()) {
2031
+ case 'GET':
2032
+ return this.get(path, options);
2033
+ case 'POST':
2034
+ return this.post(path, options.body, options);
2035
+ case 'PUT':
2036
+ return this.put(path, options.body, options);
2037
+ case 'PATCH':
2038
+ return this.patch(path, options.body, options);
2039
+ case 'DELETE':
2040
+ return this.delete(path, options);
2041
+ default:
2042
+ throw new Error(`Unsupported HTTP method: ${method}`);
2036
2043
  }
2037
- catch (error) {
2038
- // Silent failure - telemetry errors shouldn't break functionality
2039
- console.debug('Failed to initialize OpenTelemetry:', error);
2044
+ }
2045
+ async requestWithSpec(spec) {
2046
+ if (!spec.method || !spec.url) {
2047
+ throw new Error('Request spec must include method and url');
2040
2048
  }
2049
+ return this.request(spec.method, spec.url, spec);
2050
+ }
2051
+ async get(path, options = {}) {
2052
+ const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").get(path, options);
2053
+ return { data: response };
2041
2054
  }
2042
- getConnectionString() {
2043
- const connectionString = CONNECTION_STRING;
2044
- return connectionString;
2055
+ async post(path, data, options = {}) {
2056
+ const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").post(path, data, options);
2057
+ return { data: response };
2045
2058
  }
2046
- setupTelemetryProvider(connectionString) {
2047
- const exporter = new ApplicationInsightsEventExporter(connectionString);
2048
- const processor = new sdkLogs.BatchLogRecordProcessor(exporter);
2049
- this.logProvider = new sdkLogs.LoggerProvider({
2050
- processors: [processor]
2051
- });
2052
- this.logger = this.logProvider.getLogger(SDK_LOGGER_NAME);
2059
+ async put(path, data, options = {}) {
2060
+ const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").put(path, data, options);
2061
+ return { data: response };
2062
+ }
2063
+ async patch(path, data, options = {}) {
2064
+ const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").patch(path, data, options);
2065
+ return { data: response };
2066
+ }
2067
+ async delete(path, options = {}) {
2068
+ const response = await __classPrivateFieldGet(this, _BaseService_apiClient, "f").delete(path, options);
2069
+ return { data: response };
2053
2070
  }
2054
2071
  /**
2055
- * Track a telemetry event
2072
+ * Execute a request with cursor-based pagination
2056
2073
  */
2057
- track(eventName, name, extraAttributes = {}) {
2058
- try {
2059
- // Skip if logger not initialized
2060
- if (!this.logger) {
2061
- return;
2062
- }
2063
- const finalDisplayName = name || eventName;
2064
- const attributes = this.getEnrichedAttributes(extraAttributes, eventName);
2065
- // Emit as log
2066
- this.logger.emit({
2067
- body: finalDisplayName,
2068
- attributes: attributes,
2069
- timestamp: Date.now(),
2070
- });
2074
+ async requestWithPagination(method, path, paginationOptions, options) {
2075
+ const paginationType = options.pagination.paginationType;
2076
+ // Validate and prepare pagination parameters
2077
+ const params = this.validateAndPreparePaginationParams(paginationType, paginationOptions);
2078
+ // Prepare request parameters based on pagination type
2079
+ const requestParams = this.preparePaginationRequestParams(paginationType, params, options.pagination);
2080
+ // For POST requests, merge pagination params into body; for GET, use query params
2081
+ if (method.toUpperCase() === 'POST') {
2082
+ const existingBody = (options.body && typeof options.body === 'object') ? options.body : {};
2083
+ options.body = {
2084
+ ...existingBody,
2085
+ ...options.params,
2086
+ ...requestParams
2087
+ };
2071
2088
  }
2072
- catch (error) {
2073
- // Silent failure
2074
- console.debug('Failed to track telemetry event:', error);
2089
+ else {
2090
+ // Merge pagination parameters with existing parameters
2091
+ options.params = {
2092
+ ...options.params,
2093
+ ...requestParams
2094
+ };
2075
2095
  }
2096
+ // Make the request
2097
+ const response = await this.request(method, path, options);
2098
+ // Extract data from the response and create page result
2099
+ return this.createPaginatedResponseFromResponse(response, params, paginationType, {
2100
+ itemsField: options.pagination.itemsField,
2101
+ totalCountField: options.pagination.totalCountField,
2102
+ continuationTokenField: options.pagination.continuationTokenField
2103
+ });
2076
2104
  }
2077
2105
  /**
2078
- * Get enriched attributes for telemetry events
2106
+ * Validates and prepares pagination parameters from options
2079
2107
  */
2080
- getEnrichedAttributes(extraAttributes, eventName) {
2081
- const attributes = {
2082
- [APP_NAME]: SDK_SERVICE_NAME,
2083
- [VERSION]: SDK_VERSION,
2084
- [SERVICE]: eventName,
2085
- [CLOUD_URL]: this.createCloudUrl(),
2086
- [CLOUD_ORGANIZATION_NAME]: this.telemetryContext?.orgName || UNKNOWN,
2087
- [CLOUD_TENANT_NAME]: this.telemetryContext?.tenantName || UNKNOWN,
2088
- [CLOUD_REDIRECT_URI]: this.telemetryContext?.redirectUri || UNKNOWN,
2089
- [CLOUD_CLIENT_ID]: this.telemetryContext?.clientId || UNKNOWN,
2090
- ...extraAttributes,
2091
- };
2092
- return attributes;
2108
+ validateAndPreparePaginationParams(paginationType, paginationOptions) {
2109
+ return PaginationHelpers.validatePaginationOptions(paginationOptions, paginationType);
2093
2110
  }
2094
2111
  /**
2095
- * Create cloud URL from base URL, organization ID, and tenant ID
2112
+ * Prepares request parameters for pagination based on pagination type
2096
2113
  */
2097
- createCloudUrl() {
2098
- const baseUrl = this.telemetryContext?.baseUrl;
2099
- const orgId = this.telemetryContext?.orgName;
2100
- const tenantId = this.telemetryContext?.tenantName;
2101
- if (!baseUrl || !orgId || !tenantId) {
2102
- return UNKNOWN;
2114
+ preparePaginationRequestParams(paginationType, params, paginationConfig) {
2115
+ const requestParams = {};
2116
+ let limitedPageSize;
2117
+ const paginationParams = paginationConfig?.paginationParams;
2118
+ switch (paginationType) {
2119
+ case PaginationType.OFFSET:
2120
+ limitedPageSize = getLimitedPageSize(params.pageSize);
2121
+ const pageSizeParam = paginationParams?.pageSizeParam || ODATA_OFFSET_PARAMS.PAGE_SIZE_PARAM;
2122
+ const offsetParam = paginationParams?.offsetParam || ODATA_OFFSET_PARAMS.OFFSET_PARAM;
2123
+ const countParam = paginationParams?.countParam || ODATA_OFFSET_PARAMS.COUNT_PARAM;
2124
+ requestParams[pageSizeParam] = limitedPageSize;
2125
+ if (params.pageNumber && params.pageNumber > 1) {
2126
+ requestParams[offsetParam] = (params.pageNumber - 1) * limitedPageSize;
2127
+ }
2128
+ // Include total count for ODATA APIs
2129
+ {
2130
+ requestParams[countParam] = true;
2131
+ }
2132
+ break;
2133
+ case PaginationType.TOKEN:
2134
+ const tokenPageSizeParam = paginationParams?.pageSizeParam || BUCKET_TOKEN_PARAMS.PAGE_SIZE_PARAM;
2135
+ const tokenParam = paginationParams?.tokenParam || BUCKET_TOKEN_PARAMS.TOKEN_PARAM;
2136
+ if (params.pageSize) {
2137
+ requestParams[tokenPageSizeParam] = getLimitedPageSize(params.pageSize);
2138
+ }
2139
+ if (params.continuationToken) {
2140
+ requestParams[tokenParam] = params.continuationToken;
2141
+ }
2142
+ break;
2103
2143
  }
2104
- return `${baseUrl}/${orgId}/${tenantId}`;
2144
+ return requestParams;
2105
2145
  }
2106
- }
2107
- // Export singleton instance
2108
- const telemetryClient = TelemetryClient.getInstance();
2109
-
2110
- /**
2111
- * SDK Track decorator and function for telemetry
2112
- */
2113
- /**
2114
- * Common tracking logic shared between method and function decorators
2115
- */
2116
- function createTrackedFunction(originalFunction, nameOrOptions, fallbackName, opts) {
2117
- return function (...args) {
2118
- // Determine if we should track this call
2119
- let shouldTrack = true;
2120
- if (opts.condition !== undefined) {
2121
- if (typeof opts.condition === 'function') {
2122
- shouldTrack = opts.condition.apply(this, args);
2123
- }
2124
- else {
2125
- shouldTrack = opts.condition;
2126
- }
2127
- }
2128
- // Track the event if enabled
2129
- if (shouldTrack) {
2130
- // Use the full name provided in the decorator (e.g., "Queue.GetAll")
2131
- const serviceMethod = typeof nameOrOptions === 'string'
2132
- ? nameOrOptions
2133
- : fallbackName;
2134
- // Use 'Sdk.Run' as the name and serviceMethod as the service
2135
- telemetryClient.track(serviceMethod, SDK_RUN_EVENT, opts.attributes);
2136
- }
2137
- // Execute the original function
2138
- return originalFunction.apply(this, args);
2139
- };
2140
- }
2141
- /**
2142
- * Track decorator that can be used to automatically track function calls
2143
- *
2144
- * Usage:
2145
- * @track("Service.Method")
2146
- * function myFunction() { ... }
2147
- *
2148
- * @track("Queue.GetAll")
2149
- * async getAll() { ... }
2150
- *
2151
- * @track("Tasks.Create")
2152
- * async create() { ... }
2153
- *
2154
- * @track("Assets.Update", { condition: false })
2155
- * function myFunction() { ... }
2156
- *
2157
- * @track("Processes.Start", { attributes: { customProp: "value" } })
2158
- * function myFunction() { ... }
2159
- */
2160
- function track(nameOrOptions, options) {
2161
- return function decorator(_target, propertyKey, descriptor) {
2162
- const opts = typeof nameOrOptions === 'object' ? nameOrOptions : {};
2163
- if (descriptor && typeof descriptor.value === 'function') {
2164
- // Method decorator
2165
- descriptor.value = createTrackedFunction(descriptor.value, nameOrOptions, propertyKey || 'unknown_method', opts);
2166
- return descriptor;
2146
+ /**
2147
+ * Creates a paginated response from API response
2148
+ */
2149
+ createPaginatedResponseFromResponse(response, params, paginationType, fields) {
2150
+ // Extract fields from response
2151
+ const itemsField = fields.itemsField ||
2152
+ (paginationType === PaginationType.TOKEN ? 'items' : 'value');
2153
+ const totalCountField = fields.totalCountField || 'totalRecordCount';
2154
+ const continuationTokenField = fields.continuationTokenField || 'continuationToken';
2155
+ // Extract items and metadata
2156
+ const items = response.data[itemsField] || [];
2157
+ const totalCount = response.data[totalCountField];
2158
+ const continuationToken = response.data[continuationTokenField];
2159
+ // Determine if there are more pages
2160
+ const hasMore = this.determineHasMorePages(paginationType, {
2161
+ totalCount,
2162
+ pageSize: params.pageSize,
2163
+ currentPage: params.pageNumber || 1,
2164
+ itemsCount: items.length,
2165
+ continuationToken
2166
+ });
2167
+ // Create and return the page result
2168
+ return PaginationManager.createPaginatedResponse({
2169
+ pageInfo: {
2170
+ hasMore,
2171
+ totalCount,
2172
+ currentPage: params.pageNumber,
2173
+ pageSize: params.pageSize,
2174
+ continuationToken
2175
+ },
2176
+ type: paginationType,
2177
+ }, items);
2178
+ }
2179
+ /**
2180
+ * Determines if there are more pages based on pagination type and metadata
2181
+ */
2182
+ determineHasMorePages(paginationType, info) {
2183
+ switch (paginationType) {
2184
+ case PaginationType.OFFSET:
2185
+ const effectivePageSize = info.pageSize ?? DEFAULT_PAGE_SIZE;
2186
+ // If totalCount is available, use it for precise calculation
2187
+ if (info.totalCount !== undefined) {
2188
+ return (info.currentPage * effectivePageSize) < info.totalCount;
2189
+ }
2190
+ // Fallback when totalCount is not available
2191
+ // NOTE: This code path should rarely be executed as the APIs typically return totalCount
2192
+ return info.itemsCount === effectivePageSize;
2193
+ case PaginationType.TOKEN:
2194
+ return !!info.continuationToken;
2195
+ default:
2196
+ return false;
2167
2197
  }
2168
- // Function decorator
2169
- return (originalFunction) => createTrackedFunction(originalFunction, nameOrOptions, originalFunction.name || 'unknown_function', opts);
2170
- };
2198
+ }
2171
2199
  }
2200
+ _BaseService_apiClient = new WeakMap();
2172
2201
 
2173
2202
  /**
2174
2203
  * Service for interacting with UiPath Tasks API
@@ -2364,29 +2393,38 @@ class TaskService extends BaseService {
2364
2393
  }
2365
2394
  /**
2366
2395
  * Gets a task by ID
2367
- * IMPORTANT: For form tasks, folderId must be provided.
2368
- *
2369
2396
  * @param id - The ID of the task to retrieve
2370
- * @param options - Optional query parameters
2371
- * @param folderId - Optional folder ID (REQUIRED for form tasks)
2372
- * @returns Promise resolving to the task (form tasks will return form-specific data)
2373
- *
2397
+ * @param options - Optional query parameters including taskType for faster retrieval {@link TaskGetByIdOptions}
2398
+ * @param folderId - Optional folder ID (REQUIRED when options.taskType is provided)
2399
+ * @returns Promise resolving to the task
2400
+ * {@link TaskGetResponse}
2374
2401
  * @example
2375
2402
  * ```typescript
2376
- * import { Tasks } from '@uipath/uipath-typescript/tasks';
2403
+ * // Get a task by ID
2404
+ * const task = await tasks.getById(<taskId>);
2377
2405
  *
2378
- * const tasks = new Tasks(sdk);
2406
+ * // Get a form task by ID
2407
+ * const formTask = await tasks.getById(<taskId>, {}, <folderId>);
2379
2408
  *
2380
- * // Get task by ID
2381
- * const task = await tasks.getById(123);
2409
+ * // Access form task properties
2410
+ * console.log(formTask.formLayout);
2382
2411
  *
2383
- * // If the task is a form task, it will automatically return form-specific data
2412
+ * // Get a document validation task by ID (faster with taskType provided in the options)
2413
+ * const dvTask = await tasks.getById(<taskId>, { taskType: TaskType.DocumentValidation }, <folderId>);
2384
2414
  * ```
2385
2415
  */
2386
2416
  async getById(id, options = {}, folderId) {
2417
+ const { taskType, ...restOptions } = options;
2418
+ // If taskType is provided, skip the generic GET_BY_ID call and go directly to the type-specific endpoint
2419
+ if (taskType && taskType in TASK_TYPE_ENDPOINTS) {
2420
+ if (!folderId) {
2421
+ throw new ValidationError({ message: 'folderId is required when taskType is provided' });
2422
+ }
2423
+ return this.getByTaskType(id, folderId, taskType, restOptions);
2424
+ }
2387
2425
  const headers = createHeaders({ [FOLDER_ID]: folderId });
2388
2426
  // Add default expand parameters
2389
- const modifiedOptions = this.addDefaultExpand(options);
2427
+ const modifiedOptions = this.addDefaultExpand(restOptions);
2390
2428
  // prefix all keys in options
2391
2429
  const keysToPrefix = Object.keys(modifiedOptions);
2392
2430
  const apiOptions = addPrefixToKeys(modifiedOptions, ODATA_PREFIX, keysToPrefix);
@@ -2396,10 +2434,10 @@ class TaskService extends BaseService {
2396
2434
  });
2397
2435
  // Transform response from PascalCase to camelCase and normalize time fields
2398
2436
  const transformedTask = transformData(pascalToCamelCaseKeys(response.data), TaskMap);
2399
- // Check if this is a form task and get form-specific data if it is
2400
- if (transformedTask.type === exports.TaskType.Form) {
2401
- const formOptions = { expandOnFormLayout: true };
2402
- return this.getFormTaskById(id, folderId || transformedTask.folderId, formOptions);
2437
+ // Get task type from response and fetch type-specific data
2438
+ const resolvedFolderId = folderId || transformedTask.folderId;
2439
+ if (transformedTask.type in TASK_TYPE_ENDPOINTS) {
2440
+ return this.getByTaskType(id, resolvedFolderId, transformedTask.type, restOptions);
2403
2441
  }
2404
2442
  return createTaskWithMethods(applyDataTransforms(transformedTask, { field: 'status', valueMap: TaskStatusMap }), this);
2405
2443
  }
@@ -2588,24 +2626,33 @@ class TaskService extends BaseService {
2588
2626
  };
2589
2627
  }
2590
2628
  /**
2591
- * Gets a form task by ID (private method)
2629
+ * Routes to the type-specific endpoint based on task type.
2630
+ */
2631
+ getByTaskType(id, folderId, taskType, options = {}) {
2632
+ const endpoint = TASK_TYPE_ENDPOINTS[taskType];
2633
+ const extraParams = taskType === exports.TaskType.Form ? { expandOnFormLayout: true, ...options } : options;
2634
+ return this.getTaskByTypeEndpoint(id, folderId, endpoint, extraParams);
2635
+ }
2636
+ /**
2637
+ * Fetches a task from a type-specific endpoint.
2592
2638
  *
2593
- * @param id - The ID of the form task to retrieve
2639
+ * @param id - The task ID
2594
2640
  * @param folderId - Required folder ID
2595
- * @param options - Optional query parameters
2596
- * @returns Promise resolving to the form task
2641
+ * @param endpoint - The type-specific endpoint to call
2642
+ * @param extraParams - Additional query parameters (e.g. form options)
2643
+ * @returns Promise resolving to the task
2597
2644
  */
2598
- async getFormTaskById(id, folderId, options = {}) {
2645
+ async getTaskByTypeEndpoint(id, folderId, endpoint, extraParams = {}) {
2599
2646
  const headers = createHeaders({ [FOLDER_ID]: folderId });
2600
- const response = await this.get(TASK_ENDPOINTS.GET_TASK_FORM_BY_ID, {
2647
+ const response = await this.get(endpoint, {
2601
2648
  params: {
2602
2649
  taskId: id,
2603
- ...options
2650
+ ...extraParams
2604
2651
  },
2605
2652
  headers
2606
2653
  });
2607
- const transformedFormTask = transformData(response.data, TaskMap);
2608
- return createTaskWithMethods(applyDataTransforms(transformedFormTask, { field: 'status', valueMap: TaskStatusMap }), this);
2654
+ const transformedTask = transformData(response.data, TaskMap);
2655
+ return createTaskWithMethods(applyDataTransforms(transformedTask, { field: 'status', valueMap: TaskStatusMap }), this);
2609
2656
  }
2610
2657
  /**
2611
2658
  * Adds default expand parameters to options