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