@jaak.ai/stamps 2.2.0-dev.6 → 2.2.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 (30) hide show
  1. package/README.md +188 -8
  2. package/dist/cjs/jaak-stamps.cjs.entry.js +657 -3118
  3. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  4. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  5. package/dist/collection/components/my-component/my-component.css +23 -2
  6. package/dist/collection/components/my-component/my-component.js +42 -16
  7. package/dist/collection/components/my-component/my-component.js.map +1 -1
  8. package/dist/collection/services/CameraService.js +41 -9
  9. package/dist/collection/services/CameraService.js.map +1 -1
  10. package/dist/collection/services/LicenseValidationService.js +2 -2
  11. package/dist/collection/services/LicenseValidationService.js.map +1 -1
  12. package/dist/collection/services/TracingService.js +130 -78
  13. package/dist/collection/services/TracingService.js.map +1 -1
  14. package/dist/collection/services/interfaces/ITracingService.js.map +1 -1
  15. package/dist/components/jaak-stamps.js +657 -3118
  16. package/dist/components/jaak-stamps.js.map +1 -1
  17. package/dist/esm/jaak-stamps.entry.js +657 -3118
  18. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  19. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  20. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  21. package/dist/jaak-stamps-webcomponent/p-34bcebb1.entry.js +7 -0
  22. package/dist/jaak-stamps-webcomponent/p-34bcebb1.entry.js.map +1 -0
  23. package/dist/types/components/my-component/my-component.d.ts +2 -1
  24. package/dist/types/components.d.ts +2 -2
  25. package/dist/types/services/LicenseValidationService.d.ts +1 -1
  26. package/dist/types/services/TracingService.d.ts +6 -1
  27. package/dist/types/services/interfaces/ITracingService.d.ts +5 -0
  28. package/package.json +1 -1
  29. package/dist/jaak-stamps-webcomponent/p-8c49893d.entry.js +0 -7
  30. package/dist/jaak-stamps-webcomponent/p-8c49893d.entry.js.map +0 -1
@@ -530,17 +530,30 @@ class CameraService {
530
530
  }
531
531
  const constraints = { ...videoConstraints };
532
532
  if (capabilities.width && capabilities.height) {
533
- const maxWidth = Math.min(capabilities.width.max, 1920);
534
- const maxHeight = Math.min(capabilities.height.max, 1080);
535
533
  const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
536
- if (isTablet) {
537
- constraints.width = { ideal: Math.min(maxWidth, 1280) };
538
- constraints.height = { ideal: Math.min(maxHeight, 720) };
534
+ const isMobileDevice = this.deviceType === 'mobile' ||
535
+ /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
536
+ // Optimize resolution based on device type to prevent "slow motion" effect
537
+ // on devices with high-resolution cameras
538
+ let targetWidth;
539
+ let targetHeight;
540
+ if (isMobileDevice && !isTablet) {
541
+ // Mobile phones: Use 720p max to ensure smooth detection performance
542
+ targetWidth = Math.min(capabilities.width.max, 1280);
543
+ targetHeight = Math.min(capabilities.height.max, 720);
544
+ }
545
+ else if (isTablet) {
546
+ // Tablets: Can handle slightly higher resolution
547
+ targetWidth = Math.min(capabilities.width.max, 1280);
548
+ targetHeight = Math.min(capabilities.height.max, 720);
539
549
  }
540
550
  else {
541
- constraints.width = { ideal: maxWidth };
542
- constraints.height = { ideal: maxHeight };
551
+ // Desktop: Can handle full HD
552
+ targetWidth = Math.min(capabilities.width.max, 1920);
553
+ targetHeight = Math.min(capabilities.height.max, 1080);
543
554
  }
555
+ constraints.width = { ideal: targetWidth };
556
+ constraints.height = { ideal: targetHeight };
544
557
  }
545
558
  // Configure autofocus if camera has the capability
546
559
  const capabilitiesAny = capabilities;
@@ -560,9 +573,28 @@ class CameraService {
560
573
  await this.detectDeviceType();
561
574
  }
562
575
  const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
576
+ const isMobileDevice = this.deviceType === 'mobile' ||
577
+ /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
578
+ // Optimized fallback constraints for device type
579
+ let fallbackWidth;
580
+ let fallbackHeight;
581
+ if (isMobileDevice && !isTablet) {
582
+ // Mobile phones: Use 720p for smooth performance
583
+ fallbackWidth = 1280;
584
+ fallbackHeight = 720;
585
+ }
586
+ else if (isTablet) {
587
+ fallbackWidth = 1280;
588
+ fallbackHeight = 720;
589
+ }
590
+ else {
591
+ // Desktop
592
+ fallbackWidth = 1920;
593
+ fallbackHeight = 1080;
594
+ }
563
595
  const fallbackConstraints = {
564
- width: { ideal: isTablet ? 1280 : 1920 },
565
- height: { ideal: isTablet ? 720 : 1080 }
596
+ width: { ideal: fallbackWidth },
597
+ height: { ideal: fallbackHeight }
566
598
  };
567
599
  if (this.selectedCameraId) {
568
600
  fallbackConstraints.deviceId = { exact: this.selectedCameraId };
@@ -1178,7 +1210,7 @@ class DetectionService {
1178
1210
  */
1179
1211
  /** only globals that common to node and browsers are allowed */
1180
1212
  // eslint-disable-next-line node/no-unsupported-features/es-builtins, no-undef
1181
- var _globalThis$2 = typeof globalThis === 'object'
1213
+ var _globalThis$1 = typeof globalThis === 'object'
1182
1214
  ? globalThis
1183
1215
  : typeof self === 'object'
1184
1216
  ? self
@@ -1204,7 +1236,7 @@ var _globalThis$2 = typeof globalThis === 'object'
1204
1236
  * limitations under the License.
1205
1237
  */
1206
1238
  // this is autogenerated file, see scripts/version-update.js
1207
- var VERSION$4 = '1.9.0';
1239
+ var VERSION$2 = '1.9.0';
1208
1240
 
1209
1241
  /*
1210
1242
  * Copyright The OpenTelemetry Authors
@@ -1321,7 +1353,7 @@ function _makeCompatibilityCheck(ownVersion) {
1321
1353
  *
1322
1354
  * @param version version of the API requesting an instance of the global API
1323
1355
  */
1324
- var isCompatible = _makeCompatibilityCheck(VERSION$4);
1356
+ var isCompatible = _makeCompatibilityCheck(VERSION$2);
1325
1357
 
1326
1358
  /*
1327
1359
  * Copyright The OpenTelemetry Authors
@@ -1338,14 +1370,14 @@ var isCompatible = _makeCompatibilityCheck(VERSION$4);
1338
1370
  * See the License for the specific language governing permissions and
1339
1371
  * limitations under the License.
1340
1372
  */
1341
- var major = VERSION$4.split('.')[0];
1373
+ var major = VERSION$2.split('.')[0];
1342
1374
  var GLOBAL_OPENTELEMETRY_API_KEY = Symbol.for("opentelemetry.js.api." + major);
1343
- var _global$1 = _globalThis$2;
1375
+ var _global$1 = _globalThis$1;
1344
1376
  function registerGlobal(type, instance, diag, allowOverride) {
1345
1377
  var _a;
1346
1378
  if (allowOverride === void 0) { allowOverride = false; }
1347
1379
  var api = (_global$1[GLOBAL_OPENTELEMETRY_API_KEY] = (_a = _global$1[GLOBAL_OPENTELEMETRY_API_KEY]) !== null && _a !== void 0 ? _a : {
1348
- version: VERSION$4,
1380
+ version: VERSION$2,
1349
1381
  });
1350
1382
  if (!allowOverride && api[type]) {
1351
1383
  // already registered an API of this type
@@ -1353,14 +1385,14 @@ function registerGlobal(type, instance, diag, allowOverride) {
1353
1385
  diag.error(err.stack || err.message);
1354
1386
  return false;
1355
1387
  }
1356
- if (api.version !== VERSION$4) {
1388
+ if (api.version !== VERSION$2) {
1357
1389
  // All registered APIs must be of the same version exactly
1358
- var err = new Error("@opentelemetry/api: Registration of version v" + api.version + " for " + type + " does not match previously registered API v" + VERSION$4);
1390
+ var err = new Error("@opentelemetry/api: Registration of version v" + api.version + " for " + type + " does not match previously registered API v" + VERSION$2);
1359
1391
  diag.error(err.stack || err.message);
1360
1392
  return false;
1361
1393
  }
1362
1394
  api[type] = instance;
1363
- diag.debug("@opentelemetry/api: Registered a global for " + type + " v" + VERSION$4 + ".");
1395
+ diag.debug("@opentelemetry/api: Registered a global for " + type + " v" + VERSION$2 + ".");
1364
1396
  return true;
1365
1397
  }
1366
1398
  function getGlobal(type) {
@@ -1372,7 +1404,7 @@ function getGlobal(type) {
1372
1404
  return (_b = _global$1[GLOBAL_OPENTELEMETRY_API_KEY]) === null || _b === void 0 ? void 0 : _b[type];
1373
1405
  }
1374
1406
  function unregisterGlobal(type, diag) {
1375
- diag.debug("@opentelemetry/api: Unregistering a global for " + type + " v" + VERSION$4 + ".");
1407
+ diag.debug("@opentelemetry/api: Unregistering a global for " + type + " v" + VERSION$2 + ".");
1376
1408
  var api = _global$1[GLOBAL_OPENTELEMETRY_API_KEY];
1377
1409
  if (api) {
1378
1410
  delete api[type];
@@ -3608,41 +3640,6 @@ function getNumberFromEnv(_) {
3608
3640
  return undefined;
3609
3641
  }
3610
3642
 
3611
- /*
3612
- * Copyright The OpenTelemetry Authors
3613
- *
3614
- * Licensed under the Apache License, Version 2.0 (the "License");
3615
- * you may not use this file except in compliance with the License.
3616
- * You may obtain a copy of the License at
3617
- *
3618
- * https://www.apache.org/licenses/LICENSE-2.0
3619
- *
3620
- * Unless required by applicable law or agreed to in writing, software
3621
- * distributed under the License is distributed on an "AS IS" BASIS,
3622
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3623
- * See the License for the specific language governing permissions and
3624
- * limitations under the License.
3625
- */
3626
- // Updates to this file should also be replicated to @opentelemetry/api too.
3627
- /**
3628
- * - globalThis (New standard)
3629
- * - self (Will return the current window instance for supported browsers)
3630
- * - window (fallback for older browser implementations)
3631
- * - global (NodeJS implementation)
3632
- * - <object> (When all else fails)
3633
- */
3634
- /** only globals that common to node and browsers are allowed */
3635
- // eslint-disable-next-line n/no-unsupported-features/es-builtins, no-undef
3636
- const _globalThis$1 = typeof globalThis === 'object'
3637
- ? globalThis
3638
- : typeof self === 'object'
3639
- ? self
3640
- : typeof window === 'object'
3641
- ? window
3642
- : typeof global === 'object'
3643
- ? global
3644
- : {};
3645
-
3646
3643
  /*
3647
3644
  * Copyright The OpenTelemetry Authors
3648
3645
  *
@@ -3676,7 +3673,7 @@ const otperformance = performance;
3676
3673
  * limitations under the License.
3677
3674
  */
3678
3675
  // this is autogenerated file, see scripts/version-update.js
3679
- const VERSION$3 = '2.2.0';
3676
+ const VERSION$1 = '2.2.0';
3680
3677
 
3681
3678
  /*
3682
3679
  * Copyright The OpenTelemetry Authors
@@ -3702,35 +3699,6 @@ const VERSION$3 = '2.2.0';
3702
3699
  * @example handled
3703
3700
  * @example unhandled
3704
3701
  */
3705
- /**
3706
- * Describes a class of error the operation ended with.
3707
- *
3708
- * @example timeout
3709
- * @example java.net.UnknownHostException
3710
- * @example server_certificate_invalid
3711
- * @example 500
3712
- *
3713
- * @note The `error.type` **SHOULD** be predictable, and **SHOULD** have low cardinality.
3714
- *
3715
- * When `error.type` is set to a type (e.g., an exception type), its
3716
- * canonical class name identifying the type within the artifact **SHOULD** be used.
3717
- *
3718
- * Instrumentations **SHOULD** document the list of errors they report.
3719
- *
3720
- * The cardinality of `error.type` within one instrumentation library **SHOULD** be low.
3721
- * Telemetry consumers that aggregate data from multiple instrumentation libraries and applications
3722
- * should be prepared for `error.type` to have high cardinality at query time when no
3723
- * additional filters are applied.
3724
- *
3725
- * If the operation has completed successfully, instrumentations **SHOULD NOT** set `error.type`.
3726
- *
3727
- * If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes),
3728
- * it's **RECOMMENDED** to:
3729
- *
3730
- * - Use a domain-specific attribute
3731
- * - Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not.
3732
- */
3733
- const ATTR_ERROR_TYPE = 'error.type';
3734
3702
  /**
3735
3703
  * The exception message.
3736
3704
  *
@@ -3751,64 +3719,6 @@ const ATTR_EXCEPTION_STACKTRACE = 'exception.stacktrace';
3751
3719
  * @example OSError
3752
3720
  */
3753
3721
  const ATTR_EXCEPTION_TYPE = 'exception.type';
3754
- /**
3755
- * HTTP request method.
3756
- *
3757
- * @example GET
3758
- * @example POST
3759
- * @example HEAD
3760
- *
3761
- * @note HTTP request method value **SHOULD** be "known" to the instrumentation.
3762
- * By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods),
3763
- * the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html)
3764
- * and the QUERY method defined in [httpbis-safe-method-w-body](https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/?include_text=1).
3765
- *
3766
- * If the HTTP request method is not known to instrumentation, it **MUST** set the `http.request.method` attribute to `_OTHER`.
3767
- *
3768
- * If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it **MUST** provide a way to override
3769
- * the list of known HTTP methods. If this override is done via environment variable, then the environment variable **MUST** be named
3770
- * OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods
3771
- * (this list **MUST** be a full override of the default known method, it is not a list of known methods in addition to the defaults).
3772
- *
3773
- * HTTP method names are case-sensitive and `http.request.method` attribute value **MUST** match a known HTTP method name exactly.
3774
- * Instrumentations for specific web frameworks that consider HTTP methods to be case insensitive, **SHOULD** populate a canonical equivalent.
3775
- * Tracing instrumentations that do so, **MUST** also set `http.request.method_original` to the original value.
3776
- */
3777
- const ATTR_HTTP_REQUEST_METHOD = 'http.request.method';
3778
- /**
3779
- * Original HTTP method sent by the client in the request line.
3780
- *
3781
- * @example GeT
3782
- * @example ACL
3783
- * @example foo
3784
- */
3785
- const ATTR_HTTP_REQUEST_METHOD_ORIGINAL = 'http.request.method_original';
3786
- /**
3787
- * [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).
3788
- *
3789
- * @example 200
3790
- */
3791
- const ATTR_HTTP_RESPONSE_STATUS_CODE = 'http.response.status_code';
3792
- /**
3793
- * Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.
3794
- *
3795
- * @example example.com
3796
- * @example 10.1.2.80
3797
- * @example /tmp/my.sock
3798
- *
3799
- * @note When observed from the client side, and when communicating through an intermediary, `server.address` **SHOULD** represent the server address behind any intermediaries, for example proxies, if it's available.
3800
- */
3801
- const ATTR_SERVER_ADDRESS = 'server.address';
3802
- /**
3803
- * Server port number.
3804
- *
3805
- * @example 80
3806
- * @example 8080
3807
- * @example 443
3808
- *
3809
- * @note When observed from the client side, and when communicating through an intermediary, `server.port` **SHOULD** represent the server port behind any intermediaries, for example proxies, if it's available.
3810
- */
3811
- const ATTR_SERVER_PORT = 'server.port';
3812
3722
  /**
3813
3723
  * Logical name of the service.
3814
3724
  *
@@ -3844,45 +3754,6 @@ const ATTR_TELEMETRY_SDK_NAME = 'telemetry.sdk.name';
3844
3754
  * @example 1.2.3
3845
3755
  */
3846
3756
  const ATTR_TELEMETRY_SDK_VERSION = 'telemetry.sdk.version';
3847
- /**
3848
- * Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986)
3849
- *
3850
- * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv
3851
- * @example //localhost
3852
- *
3853
- * @note For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment
3854
- * is not transmitted over HTTP, but if it is known, it **SHOULD** be included nevertheless.
3855
- *
3856
- * `url.full` **MUST NOT** contain credentials passed via URL in form of `https://username:password@www.example.com/`.
3857
- * In such case username and password **SHOULD** be redacted and attribute's value **SHOULD** be `https://REDACTED:REDACTED@www.example.com/`.
3858
- *
3859
- * `url.full` **SHOULD** capture the absolute URL when it is available (or can be reconstructed).
3860
- *
3861
- * Sensitive content provided in `url.full` **SHOULD** be scrubbed when instrumentations can identify it.
3862
- *
3863
- *
3864
- * Query string values for the following keys **SHOULD** be redacted by default and replaced by the
3865
- * value `REDACTED`:
3866
- *
3867
- * - [`AWSAccessKeyId`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTAuthentication.html#RESTAuthenticationQueryStringAuth)
3868
- * - [`Signature`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTAuthentication.html#RESTAuthenticationQueryStringAuth)
3869
- * - [`sig`](https://learn.microsoft.com/azure/storage/common/storage-sas-overview#sas-token)
3870
- * - [`X-Goog-Signature`](https://cloud.google.com/storage/docs/access-control/signed-urls)
3871
- *
3872
- * This list is subject to change over time.
3873
- *
3874
- * When a query string value is redacted, the query string key **SHOULD** still be preserved, e.g.
3875
- * `https://www.example.com/path?color=blue&sig=REDACTED`.
3876
- */
3877
- const ATTR_URL_FULL = 'url.full';
3878
- /**
3879
- * Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.
3880
- *
3881
- * @example CERN-LineMode/2.15 libwww/2.17b3
3882
- * @example Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1
3883
- * @example YourApp/1.0.0 grpc-java-okhttp/1.27.2
3884
- */
3885
- const ATTR_USER_AGENT_ORIGINAL = 'user_agent.original';
3886
3757
 
3887
3758
  /*
3888
3759
  * Copyright The OpenTelemetry Authors
@@ -3933,7 +3804,7 @@ const SDK_INFO = {
3933
3804
  [ATTR_TELEMETRY_SDK_NAME]: 'opentelemetry',
3934
3805
  [ATTR_PROCESS_RUNTIME_NAME]: 'browser',
3935
3806
  [ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS,
3936
- [ATTR_TELEMETRY_SDK_VERSION]: VERSION$3,
3807
+ [ATTR_TELEMETRY_SDK_VERSION]: VERSION$1,
3937
3808
  };
3938
3809
 
3939
3810
  /*
@@ -3984,33 +3855,6 @@ function hrTime(performanceNow) {
3984
3855
  const now = millisToHrTime(typeof performanceNow === 'number' ? performanceNow : otperformance.now());
3985
3856
  return addHrTimes(timeOrigin, now);
3986
3857
  }
3987
- /**
3988
- *
3989
- * Converts a TimeInput to an HrTime, defaults to _hrtime().
3990
- * @param time
3991
- */
3992
- function timeInputToHrTime(time) {
3993
- // process.hrtime
3994
- if (isTimeInputHrTime(time)) {
3995
- return time;
3996
- }
3997
- else if (typeof time === 'number') {
3998
- // Must be a performance.now() if it's smaller than process start time.
3999
- if (time < getTimeOrigin()) {
4000
- return hrTime(time);
4001
- }
4002
- else {
4003
- // epoch milliseconds or performance.timeOrigin
4004
- return millisToHrTime(time);
4005
- }
4006
- }
4007
- else if (time instanceof Date) {
4008
- return millisToHrTime(time.getTime());
4009
- }
4010
- else {
4011
- throw TypeError('Invalid input type');
4012
- }
4013
- }
4014
3858
  /**
4015
3859
  * Returns a duration of two hrTime.
4016
3860
  * @param startTime
@@ -4323,7 +4167,7 @@ class TraceState {
4323
4167
  */
4324
4168
  const TRACE_PARENT_HEADER = 'traceparent';
4325
4169
  const TRACE_STATE_HEADER = 'tracestate';
4326
- const VERSION$2 = '00';
4170
+ const VERSION = '00';
4327
4171
  const VERSION_PART = '(?!ff)[\\da-f]{2}';
4328
4172
  const TRACE_ID_PART = '(?![0]{32})[\\da-f]{32}';
4329
4173
  const PARENT_ID_PART = '(?![0]{16})[\\da-f]{16}';
@@ -4367,7 +4211,7 @@ class W3CTraceContextPropagator {
4367
4211
  isTracingSuppressed(context) ||
4368
4212
  !isSpanContextValid(spanContext))
4369
4213
  return;
4370
- const traceParent = `${VERSION$2}-${spanContext.traceId}-${spanContext.spanId}-0${Number(spanContext.traceFlags || TraceFlags.NONE).toString(16)}`;
4214
+ const traceParent = `${VERSION}-${spanContext.traceId}-${spanContext.spanId}-0${Number(spanContext.traceFlags || TraceFlags.NONE).toString(16)}`;
4371
4215
  setter.set(carrier, TRACE_PARENT_HEADER, traceParent);
4372
4216
  if (spanContext.traceState) {
4373
4217
  setter.set(carrier, TRACE_STATE_HEADER, spanContext.traceState.serialize());
@@ -4712,46 +4556,6 @@ function shouldMerge(one, two) {
4712
4556
  return true;
4713
4557
  }
4714
4558
 
4715
- /*
4716
- * Copyright The OpenTelemetry Authors
4717
- *
4718
- * Licensed under the Apache License, Version 2.0 (the "License");
4719
- * you may not use this file except in compliance with the License.
4720
- * You may obtain a copy of the License at
4721
- *
4722
- * https://www.apache.org/licenses/LICENSE-2.0
4723
- *
4724
- * Unless required by applicable law or agreed to in writing, software
4725
- * distributed under the License is distributed on an "AS IS" BASIS,
4726
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4727
- * See the License for the specific language governing permissions and
4728
- * limitations under the License.
4729
- */
4730
- function urlMatches(url, urlToMatch) {
4731
- if (typeof urlToMatch === 'string') {
4732
- return url === urlToMatch;
4733
- }
4734
- else {
4735
- return !!url.match(urlToMatch);
4736
- }
4737
- }
4738
- /**
4739
- * Check if {@param url} should be ignored when comparing against {@param ignoredUrls}
4740
- * @param url
4741
- * @param ignoredUrls
4742
- */
4743
- function isUrlIgnored(url, ignoredUrls) {
4744
- if (!ignoredUrls) {
4745
- return false;
4746
- }
4747
- for (const ignoreUrl of ignoredUrls) {
4748
- if (urlMatches(url, ignoreUrl)) {
4749
- return true;
4750
- }
4751
- }
4752
- return false;
4753
- }
4754
-
4755
4559
  /*
4756
4560
  * Copyright The OpenTelemetry Authors
4757
4561
  *
@@ -6555,288 +6359,6 @@ class WebTracerProvider extends BasicTracerProvider {
6555
6359
  * See the License for the specific language governing permissions and
6556
6360
  * limitations under the License.
6557
6361
  */
6558
- var PerformanceTimingNames;
6559
- (function (PerformanceTimingNames) {
6560
- PerformanceTimingNames["CONNECT_END"] = "connectEnd";
6561
- PerformanceTimingNames["CONNECT_START"] = "connectStart";
6562
- PerformanceTimingNames["DECODED_BODY_SIZE"] = "decodedBodySize";
6563
- PerformanceTimingNames["DOM_COMPLETE"] = "domComplete";
6564
- PerformanceTimingNames["DOM_CONTENT_LOADED_EVENT_END"] = "domContentLoadedEventEnd";
6565
- PerformanceTimingNames["DOM_CONTENT_LOADED_EVENT_START"] = "domContentLoadedEventStart";
6566
- PerformanceTimingNames["DOM_INTERACTIVE"] = "domInteractive";
6567
- PerformanceTimingNames["DOMAIN_LOOKUP_END"] = "domainLookupEnd";
6568
- PerformanceTimingNames["DOMAIN_LOOKUP_START"] = "domainLookupStart";
6569
- PerformanceTimingNames["ENCODED_BODY_SIZE"] = "encodedBodySize";
6570
- PerformanceTimingNames["FETCH_START"] = "fetchStart";
6571
- PerformanceTimingNames["LOAD_EVENT_END"] = "loadEventEnd";
6572
- PerformanceTimingNames["LOAD_EVENT_START"] = "loadEventStart";
6573
- PerformanceTimingNames["NAVIGATION_START"] = "navigationStart";
6574
- PerformanceTimingNames["REDIRECT_END"] = "redirectEnd";
6575
- PerformanceTimingNames["REDIRECT_START"] = "redirectStart";
6576
- PerformanceTimingNames["REQUEST_START"] = "requestStart";
6577
- PerformanceTimingNames["RESPONSE_END"] = "responseEnd";
6578
- PerformanceTimingNames["RESPONSE_START"] = "responseStart";
6579
- PerformanceTimingNames["SECURE_CONNECTION_START"] = "secureConnectionStart";
6580
- PerformanceTimingNames["START_TIME"] = "startTime";
6581
- PerformanceTimingNames["UNLOAD_EVENT_END"] = "unloadEventEnd";
6582
- PerformanceTimingNames["UNLOAD_EVENT_START"] = "unloadEventStart";
6583
- })(PerformanceTimingNames || (PerformanceTimingNames = {}));
6584
-
6585
- /*
6586
- * Copyright The OpenTelemetry Authors
6587
- *
6588
- * Licensed under the Apache License, Version 2.0 (the "License");
6589
- * you may not use this file except in compliance with the License.
6590
- * You may obtain a copy of the License at
6591
- *
6592
- * https://www.apache.org/licenses/LICENSE-2.0
6593
- *
6594
- * Unless required by applicable law or agreed to in writing, software
6595
- * distributed under the License is distributed on an "AS IS" BASIS,
6596
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6597
- * See the License for the specific language governing permissions and
6598
- * limitations under the License.
6599
- */
6600
- /*
6601
- * This file contains a copy of unstable semantic convention definitions
6602
- * used by this package.
6603
- * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv
6604
- */
6605
- /**
6606
- * Deprecated, use `http.response.header.<key>` instead.
6607
- *
6608
- * @example 3495
6609
- *
6610
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
6611
- *
6612
- * @deprecated Replaced by `http.response.header.<key>`.
6613
- */
6614
- const ATTR_HTTP_RESPONSE_CONTENT_LENGTH = 'http.response_content_length';
6615
- /**
6616
- * Deprecated, use `http.response.body.size` instead.
6617
- *
6618
- * @example 5493
6619
- *
6620
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
6621
- *
6622
- * @deprecated Replace by `http.response.body.size`.
6623
- */
6624
- const ATTR_HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED = 'http.response_content_length_uncompressed';
6625
-
6626
- /*
6627
- * Copyright The OpenTelemetry Authors
6628
- *
6629
- * Licensed under the Apache License, Version 2.0 (the "License");
6630
- * you may not use this file except in compliance with the License.
6631
- * You may obtain a copy of the License at
6632
- *
6633
- * https://www.apache.org/licenses/LICENSE-2.0
6634
- *
6635
- * Unless required by applicable law or agreed to in writing, software
6636
- * distributed under the License is distributed on an "AS IS" BASIS,
6637
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6638
- * See the License for the specific language governing permissions and
6639
- * limitations under the License.
6640
- */
6641
- // Used to normalize relative URLs
6642
- let urlNormalizingAnchor;
6643
- function getUrlNormalizingAnchor() {
6644
- if (!urlNormalizingAnchor) {
6645
- urlNormalizingAnchor = document.createElement('a');
6646
- }
6647
- return urlNormalizingAnchor;
6648
- }
6649
- /**
6650
- * Helper function to be able to use enum as typed key in type and in interface when using forEach
6651
- * @param obj
6652
- * @param key
6653
- */
6654
- function hasKey(obj, key) {
6655
- return key in obj;
6656
- }
6657
- /**
6658
- * Helper function for starting an event on span based on {@link PerformanceEntries}
6659
- * @param span
6660
- * @param performanceName name of performance entry for time start
6661
- * @param entries
6662
- * @param ignoreZeros
6663
- */
6664
- function addSpanNetworkEvent(span, performanceName, entries, ignoreZeros = true) {
6665
- if (hasKey(entries, performanceName) &&
6666
- typeof entries[performanceName] === 'number' &&
6667
- !(ignoreZeros && entries[performanceName] === 0)) {
6668
- return span.addEvent(performanceName, entries[performanceName]);
6669
- }
6670
- return undefined;
6671
- }
6672
- /**
6673
- * Helper function for adding network events and content length attributes.
6674
- */
6675
- function addSpanNetworkEvents(span, resource, ignoreNetworkEvents = false, ignoreZeros, skipOldSemconvContentLengthAttrs) {
6676
- if (ignoreZeros === undefined) {
6677
- ignoreZeros = resource[PerformanceTimingNames.START_TIME] !== 0;
6678
- }
6679
- if (!ignoreNetworkEvents) {
6680
- addSpanNetworkEvent(span, PerformanceTimingNames.FETCH_START, resource, ignoreZeros);
6681
- addSpanNetworkEvent(span, PerformanceTimingNames.DOMAIN_LOOKUP_START, resource, ignoreZeros);
6682
- addSpanNetworkEvent(span, PerformanceTimingNames.DOMAIN_LOOKUP_END, resource, ignoreZeros);
6683
- addSpanNetworkEvent(span, PerformanceTimingNames.CONNECT_START, resource, ignoreZeros);
6684
- addSpanNetworkEvent(span, PerformanceTimingNames.SECURE_CONNECTION_START, resource, ignoreZeros);
6685
- addSpanNetworkEvent(span, PerformanceTimingNames.CONNECT_END, resource, ignoreZeros);
6686
- addSpanNetworkEvent(span, PerformanceTimingNames.REQUEST_START, resource, ignoreZeros);
6687
- addSpanNetworkEvent(span, PerformanceTimingNames.RESPONSE_START, resource, ignoreZeros);
6688
- addSpanNetworkEvent(span, PerformanceTimingNames.RESPONSE_END, resource, ignoreZeros);
6689
- }
6690
- if (!skipOldSemconvContentLengthAttrs) {
6691
- // This block adds content-length-related span attributes using the
6692
- // *old* HTTP semconv (v1.7.0).
6693
- const encodedLength = resource[PerformanceTimingNames.ENCODED_BODY_SIZE];
6694
- if (encodedLength !== undefined) {
6695
- span.setAttribute(ATTR_HTTP_RESPONSE_CONTENT_LENGTH, encodedLength);
6696
- }
6697
- const decodedLength = resource[PerformanceTimingNames.DECODED_BODY_SIZE];
6698
- // Spec: Not set if transport encoding not used (in which case encoded and decoded sizes match)
6699
- if (decodedLength !== undefined && encodedLength !== decodedLength) {
6700
- span.setAttribute(ATTR_HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED, decodedLength);
6701
- }
6702
- }
6703
- }
6704
- /**
6705
- * sort resources by startTime
6706
- * @param filteredResources
6707
- */
6708
- function sortResources(filteredResources) {
6709
- return filteredResources.slice().sort((a, b) => {
6710
- const valueA = a[PerformanceTimingNames.FETCH_START];
6711
- const valueB = b[PerformanceTimingNames.FETCH_START];
6712
- if (valueA > valueB) {
6713
- return 1;
6714
- }
6715
- else if (valueA < valueB) {
6716
- return -1;
6717
- }
6718
- return 0;
6719
- });
6720
- }
6721
- /** Returns the origin if present (if in browser context). */
6722
- function getOrigin() {
6723
- return typeof location !== 'undefined' ? location.origin : undefined;
6724
- }
6725
- /**
6726
- * Get closest performance resource ignoring the resources that have been
6727
- * already used.
6728
- * @param spanUrl
6729
- * @param startTimeHR
6730
- * @param endTimeHR
6731
- * @param resources
6732
- * @param ignoredResources
6733
- * @param initiatorType
6734
- */
6735
- function getResource(spanUrl, startTimeHR, endTimeHR, resources, ignoredResources = new WeakSet(), initiatorType) {
6736
- // de-relativize the URL before usage (does no harm to absolute URLs)
6737
- const parsedSpanUrl = parseUrl(spanUrl);
6738
- spanUrl = parsedSpanUrl.toString();
6739
- const filteredResources = filterResourcesForSpan(spanUrl, startTimeHR, endTimeHR, resources, ignoredResources, initiatorType);
6740
- if (filteredResources.length === 0) {
6741
- return {
6742
- mainRequest: undefined,
6743
- };
6744
- }
6745
- if (filteredResources.length === 1) {
6746
- return {
6747
- mainRequest: filteredResources[0],
6748
- };
6749
- }
6750
- const sorted = sortResources(filteredResources);
6751
- if (parsedSpanUrl.origin !== getOrigin() && sorted.length > 1) {
6752
- let corsPreFlightRequest = sorted[0];
6753
- let mainRequest = findMainRequest(sorted, corsPreFlightRequest[PerformanceTimingNames.RESPONSE_END], endTimeHR);
6754
- const responseEnd = corsPreFlightRequest[PerformanceTimingNames.RESPONSE_END];
6755
- const fetchStart = mainRequest[PerformanceTimingNames.FETCH_START];
6756
- // no corsPreFlightRequest
6757
- if (fetchStart < responseEnd) {
6758
- mainRequest = corsPreFlightRequest;
6759
- corsPreFlightRequest = undefined;
6760
- }
6761
- return {
6762
- corsPreFlightRequest,
6763
- mainRequest,
6764
- };
6765
- }
6766
- else {
6767
- return {
6768
- mainRequest: filteredResources[0],
6769
- };
6770
- }
6771
- }
6772
- /**
6773
- * Will find the main request skipping the cors pre flight requests
6774
- * @param resources
6775
- * @param corsPreFlightRequestEndTime
6776
- * @param spanEndTimeHR
6777
- */
6778
- function findMainRequest(resources, corsPreFlightRequestEndTime, spanEndTimeHR) {
6779
- const spanEndTime = hrTimeToNanoseconds(spanEndTimeHR);
6780
- const minTime = hrTimeToNanoseconds(timeInputToHrTime(corsPreFlightRequestEndTime));
6781
- let mainRequest = resources[1];
6782
- let bestGap;
6783
- const length = resources.length;
6784
- for (let i = 1; i < length; i++) {
6785
- const resource = resources[i];
6786
- const resourceStartTime = hrTimeToNanoseconds(timeInputToHrTime(resource[PerformanceTimingNames.FETCH_START]));
6787
- const resourceEndTime = hrTimeToNanoseconds(timeInputToHrTime(resource[PerformanceTimingNames.RESPONSE_END]));
6788
- const currentGap = spanEndTime - resourceEndTime;
6789
- if (resourceStartTime >= minTime && (!bestGap || currentGap < bestGap)) {
6790
- bestGap = currentGap;
6791
- mainRequest = resource;
6792
- }
6793
- }
6794
- return mainRequest;
6795
- }
6796
- /**
6797
- * Filter all resources that has started and finished according to span start time and end time.
6798
- * It will return the closest resource to a start time
6799
- * @param spanUrl
6800
- * @param startTimeHR
6801
- * @param endTimeHR
6802
- * @param resources
6803
- * @param ignoredResources
6804
- */
6805
- function filterResourcesForSpan(spanUrl, startTimeHR, endTimeHR, resources, ignoredResources, initiatorType) {
6806
- const startTime = hrTimeToNanoseconds(startTimeHR);
6807
- const endTime = hrTimeToNanoseconds(endTimeHR);
6808
- let filteredResources = resources.filter(resource => {
6809
- const resourceStartTime = hrTimeToNanoseconds(timeInputToHrTime(resource[PerformanceTimingNames.FETCH_START]));
6810
- const resourceEndTime = hrTimeToNanoseconds(timeInputToHrTime(resource[PerformanceTimingNames.RESPONSE_END]));
6811
- return (resource.initiatorType.toLowerCase() ===
6812
- (initiatorType || 'xmlhttprequest') &&
6813
- resource.name === spanUrl &&
6814
- resourceStartTime >= startTime &&
6815
- resourceEndTime <= endTime);
6816
- });
6817
- if (filteredResources.length > 0) {
6818
- filteredResources = filteredResources.filter(resource => {
6819
- return !ignoredResources.has(resource);
6820
- });
6821
- }
6822
- return filteredResources;
6823
- }
6824
- /**
6825
- * Parses url using URL constructor or fallback to anchor element.
6826
- * @param url
6827
- */
6828
- function parseUrl(url) {
6829
- if (typeof URL === 'function') {
6830
- return new URL(url, typeof document !== 'undefined'
6831
- ? document.baseURI
6832
- : typeof location !== 'undefined' // Some JS runtimes (e.g. Deno) don't define this
6833
- ? location.href
6834
- : undefined);
6835
- }
6836
- const element = getUrlNormalizingAnchor();
6837
- element.href = url;
6838
- return element;
6839
- }
6840
6362
  /**
6841
6363
  * Get element XPath
6842
6364
  * @param target - target element
@@ -6915,25 +6437,6 @@ function getNodeValue(target, optimised) {
6915
6437
  }
6916
6438
  return `/${nodeValue}`;
6917
6439
  }
6918
- /**
6919
- * Checks if trace headers should be propagated
6920
- * @param spanUrl
6921
- * @private
6922
- */
6923
- function shouldPropagateTraceHeaders(spanUrl, propagateTraceHeaderCorsUrls) {
6924
- let propagateTraceHeaderUrls = propagateTraceHeaderCorsUrls || [];
6925
- if (typeof propagateTraceHeaderUrls === 'string' ||
6926
- propagateTraceHeaderUrls instanceof RegExp) {
6927
- propagateTraceHeaderUrls = [propagateTraceHeaderUrls];
6928
- }
6929
- const parsedSpanUrl = parseUrl(spanUrl);
6930
- if (parsedSpanUrl.origin === getOrigin()) {
6931
- return true;
6932
- }
6933
- else {
6934
- return propagateTraceHeaderUrls.some(propagateTraceHeaderUrl => urlMatches(spanUrl, propagateTraceHeaderUrl));
6935
- }
6936
- }
6937
6440
 
6938
6441
  /*
6939
6442
  * Copyright The OpenTelemetry Authors
@@ -16263,21 +15766,6 @@ class InstrumentationBase extends InstrumentationAbstract {
16263
15766
  * @param execute - function to be executed
16264
15767
  * @param onFinish - callback to run when execute finishes
16265
15768
  */
16266
- function safeExecuteInTheMiddle(execute, onFinish, preventThrowingError) {
16267
- let error;
16268
- let result;
16269
- try {
16270
- result = execute();
16271
- }
16272
- catch (e) {
16273
- error = e;
16274
- }
16275
- finally {
16276
- onFinish(error, result);
16277
- // eslint-disable-next-line no-unsafe-finally
16278
- return result;
16279
- }
16280
- }
16281
15769
  /**
16282
15770
  * Checks if certain function has been already wrapped
16283
15771
  * @param func
@@ -16304,104 +15792,13 @@ function isWrapped(func) {
16304
15792
  * See the License for the specific language governing permissions and
16305
15793
  * limitations under the License.
16306
15794
  */
16307
- var SemconvStability;
16308
- (function (SemconvStability) {
16309
- /** Emit only stable semantic conventions. */
16310
- SemconvStability[SemconvStability["STABLE"] = 1] = "STABLE";
16311
- /** Emit only old semantic conventions. */
16312
- SemconvStability[SemconvStability["OLD"] = 2] = "OLD";
16313
- /** Emit both stable and old semantic conventions. */
16314
- SemconvStability[SemconvStability["DUPLICATE"] = 3] = "DUPLICATE";
16315
- })(SemconvStability || (SemconvStability = {}));
16316
- /**
16317
- * Determine the appropriate semconv stability for the given namespace.
16318
- *
16319
- * This will parse the given string of comma-separated values (often
16320
- * `process.env.OTEL_SEMCONV_STABILITY_OPT_IN`) looking for the `${namespace}`
16321
- * or `${namespace}/dup` tokens. This is a pattern defined by a number of
16322
- * non-normative semconv documents.
16323
- *
16324
- * For example:
16325
- * - namespace 'http': https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/
16326
- * - namespace 'database': https://opentelemetry.io/docs/specs/semconv/non-normative/database-migration/
16327
- * - namespace 'k8s': https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-migration/
16328
- *
16329
- * Usage:
16330
- *
16331
- * import {SemconvStability, semconvStabilityFromStr} from '@opentelemetry/instrumentation';
16332
- *
16333
- * export class FooInstrumentation extends InstrumentationBase<FooInstrumentationConfig> {
16334
- * private _semconvStability: SemconvStability;
16335
- * constructor(config: FooInstrumentationConfig = {}) {
16336
- * super('@opentelemetry/instrumentation-foo', VERSION, config);
16337
- *
16338
- * // When supporting the OTEL_SEMCONV_STABILITY_OPT_IN envvar
16339
- * this._semconvStability = semconvStabilityFromStr(
16340
- * 'http',
16341
- * process.env.OTEL_SEMCONV_STABILITY_OPT_IN
16342
- * );
16343
- *
16344
- * // or when supporting a `semconvStabilityOptIn` config option (e.g. for
16345
- * // the web where there are no envvars).
16346
- * this._semconvStability = semconvStabilityFromStr(
16347
- * 'http',
16348
- * config?.semconvStabilityOptIn
16349
- * );
16350
- * }
16351
- * }
16352
- *
16353
- * // Then, to apply semconv, use the following or similar:
16354
- * if (this._semconvStability & SemconvStability.OLD) {
16355
- * // ...
16356
- * }
16357
- * if (this._semconvStability & SemconvStability.STABLE) {
16358
- * // ...
16359
- * }
16360
- *
16361
- */
16362
- function semconvStabilityFromStr(namespace, str) {
16363
- let semconvStability = SemconvStability.OLD;
16364
- // The same parsing of `str` as `getStringListFromEnv` from the core pkg.
16365
- const entries = str
16366
- ?.split(',')
16367
- .map(v => v.trim())
16368
- .filter(s => s !== '');
16369
- for (const entry of entries ?? []) {
16370
- if (entry.toLowerCase() === namespace + '/dup') {
16371
- // DUPLICATE takes highest precedence.
16372
- semconvStability = SemconvStability.DUPLICATE;
16373
- break;
16374
- }
16375
- else if (entry.toLowerCase() === namespace) {
16376
- semconvStability = SemconvStability.STABLE;
16377
- }
16378
- }
16379
- return semconvStability;
16380
- }
16381
-
16382
- /*
16383
- * Copyright The OpenTelemetry Authors
16384
- *
16385
- * Licensed under the Apache License, Version 2.0 (the "License");
16386
- * you may not use this file except in compliance with the License.
16387
- * You may obtain a copy of the License at
16388
- *
16389
- * https://www.apache.org/licenses/LICENSE-2.0
16390
- *
16391
- * Unless required by applicable law or agreed to in writing, software
16392
- * distributed under the License is distributed on an "AS IS" BASIS,
16393
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16394
- * See the License for the specific language governing permissions and
16395
- * limitations under the License.
16396
- */
16397
- /**
16398
- * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md
16399
- */
16400
- var AttributeNames$3;
15795
+ var AttributeNames;
16401
15796
  (function (AttributeNames) {
16402
- AttributeNames["COMPONENT"] = "component";
16403
- AttributeNames["HTTP_STATUS_TEXT"] = "http.status_text";
16404
- })(AttributeNames$3 || (AttributeNames$3 = {}));
15797
+ AttributeNames["EVENT_TYPE"] = "event_type";
15798
+ AttributeNames["TARGET_ELEMENT"] = "target_element";
15799
+ AttributeNames["TARGET_XPATH"] = "target_xpath";
15800
+ AttributeNames["HTTP_URL"] = "http.url";
15801
+ })(AttributeNames || (AttributeNames = {}));
16405
15802
 
16406
15803
  /*
16407
15804
  * Copyright The OpenTelemetry Authors
@@ -16418,93 +15815,9 @@ var AttributeNames$3;
16418
15815
  * See the License for the specific language governing permissions and
16419
15816
  * limitations under the License.
16420
15817
  */
16421
- /*
16422
- * This file contains a copy of unstable semantic convention definitions
16423
- * used by this package.
16424
- * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv
16425
- */
16426
- /**
16427
- * Deprecated, use one of `server.address`, `client.address` or `http.request.header.host` instead, depending on the usage.
16428
- *
16429
- * @example www.example.org
16430
- *
16431
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16432
- *
16433
- * @deprecated Replaced by one of `server.address`, `client.address` or `http.request.header.host`, depending on the usage.
16434
- */
16435
- const ATTR_HTTP_HOST$1 = 'http.host';
16436
- /**
16437
- * Deprecated, use `http.request.method` instead.
16438
- *
16439
- * @example GET
16440
- * @example POST
16441
- * @example HEAD
16442
- *
16443
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16444
- *
16445
- * @deprecated Replaced by `http.request.method`.
16446
- */
16447
- const ATTR_HTTP_METHOD$1 = 'http.method';
16448
- /**
16449
- * The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.
16450
- *
16451
- * @example 3495
16452
- *
16453
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16454
- */
16455
- const ATTR_HTTP_REQUEST_BODY_SIZE$1 = 'http.request.body.size';
16456
- /**
16457
- * Deprecated, use `http.request.body.size` instead.
16458
- *
16459
- * @example 5493
16460
- *
16461
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16462
- *
16463
- * @deprecated Replaced by `http.request.body.size`.
16464
- */
16465
- const ATTR_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED$1 = 'http.request_content_length_uncompressed';
16466
- /**
16467
- * Deprecated, use `url.scheme` instead.
16468
- *
16469
- * @example http
16470
- * @example https
16471
- *
16472
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16473
- *
16474
- * @deprecated Replaced by `url.scheme` instead.
16475
- */
16476
- const ATTR_HTTP_SCHEME$1 = 'http.scheme';
16477
- /**
16478
- * Deprecated, use `http.response.status_code` instead.
16479
- *
16480
- * @example 200
16481
- *
16482
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16483
- *
16484
- * @deprecated Replaced by `http.response.status_code`.
16485
- */
16486
- const ATTR_HTTP_STATUS_CODE$1 = 'http.status_code';
16487
- /**
16488
- * Deprecated, use `url.full` instead.
16489
- *
16490
- * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv
16491
- *
16492
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16493
- *
16494
- * @deprecated Replaced by `url.full`.
16495
- */
16496
- const ATTR_HTTP_URL$2 = 'http.url';
16497
- /**
16498
- * Deprecated, use `user_agent.original` instead.
16499
- *
16500
- * @example CERN-LineMode/2.15 libwww/2.17b3
16501
- * @example Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1
16502
- *
16503
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
16504
- *
16505
- * @deprecated Replaced by `user_agent.original`.
16506
- */
16507
- const ATTR_HTTP_USER_AGENT$2 = 'http.user_agent';
15818
+ // this is autogenerated file, see scripts/version-update.js
15819
+ const PACKAGE_VERSION = '0.53.0';
15820
+ const PACKAGE_NAME = '@opentelemetry/instrumentation-user-interaction';
16508
15821
 
16509
15822
  /*
16510
15823
  * Copyright The OpenTelemetry Authors
@@ -16521,2375 +15834,532 @@ const ATTR_HTTP_USER_AGENT$2 = 'http.user_agent';
16521
15834
  * See the License for the specific language governing permissions and
16522
15835
  * limitations under the License.
16523
15836
  */
16524
- // Much of the logic here overlaps with the same utils file in opentelemetry-instrumentation-xml-http-request
16525
- // These may be unified in the future.
16526
- const DIAG_LOGGER$1 = diag.createComponentLogger({
16527
- namespace: '@opentelemetry/opentelemetry-instrumentation-fetch/utils',
16528
- });
16529
- /**
16530
- * Helper function to determine payload content length for fetch requests
16531
- *
16532
- * The fetch API is kinda messy: there are a couple of ways the body can be passed in.
16533
- *
16534
- * In all cases, the body param can be some variation of ReadableStream,
16535
- * and ReadableStreams can only be read once! We want to avoid consuming the body here,
16536
- * because that would mean that the body never gets sent with the actual fetch request.
16537
- *
16538
- * Either the first arg is a Request object, which can be cloned
16539
- * so we can clone that object and read the body of the clone
16540
- * without disturbing the original argument
16541
- * However, reading the body here can only be done async; the body() method returns a promise
16542
- * this means this entire function has to return a promise
16543
- *
16544
- * OR the first arg is a url/string
16545
- * in which case the second arg has type RequestInit
16546
- * RequestInit is NOT cloneable, but RequestInit.body is writable
16547
- * so we can chain it into ReadableStream.pipeThrough()
16548
- *
16549
- * ReadableStream.pipeThrough() lets us process a stream and returns a new stream
16550
- * So we can measure the body length as it passes through the pie, but need to attach
16551
- * the new stream to the original request
16552
- * so that the browser still has access to the body.
16553
- *
16554
- * @param body
16555
- * @returns promise that resolves to the content length of the body
16556
- */
16557
- function getFetchBodyLength(...args) {
16558
- if (args[0] instanceof URL || typeof args[0] === 'string') {
16559
- const requestInit = args[1];
16560
- if (!requestInit?.body) {
16561
- return Promise.resolve();
16562
- }
16563
- if (requestInit.body instanceof ReadableStream) {
16564
- const { body, length } = _getBodyNonDestructively(requestInit.body);
16565
- requestInit.body = body;
16566
- return length;
16567
- }
16568
- else {
16569
- return Promise.resolve(getXHRBodyLength$1(requestInit.body));
16570
- }
16571
- }
16572
- else {
16573
- const info = args[0];
16574
- if (!info?.body) {
16575
- return Promise.resolve();
16576
- }
16577
- return info
16578
- .clone()
16579
- .text()
16580
- .then(t => getByteLength$1(t));
16581
- }
16582
- }
16583
- function _getBodyNonDestructively(body) {
16584
- // can't read a ReadableStream without destroying it
16585
- // but we CAN pipe it through and return a new ReadableStream
16586
- // some (older) platforms don't expose the pipeThrough method and in that scenario, we're out of luck;
16587
- // there's no way to read the stream without consuming it.
16588
- if (!body.pipeThrough) {
16589
- DIAG_LOGGER$1.warn('Platform has ReadableStream but not pipeThrough!');
16590
- return {
16591
- body,
16592
- length: Promise.resolve(undefined),
16593
- };
16594
- }
16595
- let length = 0;
16596
- let resolveLength;
16597
- const lengthPromise = new Promise(resolve => {
16598
- resolveLength = resolve;
16599
- });
16600
- const transform = new TransformStream({
16601
- start() { },
16602
- async transform(chunk, controller) {
16603
- const bytearray = (await chunk);
16604
- length += bytearray.byteLength;
16605
- controller.enqueue(chunk);
16606
- },
16607
- flush() {
16608
- resolveLength(length);
16609
- },
16610
- });
16611
- return {
16612
- body: body.pipeThrough(transform),
16613
- length: lengthPromise,
16614
- };
16615
- }
16616
- function isDocument$1(value) {
16617
- return typeof Document !== 'undefined' && value instanceof Document;
16618
- }
16619
- /**
16620
- * Helper function to determine payload content length for XHR requests
16621
- * @param body
16622
- * @returns content length
16623
- */
16624
- function getXHRBodyLength$1(body) {
16625
- if (isDocument$1(body)) {
16626
- return new XMLSerializer().serializeToString(document).length;
16627
- }
16628
- // XMLHttpRequestBodyInit expands to the following:
16629
- if (typeof body === 'string') {
16630
- return getByteLength$1(body);
16631
- }
16632
- if (body instanceof Blob) {
16633
- return body.size;
16634
- }
16635
- if (body instanceof FormData) {
16636
- return getFormDataSize$1(body);
16637
- }
16638
- if (body instanceof URLSearchParams) {
16639
- return getByteLength$1(body.toString());
16640
- }
16641
- // ArrayBuffer | ArrayBufferView
16642
- if (body.byteLength !== undefined) {
16643
- return body.byteLength;
16644
- }
16645
- DIAG_LOGGER$1.warn('unknown body type');
16646
- return undefined;
16647
- }
16648
- const TEXT_ENCODER$1 = new TextEncoder();
16649
- function getByteLength$1(s) {
16650
- return TEXT_ENCODER$1.encode(s).byteLength;
16651
- }
16652
- function getFormDataSize$1(formData) {
16653
- let size = 0;
16654
- for (const [key, value] of formData.entries()) {
16655
- size += key.length;
16656
- if (value instanceof Blob) {
16657
- size += value.size;
16658
- }
16659
- else {
16660
- size += value.length;
16661
- }
16662
- }
16663
- return size;
15837
+ /// <reference types="zone.js" />
15838
+ const ZONE_CONTEXT_KEY = 'OT_ZONE_CONTEXT';
15839
+ const EVENT_NAVIGATION_NAME = 'Navigation:';
15840
+ const DEFAULT_EVENT_NAMES = ['click'];
15841
+ function defaultShouldPreventSpanCreation() {
15842
+ return false;
16664
15843
  }
16665
15844
  /**
16666
- * Normalize an HTTP request method string per `http.request.method` spec
16667
- * https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#http-client-span
16668
- */
16669
- function normalizeHttpRequestMethod$1(method) {
16670
- const knownMethods = getKnownMethods$1();
16671
- const methUpper = method.toUpperCase();
16672
- if (methUpper in knownMethods) {
16673
- return methUpper;
16674
- }
16675
- else {
16676
- return '_OTHER';
16677
- }
16678
- }
16679
- const DEFAULT_KNOWN_METHODS$1 = {
16680
- CONNECT: true,
16681
- DELETE: true,
16682
- GET: true,
16683
- HEAD: true,
16684
- OPTIONS: true,
16685
- PATCH: true,
16686
- POST: true,
16687
- PUT: true,
16688
- TRACE: true,
16689
- };
16690
- let knownMethods$1;
16691
- function getKnownMethods$1() {
16692
- if (knownMethods$1 === undefined) {
16693
- {
16694
- knownMethods$1 = DEFAULT_KNOWN_METHODS$1;
16695
- }
16696
- }
16697
- return knownMethods$1;
16698
- }
16699
- const HTTP_PORT_FROM_PROTOCOL$1 = {
16700
- 'https:': '443',
16701
- 'http:': '80',
16702
- };
16703
- function serverPortFromUrl$1(url) {
16704
- const serverPort = Number(url.port || HTTP_PORT_FROM_PROTOCOL$1[url.protocol]);
16705
- // Guard with `if (serverPort)` because `Number('') === 0`.
16706
- if (serverPort && !isNaN(serverPort)) {
16707
- return serverPort;
16708
- }
16709
- else {
16710
- return undefined;
16711
- }
16712
- }
16713
-
16714
- /*
16715
- * Copyright The OpenTelemetry Authors
16716
- *
16717
- * Licensed under the Apache License, Version 2.0 (the "License");
16718
- * you may not use this file except in compliance with the License.
16719
- * You may obtain a copy of the License at
16720
- *
16721
- * https://www.apache.org/licenses/LICENSE-2.0
16722
- *
16723
- * Unless required by applicable law or agreed to in writing, software
16724
- * distributed under the License is distributed on an "AS IS" BASIS,
16725
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16726
- * See the License for the specific language governing permissions and
16727
- * limitations under the License.
16728
- */
16729
- // this is autogenerated file, see scripts/version-update.js
16730
- const VERSION$1 = '0.208.0';
16731
-
16732
- /*
16733
- * Copyright The OpenTelemetry Authors
16734
- *
16735
- * Licensed under the Apache License, Version 2.0 (the "License");
16736
- * you may not use this file except in compliance with the License.
16737
- * You may obtain a copy of the License at
16738
- *
16739
- * https://www.apache.org/licenses/LICENSE-2.0
16740
- *
16741
- * Unless required by applicable law or agreed to in writing, software
16742
- * distributed under the License is distributed on an "AS IS" BASIS,
16743
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16744
- * See the License for the specific language governing permissions and
16745
- * limitations under the License.
15845
+ * This class represents a UserInteraction plugin for auto instrumentation.
15846
+ * If zone.js is available then it patches the zone otherwise it patches
15847
+ * addEventListener of HTMLElement
16746
15848
  */
16747
- // how long to wait for observer to collect information about resources
16748
- // this is needed as event "load" is called before observer
16749
- // hard to say how long it should really wait, seems like 300ms is
16750
- // safe enough
16751
- const OBSERVER_WAIT_TIME_MS$1 = 300;
16752
- const isNode = typeof process === 'object' && process.release?.name === 'node';
16753
- /**
16754
- * This class represents a fetch plugin for auto instrumentation
16755
- */
16756
- class FetchInstrumentation extends InstrumentationBase {
16757
- component = 'fetch';
16758
- version = VERSION$1;
16759
- moduleName = this.component;
16760
- _usedResources = new WeakSet();
16761
- _tasksCount = 0;
16762
- _semconvStability;
15849
+ class UserInteractionInstrumentation extends InstrumentationBase {
15850
+ version = PACKAGE_VERSION;
15851
+ moduleName = 'user-interaction';
15852
+ _spansData = new WeakMap();
15853
+ // for addEventListener/removeEventListener state
15854
+ _wrappedListeners = new WeakMap();
15855
+ // for event bubbling
15856
+ _eventsSpanMap = new WeakMap();
15857
+ _eventNames;
15858
+ _shouldPreventSpanCreation;
16763
15859
  constructor(config = {}) {
16764
- super('@opentelemetry/instrumentation-fetch', VERSION$1, config);
16765
- this._semconvStability = semconvStabilityFromStr('http', config?.semconvStabilityOptIn);
15860
+ super(PACKAGE_NAME, PACKAGE_VERSION, config);
15861
+ this._eventNames = new Set(config?.eventNames ?? DEFAULT_EVENT_NAMES);
15862
+ this._shouldPreventSpanCreation =
15863
+ typeof config?.shouldPreventSpanCreation === 'function'
15864
+ ? config.shouldPreventSpanCreation
15865
+ : defaultShouldPreventSpanCreation;
16766
15866
  }
16767
15867
  init() { }
16768
15868
  /**
16769
- * Add cors pre flight child span
16770
- * @param span
16771
- * @param corsPreFlightRequest
16772
- */
16773
- _addChildSpan(span, corsPreFlightRequest) {
16774
- const childSpan = this.tracer.startSpan('CORS Preflight', {
16775
- startTime: corsPreFlightRequest[PerformanceTimingNames.FETCH_START],
16776
- }, trace.setSpan(context.active(), span));
16777
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
16778
- addSpanNetworkEvents(childSpan, corsPreFlightRequest, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
16779
- childSpan.end(corsPreFlightRequest[PerformanceTimingNames.RESPONSE_END]);
16780
- }
16781
- /**
16782
- * Adds more attributes to span just before ending it
15869
+ * This will check if last task was timeout and will save the time to
15870
+ * fix the user interaction when nothing happens
15871
+ * This timeout comes from xhr plugin which is needed to collect information
15872
+ * about last xhr main request from observer
15873
+ * @param task
16783
15874
  * @param span
16784
- * @param response
16785
15875
  */
16786
- _addFinalSpanAttributes(span, response) {
16787
- const parsedUrl = parseUrl(response.url);
16788
- if (this._semconvStability & SemconvStability.OLD) {
16789
- span.setAttribute(ATTR_HTTP_STATUS_CODE$1, response.status);
16790
- if (response.statusText != null) {
16791
- span.setAttribute(AttributeNames$3.HTTP_STATUS_TEXT, response.statusText);
16792
- }
16793
- span.setAttribute(ATTR_HTTP_HOST$1, parsedUrl.host);
16794
- span.setAttribute(ATTR_HTTP_SCHEME$1, parsedUrl.protocol.replace(':', ''));
16795
- if (typeof navigator !== 'undefined') {
16796
- span.setAttribute(ATTR_HTTP_USER_AGENT$2, navigator.userAgent);
15876
+ _checkForTimeout(task, span) {
15877
+ const spanData = this._spansData.get(span);
15878
+ if (spanData) {
15879
+ if (task.source === 'setTimeout') {
15880
+ spanData.hrTimeLastTimeout = hrTime();
16797
15881
  }
16798
- }
16799
- if (this._semconvStability & SemconvStability.STABLE) {
16800
- span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, response.status);
16801
- // TODO: Set server.{address,port} at span creation for sampling decisions
16802
- // (a "SHOULD" requirement in semconv).
16803
- span.setAttribute(ATTR_SERVER_ADDRESS, parsedUrl.hostname);
16804
- const serverPort = serverPortFromUrl$1(parsedUrl);
16805
- if (serverPort) {
16806
- span.setAttribute(ATTR_SERVER_PORT, serverPort);
15882
+ else if (task.source !== 'Promise.then' &&
15883
+ task.source !== 'setTimeout') {
15884
+ spanData.hrTimeLastTimeout = undefined;
16807
15885
  }
16808
15886
  }
16809
15887
  }
16810
15888
  /**
16811
- * Add headers
16812
- * @param options
16813
- * @param spanUrl
15889
+ * Controls whether or not to create a span, based on the event type.
15890
+ */
15891
+ _allowEventName(eventName) {
15892
+ return this._eventNames.has(eventName);
15893
+ }
15894
+ /**
15895
+ * Creates a new span
15896
+ * @param element
15897
+ * @param eventName
15898
+ * @param parentSpan
16814
15899
  */
16815
- _addHeaders(options, spanUrl) {
16816
- if (!shouldPropagateTraceHeaders(spanUrl, this.getConfig().propagateTraceHeaderCorsUrls)) {
16817
- const headers = {};
16818
- propagation.inject(context.active(), headers);
16819
- if (Object.keys(headers).length > 0) {
16820
- this._diag.debug('headers inject skipped due to CORS policy');
16821
- }
16822
- return;
15900
+ _createSpan(element, eventName, parentSpan) {
15901
+ if (!(element instanceof HTMLElement)) {
15902
+ return undefined;
16823
15903
  }
16824
- if (options instanceof Request) {
16825
- propagation.inject(context.active(), options.headers, {
16826
- set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)),
16827
- });
15904
+ if (!element.getAttribute) {
15905
+ return undefined;
16828
15906
  }
16829
- else if (options.headers instanceof Headers) {
16830
- propagation.inject(context.active(), options.headers, {
16831
- set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)),
16832
- });
15907
+ if (element.hasAttribute('disabled')) {
15908
+ return undefined;
16833
15909
  }
16834
- else if (options.headers instanceof Map) {
16835
- propagation.inject(context.active(), options.headers, {
16836
- set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)),
15910
+ if (!this._allowEventName(eventName)) {
15911
+ return undefined;
15912
+ }
15913
+ const xpath = getElementXPath(element, true);
15914
+ try {
15915
+ const span = this.tracer.startSpan(eventName, {
15916
+ attributes: {
15917
+ [AttributeNames.EVENT_TYPE]: eventName,
15918
+ [AttributeNames.TARGET_ELEMENT]: element.tagName,
15919
+ [AttributeNames.TARGET_XPATH]: xpath,
15920
+ [AttributeNames.HTTP_URL]: window.location.href,
15921
+ },
15922
+ }, parentSpan
15923
+ ? trace.setSpan(context.active(), parentSpan)
15924
+ : undefined);
15925
+ if (this._shouldPreventSpanCreation(eventName, element, span) === true) {
15926
+ return undefined;
15927
+ }
15928
+ this._spansData.set(span, {
15929
+ taskCount: 0,
16837
15930
  });
15931
+ return span;
16838
15932
  }
16839
- else {
16840
- const headers = {};
16841
- propagation.inject(context.active(), headers);
16842
- options.headers = Object.assign({}, headers, options.headers || {});
15933
+ catch (e) {
15934
+ this._diag.error('failed to start create new user interaction span', e);
16843
15935
  }
15936
+ return undefined;
16844
15937
  }
16845
15938
  /**
16846
- * Clears the resource timings and all resources assigned with spans
16847
- * when {@link FetchPluginConfig.clearTimingResources} is
16848
- * set to true (default false)
16849
- * @private
15939
+ * Decrement number of tasks that left in zone,
15940
+ * This is needed to be able to end span when no more tasks left
15941
+ * @param span
16850
15942
  */
16851
- _clearResources() {
16852
- if (this._tasksCount === 0 && this.getConfig().clearTimingResources) {
16853
- performance.clearResourceTimings();
16854
- this._usedResources = new WeakSet();
16855
- }
16856
- }
16857
- /**
16858
- * Creates a new span
16859
- * @param url
16860
- * @param options
15943
+ _decrementTask(span) {
15944
+ const spanData = this._spansData.get(span);
15945
+ if (spanData) {
15946
+ spanData.taskCount--;
15947
+ if (spanData.taskCount === 0) {
15948
+ this._tryToEndSpan(span, spanData.hrTimeLastTimeout);
15949
+ }
15950
+ }
15951
+ }
15952
+ /**
15953
+ * Return the current span
15954
+ * @param zone
15955
+ * @private
16861
15956
  */
16862
- _createSpan(url, options = {}) {
16863
- if (isUrlIgnored(url, this.getConfig().ignoreUrls)) {
16864
- this._diag.debug('ignoring span as url matches ignored url');
16865
- return;
15957
+ _getCurrentSpan(zone) {
15958
+ const context = zone.get(ZONE_CONTEXT_KEY);
15959
+ if (context) {
15960
+ return trace.getSpan(context);
16866
15961
  }
16867
- let name = '';
16868
- const attributes = {};
16869
- if (this._semconvStability & SemconvStability.OLD) {
16870
- const method = (options.method || 'GET').toUpperCase();
16871
- name = `HTTP ${method}`;
16872
- attributes[AttributeNames$3.COMPONENT] = this.moduleName;
16873
- attributes[ATTR_HTTP_METHOD$1] = method;
16874
- attributes[ATTR_HTTP_URL$2] = url;
16875
- }
16876
- if (this._semconvStability & SemconvStability.STABLE) {
16877
- const origMethod = options.method;
16878
- const normMethod = normalizeHttpRequestMethod$1(options.method || 'GET');
16879
- if (!name) {
16880
- // The "old" span name wins if emitting both old and stable semconv
16881
- // ('http/dup').
16882
- name = normMethod;
16883
- }
16884
- attributes[ATTR_HTTP_REQUEST_METHOD] = normMethod;
16885
- if (normMethod !== origMethod) {
16886
- attributes[ATTR_HTTP_REQUEST_METHOD_ORIGINAL] = origMethod;
16887
- }
16888
- attributes[ATTR_URL_FULL] = url;
16889
- }
16890
- return this.tracer.startSpan(name, {
16891
- kind: SpanKind.CLIENT,
16892
- attributes,
16893
- });
15962
+ return context;
16894
15963
  }
16895
15964
  /**
16896
- * Finds appropriate resource and add network events to the span
15965
+ * Increment number of tasks that are run within the same zone.
15966
+ * This is needed to be able to end span when no more tasks left
16897
15967
  * @param span
16898
- * @param resourcesObserver
16899
- * @param endTime
16900
15968
  */
16901
- _findResourceAndAddNetworkEvents(span, resourcesObserver, endTime) {
16902
- let resources = resourcesObserver.entries;
16903
- if (!resources.length) {
16904
- if (!performance.getEntriesByType) {
16905
- return;
16906
- }
16907
- // fallback - either Observer is not available or it took longer
16908
- // then OBSERVER_WAIT_TIME_MS and observer didn't collect enough
16909
- // information
16910
- resources = performance.getEntriesByType('resource');
16911
- }
16912
- const resource = getResource(resourcesObserver.spanUrl, resourcesObserver.startTime, endTime, resources, this._usedResources, 'fetch');
16913
- if (resource.mainRequest) {
16914
- const mainRequest = resource.mainRequest;
16915
- this._markResourceAsUsed(mainRequest);
16916
- const corsPreFlightRequest = resource.corsPreFlightRequest;
16917
- if (corsPreFlightRequest) {
16918
- this._addChildSpan(span, corsPreFlightRequest);
16919
- this._markResourceAsUsed(corsPreFlightRequest);
16920
- }
16921
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
16922
- addSpanNetworkEvents(span, mainRequest, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
15969
+ _incrementTask(span) {
15970
+ const spanData = this._spansData.get(span);
15971
+ if (spanData) {
15972
+ spanData.taskCount++;
16923
15973
  }
16924
15974
  }
16925
15975
  /**
16926
- * Marks certain [resource]{@link PerformanceResourceTiming} when information
16927
- * from this is used to add events to span.
16928
- * This is done to avoid reusing the same resource again for next span
16929
- * @param resource
15976
+ * Returns true iff we should use the patched callback; false if it's already been patched
16930
15977
  */
16931
- _markResourceAsUsed(resource) {
16932
- this._usedResources.add(resource);
15978
+ addPatchedListener(on, type, listener, wrappedListener) {
15979
+ let listener2Type = this._wrappedListeners.get(listener);
15980
+ if (!listener2Type) {
15981
+ listener2Type = new Map();
15982
+ this._wrappedListeners.set(listener, listener2Type);
15983
+ }
15984
+ let element2patched = listener2Type.get(type);
15985
+ if (!element2patched) {
15986
+ element2patched = new Map();
15987
+ listener2Type.set(type, element2patched);
15988
+ }
15989
+ if (element2patched.has(on)) {
15990
+ return false;
15991
+ }
15992
+ element2patched.set(on, wrappedListener);
15993
+ return true;
16933
15994
  }
16934
15995
  /**
16935
- * Finish span, add attributes, network events etc.
16936
- * @param span
16937
- * @param spanData
16938
- * @param response
15996
+ * Returns the patched version of the callback (or undefined)
16939
15997
  */
16940
- _endSpan(span, spanData, response) {
16941
- const endTime = millisToHrTime(Date.now());
16942
- const performanceEndTime = hrTime();
16943
- this._addFinalSpanAttributes(span, response);
16944
- if (this._semconvStability & SemconvStability.STABLE) {
16945
- // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#status
16946
- if (response.status >= 400) {
16947
- span.setStatus({ code: SpanStatusCode.ERROR });
16948
- span.setAttribute(ATTR_ERROR_TYPE, String(response.status));
15998
+ removePatchedListener(on, type, listener) {
15999
+ const listener2Type = this._wrappedListeners.get(listener);
16000
+ if (!listener2Type) {
16001
+ return undefined;
16002
+ }
16003
+ const element2patched = listener2Type.get(type);
16004
+ if (!element2patched) {
16005
+ return undefined;
16006
+ }
16007
+ const patched = element2patched.get(on);
16008
+ if (patched) {
16009
+ element2patched.delete(on);
16010
+ if (element2patched.size === 0) {
16011
+ listener2Type.delete(type);
16012
+ if (listener2Type.size === 0) {
16013
+ this._wrappedListeners.delete(listener);
16014
+ }
16949
16015
  }
16950
16016
  }
16951
- setTimeout(() => {
16952
- spanData.observer?.disconnect();
16953
- this._findResourceAndAddNetworkEvents(span, spanData, performanceEndTime);
16954
- this._tasksCount--;
16955
- this._clearResources();
16956
- span.end(endTime);
16957
- }, OBSERVER_WAIT_TIME_MS$1);
16017
+ return patched;
16018
+ }
16019
+ // utility method to deal with the Function|EventListener nature of addEventListener
16020
+ _invokeListener(listener, target, args) {
16021
+ if (typeof listener === 'function') {
16022
+ return listener.apply(target, args);
16023
+ }
16024
+ else {
16025
+ return listener.handleEvent(args[0]);
16026
+ }
16958
16027
  }
16959
16028
  /**
16960
- * Patches the constructor of fetch
16029
+ * This patches the addEventListener of HTMLElement to be able to
16030
+ * auto instrument the click events
16031
+ * This is done when zone is not available
16961
16032
  */
16962
- _patchConstructor() {
16963
- return original => {
16964
- const plugin = this;
16965
- return function patchConstructor(...args) {
16966
- const self = this;
16967
- const url = parseUrl(args[0] instanceof Request ? args[0].url : String(args[0])).href;
16968
- const options = args[0] instanceof Request ? args[0] : args[1] || {};
16969
- const createdSpan = plugin._createSpan(url, options);
16970
- if (!createdSpan) {
16971
- return original.apply(this, args);
16972
- }
16973
- const spanData = plugin._prepareSpanData(url);
16974
- if (plugin.getConfig().measureRequestSize) {
16975
- getFetchBodyLength(...args)
16976
- .then(bodyLength => {
16977
- if (!bodyLength)
16978
- return;
16979
- if (plugin._semconvStability & SemconvStability.OLD) {
16980
- createdSpan.setAttribute(ATTR_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED$1, bodyLength);
16981
- }
16982
- if (plugin._semconvStability & SemconvStability.STABLE) {
16983
- createdSpan.setAttribute(ATTR_HTTP_REQUEST_BODY_SIZE$1, bodyLength);
16984
- }
16985
- })
16986
- .catch(error => {
16987
- plugin._diag.warn('getFetchBodyLength', error);
16988
- });
16989
- }
16990
- function endSpanOnError(span, error) {
16991
- plugin._applyAttributesAfterFetch(span, options, error);
16992
- plugin._endSpan(span, spanData, {
16993
- status: error.status || 0,
16994
- statusText: error.message,
16995
- url,
16996
- });
16033
+ _patchAddEventListener() {
16034
+ const plugin = this;
16035
+ return (original) => {
16036
+ return function addEventListenerPatched(type, listener, useCapture) {
16037
+ // Forward calls with listener = null
16038
+ if (!listener) {
16039
+ return original.call(this, type, listener, useCapture);
16997
16040
  }
16998
- function endSpanOnSuccess(span, response) {
16999
- plugin._applyAttributesAfterFetch(span, options, response);
17000
- if (response.status >= 200 && response.status < 400) {
17001
- plugin._endSpan(span, spanData, response);
16041
+ // filter out null (typeof null === 'object')
16042
+ const once = useCapture && typeof useCapture === 'object' && useCapture.once;
16043
+ const patchedListener = function (...args) {
16044
+ let parentSpan;
16045
+ const event = args[0];
16046
+ const target = event?.target;
16047
+ if (event) {
16048
+ parentSpan = plugin._eventsSpanMap.get(event);
17002
16049
  }
17003
- else {
17004
- plugin._endSpan(span, spanData, {
17005
- status: response.status,
17006
- statusText: response.statusText,
17007
- url,
17008
- });
16050
+ if (once) {
16051
+ plugin.removePatchedListener(this, type, listener);
17009
16052
  }
17010
- }
17011
- function withCancelPropagation(body, readerClone) {
17012
- if (!body)
17013
- return null;
17014
- const reader = body.getReader();
17015
- return new ReadableStream({
17016
- async pull(controller) {
17017
- try {
17018
- const { value, done } = await reader.read();
17019
- if (done) {
17020
- reader.releaseLock();
17021
- controller.close();
17022
- }
17023
- else {
17024
- controller.enqueue(value);
17025
- }
17026
- }
17027
- catch (err) {
17028
- controller.error(err);
17029
- reader.cancel(err).catch(_ => { });
17030
- try {
17031
- reader.releaseLock();
17032
- }
17033
- catch {
17034
- // Spec reference:
17035
- // https://streams.spec.whatwg.org/#default-reader-release-lock
17036
- //
17037
- // releaseLock() only throws if called on an invalid reader
17038
- // (i.e. reader.[[stream]] is undefined, meaning the lock is already released
17039
- // or the reader was never associated). In normal use this cannot happen.
17040
- // This catch is defensive only.
17041
- }
17042
- }
17043
- },
17044
- cancel(reason) {
17045
- readerClone.cancel(reason).catch(_ => { });
17046
- return reader.cancel(reason);
17047
- },
17048
- });
17049
- }
17050
- function onSuccess(span, resolve, response) {
17051
- let proxiedResponse = null;
17052
- try {
17053
- // TODO: Switch to a consumer-driven model and drop `resClone`.
17054
- // Keeping eager consumption here to preserve current behavior and avoid breaking existing tests.
17055
- // Context: discussion in PR #5894 → https://github.com/open-telemetry/opentelemetry-js/pull/5894
17056
- const resClone = response.clone();
17057
- const body = resClone.body;
17058
- if (body) {
17059
- const reader = body.getReader();
17060
- const isNullBodyStatus =
17061
- // 101 responses and protocol upgrading is handled internally by the browser
17062
- response.status === 204 ||
17063
- response.status === 205 ||
17064
- response.status === 304;
17065
- const wrappedBody = isNullBodyStatus
17066
- ? null
17067
- : withCancelPropagation(response.body, reader);
17068
- proxiedResponse = new Response(wrappedBody, {
17069
- status: response.status,
17070
- statusText: response.statusText,
17071
- headers: response.headers,
17072
- });
17073
- const read = () => {
17074
- reader.read().then(({ done }) => {
17075
- if (done) {
17076
- endSpanOnSuccess(span, response);
17077
- }
17078
- else {
17079
- read();
17080
- }
17081
- }, error => {
17082
- endSpanOnError(span, error);
17083
- });
17084
- };
17085
- read();
17086
- }
17087
- else {
17088
- // some older browsers don't have .body implemented
17089
- endSpanOnSuccess(span, response);
16053
+ const span = plugin._createSpan(target, type, parentSpan);
16054
+ if (span) {
16055
+ if (event) {
16056
+ plugin._eventsSpanMap.set(event, span);
17090
16057
  }
16058
+ return context.with(trace.setSpan(context.active(), span), () => {
16059
+ const result = plugin._invokeListener(listener, this, args);
16060
+ // no zone so end span immediately
16061
+ span.end();
16062
+ return result;
16063
+ });
17091
16064
  }
17092
- finally {
17093
- resolve(proxiedResponse ?? response);
17094
- }
17095
- }
17096
- function onError(span, reject, error) {
17097
- try {
17098
- endSpanOnError(span, error);
17099
- }
17100
- finally {
17101
- reject(error);
16065
+ else {
16066
+ return plugin._invokeListener(listener, this, args);
17102
16067
  }
16068
+ };
16069
+ if (plugin.addPatchedListener(this, type, listener, patchedListener)) {
16070
+ return original.call(this, type, patchedListener, useCapture);
17103
16071
  }
17104
- return new Promise((resolve, reject) => {
17105
- return context.with(trace.setSpan(context.active(), createdSpan), () => {
17106
- plugin._addHeaders(options, url);
17107
- plugin._callRequestHook(createdSpan, options);
17108
- plugin._tasksCount++;
17109
- return original
17110
- .apply(self, options instanceof Request ? [options] : [url, options])
17111
- .then(onSuccess.bind(self, createdSpan, resolve), onError.bind(self, createdSpan, reject));
17112
- });
17113
- });
17114
16072
  };
17115
16073
  };
17116
16074
  }
17117
- _applyAttributesAfterFetch(span, request, result) {
17118
- const applyCustomAttributesOnSpan = this.getConfig().applyCustomAttributesOnSpan;
17119
- if (applyCustomAttributesOnSpan) {
17120
- safeExecuteInTheMiddle(() => applyCustomAttributesOnSpan(span, request, result), error => {
17121
- if (!error) {
17122
- return;
16075
+ /**
16076
+ * This patches the removeEventListener of HTMLElement to handle the fact that
16077
+ * we patched the original callbacks
16078
+ * This is done when zone is not available
16079
+ */
16080
+ _patchRemoveEventListener() {
16081
+ const plugin = this;
16082
+ return (original) => {
16083
+ return function removeEventListenerPatched(type, listener, useCapture) {
16084
+ const wrappedListener = plugin.removePatchedListener(this, type, listener);
16085
+ if (wrappedListener) {
16086
+ return original.call(this, type, wrappedListener, useCapture);
17123
16087
  }
17124
- this._diag.error('applyCustomAttributesOnSpan', error);
17125
- });
17126
- }
17127
- }
17128
- _callRequestHook(span, request) {
17129
- const requestHook = this.getConfig().requestHook;
17130
- if (requestHook) {
17131
- safeExecuteInTheMiddle(() => requestHook(span, request), error => {
17132
- if (!error) {
17133
- return;
16088
+ else {
16089
+ return original.call(this, type, listener, useCapture);
17134
16090
  }
17135
- this._diag.error('requestHook', error);
17136
- });
17137
- }
16091
+ };
16092
+ };
16093
+ }
16094
+ /**
16095
+ * Most browser provide event listener api via EventTarget in prototype chain.
16096
+ * Exception to this is IE 11 which has it on the prototypes closest to EventTarget:
16097
+ *
16098
+ * * - has addEventListener in IE
16099
+ * ** - has addEventListener in all other browsers
16100
+ * ! - missing in IE
16101
+ *
16102
+ * HTMLElement -> Element -> Node * -> EventTarget **! -> Object
16103
+ * Document -> Node * -> EventTarget **! -> Object
16104
+ * Window * -> WindowProperties ! -> EventTarget **! -> Object
16105
+ */
16106
+ _getPatchableEventTargets() {
16107
+ return window.EventTarget
16108
+ ? [EventTarget.prototype]
16109
+ : [Node.prototype, Window.prototype];
16110
+ }
16111
+ /**
16112
+ * Patches the history api
16113
+ */
16114
+ _patchHistoryApi() {
16115
+ this._unpatchHistoryApi();
16116
+ this._wrap(history, 'replaceState', this._patchHistoryMethod());
16117
+ this._wrap(history, 'pushState', this._patchHistoryMethod());
16118
+ this._wrap(history, 'back', this._patchHistoryMethod());
16119
+ this._wrap(history, 'forward', this._patchHistoryMethod());
16120
+ this._wrap(history, 'go', this._patchHistoryMethod());
17138
16121
  }
17139
16122
  /**
17140
- * Prepares a span data - needed later for matching appropriate network
17141
- * resources
17142
- * @param spanUrl
16123
+ * Patches the certain history api method
17143
16124
  */
17144
- _prepareSpanData(spanUrl) {
17145
- const startTime = hrTime();
17146
- const entries = [];
17147
- if (typeof PerformanceObserver !== 'function') {
17148
- return { entries, startTime, spanUrl };
17149
- }
17150
- const observer = new PerformanceObserver(list => {
17151
- const perfObsEntries = list.getEntries();
17152
- perfObsEntries.forEach(entry => {
17153
- if (entry.initiatorType === 'fetch' && entry.name === spanUrl) {
17154
- entries.push(entry);
16125
+ _patchHistoryMethod() {
16126
+ const plugin = this;
16127
+ return (original) => {
16128
+ return function patchHistoryMethod(...args) {
16129
+ const url = `${location.pathname}${location.hash}${location.search}`;
16130
+ const result = original.apply(this, args);
16131
+ const urlAfter = `${location.pathname}${location.hash}${location.search}`;
16132
+ if (url !== urlAfter) {
16133
+ plugin._updateInteractionName(urlAfter);
17155
16134
  }
17156
- });
17157
- });
17158
- observer.observe({
17159
- entryTypes: ['resource'],
17160
- });
17161
- return { entries, observer, startTime, spanUrl };
16135
+ return result;
16136
+ };
16137
+ };
17162
16138
  }
17163
16139
  /**
17164
- * implements enable function
16140
+ * unpatch the history api methods
17165
16141
  */
17166
- enable() {
17167
- if (isNode) {
17168
- // Node.js v18+ *does* have a global `fetch()`, but this package does not
17169
- // support instrumenting it.
17170
- this._diag.warn("this instrumentation is intended for web usage only, it does not instrument Node.js's fetch()");
17171
- return;
17172
- }
17173
- if (isWrapped(fetch)) {
17174
- this._unwrap(_globalThis$1, 'fetch');
17175
- this._diag.debug('removing previous patch for constructor');
17176
- }
17177
- this._wrap(_globalThis$1, 'fetch', this._patchConstructor());
16142
+ _unpatchHistoryApi() {
16143
+ if (isWrapped(history.replaceState))
16144
+ this._unwrap(history, 'replaceState');
16145
+ if (isWrapped(history.pushState))
16146
+ this._unwrap(history, 'pushState');
16147
+ if (isWrapped(history.back))
16148
+ this._unwrap(history, 'back');
16149
+ if (isWrapped(history.forward))
16150
+ this._unwrap(history, 'forward');
16151
+ if (isWrapped(history.go))
16152
+ this._unwrap(history, 'go');
17178
16153
  }
17179
16154
  /**
17180
- * implements unpatch function
16155
+ * Updates interaction span name
16156
+ * @param url
17181
16157
  */
17182
- disable() {
17183
- if (isNode) {
17184
- return;
16158
+ _updateInteractionName(url) {
16159
+ const span = trace.getSpan(context.active());
16160
+ if (span && typeof span.updateName === 'function') {
16161
+ span.updateName(`${EVENT_NAVIGATION_NAME} ${url}`);
17185
16162
  }
17186
- this._unwrap(_globalThis$1, 'fetch');
17187
- this._usedResources = new WeakSet();
17188
- }
17189
- }
17190
-
17191
- /*
17192
- * Copyright The OpenTelemetry Authors
17193
- *
17194
- * Licensed under the Apache License, Version 2.0 (the "License");
17195
- * you may not use this file except in compliance with the License.
17196
- * You may obtain a copy of the License at
17197
- *
17198
- * https://www.apache.org/licenses/LICENSE-2.0
17199
- *
17200
- * Unless required by applicable law or agreed to in writing, software
17201
- * distributed under the License is distributed on an "AS IS" BASIS,
17202
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17203
- * See the License for the specific language governing permissions and
17204
- * limitations under the License.
17205
- */
17206
- /*
17207
- * This file contains a copy of unstable semantic convention definitions
17208
- * used by this package.
17209
- * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv
17210
- */
17211
- /**
17212
- * Deprecated, use one of `server.address`, `client.address` or `http.request.header.host` instead, depending on the usage.
17213
- *
17214
- * @example www.example.org
17215
- *
17216
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17217
- *
17218
- * @deprecated Replaced by one of `server.address`, `client.address` or `http.request.header.host`, depending on the usage.
17219
- */
17220
- const ATTR_HTTP_HOST = 'http.host';
17221
- /**
17222
- * Deprecated, use `http.request.method` instead.
17223
- *
17224
- * @example GET
17225
- * @example POST
17226
- * @example HEAD
17227
- *
17228
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17229
- *
17230
- * @deprecated Replaced by `http.request.method`.
17231
- */
17232
- const ATTR_HTTP_METHOD = 'http.method';
17233
- /**
17234
- * The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.
17235
- *
17236
- * @example 3495
17237
- *
17238
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17239
- */
17240
- const ATTR_HTTP_REQUEST_BODY_SIZE = 'http.request.body.size';
17241
- /**
17242
- * Deprecated, use `http.request.body.size` instead.
17243
- *
17244
- * @example 5493
17245
- *
17246
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17247
- *
17248
- * @deprecated Replaced by `http.request.body.size`.
17249
- */
17250
- const ATTR_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED = 'http.request_content_length_uncompressed';
17251
- /**
17252
- * Deprecated, use `url.scheme` instead.
17253
- *
17254
- * @example http
17255
- * @example https
17256
- *
17257
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17258
- *
17259
- * @deprecated Replaced by `url.scheme` instead.
17260
- */
17261
- const ATTR_HTTP_SCHEME = 'http.scheme';
17262
- /**
17263
- * Deprecated, use `http.response.status_code` instead.
17264
- *
17265
- * @example 200
17266
- *
17267
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17268
- *
17269
- * @deprecated Replaced by `http.response.status_code`.
17270
- */
17271
- const ATTR_HTTP_STATUS_CODE = 'http.status_code';
17272
- /**
17273
- * Deprecated, use `url.full` instead.
17274
- *
17275
- * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv
17276
- *
17277
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17278
- *
17279
- * @deprecated Replaced by `url.full`.
17280
- */
17281
- const ATTR_HTTP_URL$1 = 'http.url';
17282
- /**
17283
- * Deprecated, use `user_agent.original` instead.
17284
- *
17285
- * @example CERN-LineMode/2.15 libwww/2.17b3
17286
- * @example Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1
17287
- *
17288
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17289
- *
17290
- * @deprecated Replaced by `user_agent.original`.
17291
- */
17292
- const ATTR_HTTP_USER_AGENT$1 = 'http.user_agent';
17293
-
17294
- /*
17295
- * Copyright The OpenTelemetry Authors
17296
- *
17297
- * Licensed under the Apache License, Version 2.0 (the "License");
17298
- * you may not use this file except in compliance with the License.
17299
- * You may obtain a copy of the License at
17300
- *
17301
- * https://www.apache.org/licenses/LICENSE-2.0
17302
- *
17303
- * Unless required by applicable law or agreed to in writing, software
17304
- * distributed under the License is distributed on an "AS IS" BASIS,
17305
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17306
- * See the License for the specific language governing permissions and
17307
- * limitations under the License.
17308
- */
17309
- var EventNames$1;
17310
- (function (EventNames) {
17311
- EventNames["METHOD_OPEN"] = "open";
17312
- EventNames["METHOD_SEND"] = "send";
17313
- EventNames["EVENT_ABORT"] = "abort";
17314
- EventNames["EVENT_ERROR"] = "error";
17315
- EventNames["EVENT_LOAD"] = "loaded";
17316
- EventNames["EVENT_TIMEOUT"] = "timeout";
17317
- })(EventNames$1 || (EventNames$1 = {}));
17318
-
17319
- /*
17320
- * Copyright The OpenTelemetry Authors
17321
- *
17322
- * Licensed under the Apache License, Version 2.0 (the "License");
17323
- * you may not use this file except in compliance with the License.
17324
- * You may obtain a copy of the License at
17325
- *
17326
- * https://www.apache.org/licenses/LICENSE-2.0
17327
- *
17328
- * Unless required by applicable law or agreed to in writing, software
17329
- * distributed under the License is distributed on an "AS IS" BASIS,
17330
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17331
- * See the License for the specific language governing permissions and
17332
- * limitations under the License.
17333
- */
17334
- // Much of the logic here overlaps with the same utils file in opentelemetry-instrumentation-fetch
17335
- // These may be unified in the future.
17336
- const DIAG_LOGGER = diag.createComponentLogger({
17337
- namespace: '@opentelemetry/opentelemetry-instrumentation-xml-http-request/utils',
17338
- });
17339
- function isDocument(value) {
17340
- return typeof Document !== 'undefined' && value instanceof Document;
17341
- }
17342
- /**
17343
- * Helper function to determine payload content length for XHR requests
17344
- * @param body
17345
- * @returns content length
17346
- */
17347
- function getXHRBodyLength(body) {
17348
- if (isDocument(body)) {
17349
- return new XMLSerializer().serializeToString(document).length;
17350
- }
17351
- // XMLHttpRequestBodyInit expands to the following:
17352
- if (typeof body === 'string') {
17353
- return getByteLength(body);
17354
- }
17355
- if (body instanceof Blob) {
17356
- return body.size;
17357
- }
17358
- if (body instanceof FormData) {
17359
- return getFormDataSize(body);
17360
- }
17361
- if (body instanceof URLSearchParams) {
17362
- return getByteLength(body.toString());
17363
- }
17364
- // ArrayBuffer | ArrayBufferView
17365
- if (body.byteLength !== undefined) {
17366
- return body.byteLength;
17367
- }
17368
- DIAG_LOGGER.warn('unknown body type');
17369
- return undefined;
17370
- }
17371
- const TEXT_ENCODER = new TextEncoder();
17372
- function getByteLength(s) {
17373
- return TEXT_ENCODER.encode(s).byteLength;
17374
- }
17375
- function getFormDataSize(formData) {
17376
- let size = 0;
17377
- for (const [key, value] of formData.entries()) {
17378
- size += key.length;
17379
- if (value instanceof Blob) {
17380
- size += value.size;
17381
- }
17382
- else {
17383
- size += value.length;
17384
- }
17385
- }
17386
- return size;
17387
- }
17388
- /**
17389
- * Normalize an HTTP request method string per `http.request.method` spec
17390
- * https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#http-client-span
17391
- */
17392
- function normalizeHttpRequestMethod(method) {
17393
- const knownMethods = getKnownMethods();
17394
- const methUpper = method.toUpperCase();
17395
- if (methUpper in knownMethods) {
17396
- return methUpper;
17397
- }
17398
- else {
17399
- return '_OTHER';
17400
- }
17401
- }
17402
- const DEFAULT_KNOWN_METHODS = {
17403
- CONNECT: true,
17404
- DELETE: true,
17405
- GET: true,
17406
- HEAD: true,
17407
- OPTIONS: true,
17408
- PATCH: true,
17409
- POST: true,
17410
- PUT: true,
17411
- TRACE: true,
17412
- };
17413
- let knownMethods;
17414
- function getKnownMethods() {
17415
- if (knownMethods === undefined) {
17416
- {
17417
- knownMethods = DEFAULT_KNOWN_METHODS;
17418
- }
17419
- }
17420
- return knownMethods;
17421
- }
17422
- const HTTP_PORT_FROM_PROTOCOL = {
17423
- 'https:': '443',
17424
- 'http:': '80',
17425
- };
17426
- function serverPortFromUrl(url) {
17427
- const serverPort = Number(url.port || HTTP_PORT_FROM_PROTOCOL[url.protocol]);
17428
- // Guard with `if (serverPort)` because `Number('') === 0`.
17429
- if (serverPort && !isNaN(serverPort)) {
17430
- return serverPort;
17431
- }
17432
- else {
17433
- return undefined;
17434
- }
17435
- }
17436
-
17437
- /*
17438
- * Copyright The OpenTelemetry Authors
17439
- *
17440
- * Licensed under the Apache License, Version 2.0 (the "License");
17441
- * you may not use this file except in compliance with the License.
17442
- * You may obtain a copy of the License at
17443
- *
17444
- * https://www.apache.org/licenses/LICENSE-2.0
17445
- *
17446
- * Unless required by applicable law or agreed to in writing, software
17447
- * distributed under the License is distributed on an "AS IS" BASIS,
17448
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17449
- * See the License for the specific language governing permissions and
17450
- * limitations under the License.
17451
- */
17452
- // this is autogenerated file, see scripts/version-update.js
17453
- const VERSION = '0.208.0';
17454
-
17455
- /*
17456
- * Copyright The OpenTelemetry Authors
17457
- *
17458
- * Licensed under the Apache License, Version 2.0 (the "License");
17459
- * you may not use this file except in compliance with the License.
17460
- * You may obtain a copy of the License at
17461
- *
17462
- * https://www.apache.org/licenses/LICENSE-2.0
17463
- *
17464
- * Unless required by applicable law or agreed to in writing, software
17465
- * distributed under the License is distributed on an "AS IS" BASIS,
17466
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17467
- * See the License for the specific language governing permissions and
17468
- * limitations under the License.
17469
- */
17470
- /**
17471
- * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md
17472
- */
17473
- var AttributeNames$2;
17474
- (function (AttributeNames) {
17475
- AttributeNames["HTTP_STATUS_TEXT"] = "http.status_text";
17476
- })(AttributeNames$2 || (AttributeNames$2 = {}));
17477
-
17478
- /*
17479
- * Copyright The OpenTelemetry Authors
17480
- *
17481
- * Licensed under the Apache License, Version 2.0 (the "License");
17482
- * you may not use this file except in compliance with the License.
17483
- * You may obtain a copy of the License at
17484
- *
17485
- * https://www.apache.org/licenses/LICENSE-2.0
17486
- *
17487
- * Unless required by applicable law or agreed to in writing, software
17488
- * distributed under the License is distributed on an "AS IS" BASIS,
17489
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17490
- * See the License for the specific language governing permissions and
17491
- * limitations under the License.
17492
- */
17493
- // how long to wait for observer to collect information about resources
17494
- // this is needed as event "load" is called before observer
17495
- // hard to say how long it should really wait, seems like 300ms is
17496
- // safe enough
17497
- const OBSERVER_WAIT_TIME_MS = 300;
17498
- /**
17499
- * This class represents a XMLHttpRequest plugin for auto instrumentation
17500
- */
17501
- class XMLHttpRequestInstrumentation extends InstrumentationBase {
17502
- component = 'xml-http-request';
17503
- version = VERSION;
17504
- moduleName = this.component;
17505
- _tasksCount = 0;
17506
- _xhrMem = new WeakMap();
17507
- _usedResources = new WeakSet();
17508
- _semconvStability;
17509
- constructor(config = {}) {
17510
- super('@opentelemetry/instrumentation-xml-http-request', VERSION, config);
17511
- this._semconvStability = semconvStabilityFromStr('http', config?.semconvStabilityOptIn);
17512
- }
17513
- init() { }
17514
- /**
17515
- * Adds custom headers to XMLHttpRequest
17516
- * @param xhr
17517
- * @param spanUrl
17518
- * @private
17519
- */
17520
- _addHeaders(xhr, spanUrl) {
17521
- const url = parseUrl(spanUrl).href;
17522
- if (!shouldPropagateTraceHeaders(url, this.getConfig().propagateTraceHeaderCorsUrls)) {
17523
- const headers = {};
17524
- propagation.inject(context.active(), headers);
17525
- if (Object.keys(headers).length > 0) {
17526
- this._diag.debug('headers inject skipped due to CORS policy');
17527
- }
17528
- return;
17529
- }
17530
- const headers = {};
17531
- propagation.inject(context.active(), headers);
17532
- Object.keys(headers).forEach(key => {
17533
- xhr.setRequestHeader(key, String(headers[key]));
17534
- });
17535
- }
17536
- /**
17537
- * Add cors pre flight child span
17538
- * @param span
17539
- * @param corsPreFlightRequest
17540
- * @private
17541
- */
17542
- _addChildSpan(span, corsPreFlightRequest) {
17543
- context.with(trace.setSpan(context.active(), span), () => {
17544
- const childSpan = this.tracer.startSpan('CORS Preflight', {
17545
- startTime: corsPreFlightRequest[PerformanceTimingNames.FETCH_START],
17546
- });
17547
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
17548
- addSpanNetworkEvents(childSpan, corsPreFlightRequest, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
17549
- childSpan.end(corsPreFlightRequest[PerformanceTimingNames.RESPONSE_END]);
17550
- });
17551
- }
17552
- /**
17553
- * Add attributes when span is going to end
17554
- * @param span
17555
- * @param xhr
17556
- * @param spanUrl
17557
- * @private
17558
- */
17559
- _addFinalSpanAttributes(span, xhrMem, spanUrl) {
17560
- if (this._semconvStability & SemconvStability.OLD) {
17561
- if (xhrMem.status !== undefined) {
17562
- span.setAttribute(ATTR_HTTP_STATUS_CODE, xhrMem.status);
17563
- }
17564
- if (xhrMem.statusText !== undefined) {
17565
- span.setAttribute(AttributeNames$2.HTTP_STATUS_TEXT, xhrMem.statusText);
17566
- }
17567
- if (typeof spanUrl === 'string') {
17568
- const parsedUrl = parseUrl(spanUrl);
17569
- span.setAttribute(ATTR_HTTP_HOST, parsedUrl.host);
17570
- span.setAttribute(ATTR_HTTP_SCHEME, parsedUrl.protocol.replace(':', ''));
17571
- }
17572
- // @TODO do we want to collect this or it will be collected earlier once only or
17573
- // maybe when parent span is not available ?
17574
- span.setAttribute(ATTR_HTTP_USER_AGENT$1, navigator.userAgent);
17575
- }
17576
- if (this._semconvStability & SemconvStability.STABLE) {
17577
- if (xhrMem.status) {
17578
- // Intentionally exclude status=0, because XHR uses 0 for before a
17579
- // response is received and semconv says to only add the attribute if
17580
- // received a response.
17581
- span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, xhrMem.status);
17582
- }
17583
- }
17584
- }
17585
- _applyAttributesAfterXHR(span, xhr) {
17586
- const applyCustomAttributesOnSpan = this.getConfig().applyCustomAttributesOnSpan;
17587
- if (typeof applyCustomAttributesOnSpan === 'function') {
17588
- safeExecuteInTheMiddle(() => applyCustomAttributesOnSpan(span, xhr), error => {
17589
- if (!error) {
17590
- return;
17591
- }
17592
- this._diag.error('applyCustomAttributesOnSpan', error);
17593
- });
17594
- }
17595
- }
17596
- /**
17597
- * will collect information about all resources created
17598
- * between "send" and "end" with additional waiting for main resource
17599
- * @param xhr
17600
- * @param spanUrl
17601
- * @private
17602
- */
17603
- _addResourceObserver(xhr, spanUrl) {
17604
- const xhrMem = this._xhrMem.get(xhr);
17605
- if (!xhrMem ||
17606
- typeof PerformanceObserver !== 'function' ||
17607
- typeof PerformanceResourceTiming !== 'function') {
17608
- return;
17609
- }
17610
- xhrMem.createdResources = {
17611
- observer: new PerformanceObserver(list => {
17612
- const entries = list.getEntries();
17613
- const parsedUrl = parseUrl(spanUrl);
17614
- entries.forEach(entry => {
17615
- if (entry.initiatorType === 'xmlhttprequest' &&
17616
- entry.name === parsedUrl.href) {
17617
- if (xhrMem.createdResources) {
17618
- xhrMem.createdResources.entries.push(entry);
17619
- }
17620
- }
17621
- });
17622
- }),
17623
- entries: [],
17624
- };
17625
- xhrMem.createdResources.observer.observe({
17626
- entryTypes: ['resource'],
17627
- });
17628
- }
17629
- /**
17630
- * Clears the resource timings and all resources assigned with spans
17631
- * when {@link XMLHttpRequestInstrumentationConfig.clearTimingResources} is
17632
- * set to true (default false)
17633
- * @private
17634
- */
17635
- _clearResources() {
17636
- if (this._tasksCount === 0 && this.getConfig().clearTimingResources) {
17637
- otperformance.clearResourceTimings();
17638
- this._xhrMem = new WeakMap();
17639
- this._usedResources = new WeakSet();
17640
- }
17641
- }
17642
- /**
17643
- * Finds appropriate resource and add network events to the span
17644
- * @param span
17645
- */
17646
- _findResourceAndAddNetworkEvents(xhrMem, span, spanUrl, startTime, endTime) {
17647
- if (!spanUrl || !startTime || !endTime || !xhrMem.createdResources) {
17648
- return;
17649
- }
17650
- let resources = xhrMem.createdResources.entries;
17651
- if (!resources || !resources.length) {
17652
- // fallback - either Observer is not available or it took longer
17653
- // then OBSERVER_WAIT_TIME_MS and observer didn't collect enough
17654
- // information
17655
- // ts thinks this is the perf_hooks module, but it is the browser performance api
17656
- resources = otperformance.getEntriesByType('resource');
17657
- }
17658
- const resource = getResource(parseUrl(spanUrl).href, startTime, endTime, resources, this._usedResources);
17659
- if (resource.mainRequest) {
17660
- const mainRequest = resource.mainRequest;
17661
- this._markResourceAsUsed(mainRequest);
17662
- const corsPreFlightRequest = resource.corsPreFlightRequest;
17663
- if (corsPreFlightRequest) {
17664
- this._addChildSpan(span, corsPreFlightRequest);
17665
- this._markResourceAsUsed(corsPreFlightRequest);
17666
- }
17667
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
17668
- addSpanNetworkEvents(span, mainRequest, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
17669
- }
17670
- }
17671
- /**
17672
- * Removes the previous information about span.
17673
- * This might happened when the same xhr is used again.
17674
- * @param xhr
17675
- * @private
17676
- */
17677
- _cleanPreviousSpanInformation(xhr) {
17678
- const xhrMem = this._xhrMem.get(xhr);
17679
- if (xhrMem) {
17680
- const callbackToRemoveEvents = xhrMem.callbackToRemoveEvents;
17681
- if (callbackToRemoveEvents) {
17682
- callbackToRemoveEvents();
17683
- }
17684
- this._xhrMem.delete(xhr);
17685
- }
17686
- }
17687
- /**
17688
- * Creates a new span when method "open" is called
17689
- * @param xhr
17690
- * @param url
17691
- * @param method
17692
- * @private
17693
- */
17694
- _createSpan(xhr, url, method) {
17695
- if (isUrlIgnored(url, this.getConfig().ignoreUrls)) {
17696
- this._diag.debug('ignoring span as url matches ignored url');
17697
- return;
17698
- }
17699
- let name = '';
17700
- const parsedUrl = parseUrl(url);
17701
- const attributes = {};
17702
- if (this._semconvStability & SemconvStability.OLD) {
17703
- name = method.toUpperCase();
17704
- attributes[ATTR_HTTP_METHOD] = method;
17705
- attributes[ATTR_HTTP_URL$1] = parsedUrl.toString();
17706
- }
17707
- if (this._semconvStability & SemconvStability.STABLE) {
17708
- const origMethod = method;
17709
- const normMethod = normalizeHttpRequestMethod(method);
17710
- if (!name) {
17711
- // The "old" span name wins if emitting both old and stable semconv
17712
- // ('http/dup').
17713
- name = normMethod;
17714
- }
17715
- attributes[ATTR_HTTP_REQUEST_METHOD] = normMethod;
17716
- if (normMethod !== origMethod) {
17717
- attributes[ATTR_HTTP_REQUEST_METHOD_ORIGINAL] = origMethod;
17718
- }
17719
- attributes[ATTR_URL_FULL] = parsedUrl.toString();
17720
- attributes[ATTR_SERVER_ADDRESS] = parsedUrl.hostname;
17721
- const serverPort = serverPortFromUrl(parsedUrl);
17722
- if (serverPort) {
17723
- attributes[ATTR_SERVER_PORT] = serverPort;
17724
- }
17725
- }
17726
- const currentSpan = this.tracer.startSpan(name, {
17727
- kind: SpanKind.CLIENT,
17728
- attributes,
17729
- });
17730
- currentSpan.addEvent(EventNames$1.METHOD_OPEN);
17731
- this._cleanPreviousSpanInformation(xhr);
17732
- this._xhrMem.set(xhr, {
17733
- span: currentSpan,
17734
- spanUrl: url,
17735
- });
17736
- return currentSpan;
17737
- }
17738
- /**
17739
- * Marks certain [resource]{@link PerformanceResourceTiming} when information
17740
- * from this is used to add events to span.
17741
- * This is done to avoid reusing the same resource again for next span
17742
- * @param resource
17743
- * @private
17744
- */
17745
- _markResourceAsUsed(resource) {
17746
- this._usedResources.add(resource);
17747
16163
  }
17748
16164
  /**
17749
- * Patches the method open
17750
- * @private
16165
+ * Patches zone cancel task - this is done to be able to correctly
16166
+ * decrement the number of remaining tasks
17751
16167
  */
17752
- _patchOpen() {
16168
+ _patchZoneCancelTask() {
16169
+ const plugin = this;
17753
16170
  return (original) => {
17754
- const plugin = this;
17755
- return function patchOpen(...args) {
17756
- const method = args[0];
17757
- const url = args[1];
17758
- plugin._createSpan(this, url, method);
17759
- return original.apply(this, args);
17760
- };
17761
- };
17762
- }
17763
- /**
17764
- * Patches the method send
17765
- * @private
17766
- */
17767
- _patchSend() {
17768
- const plugin = this;
17769
- function endSpanTimeout(eventName, xhrMem, performanceEndTime, endTime) {
17770
- const callbackToRemoveEvents = xhrMem.callbackToRemoveEvents;
17771
- if (typeof callbackToRemoveEvents === 'function') {
17772
- callbackToRemoveEvents();
17773
- }
17774
- const { span, spanUrl, sendStartTime } = xhrMem;
17775
- if (span) {
17776
- plugin._findResourceAndAddNetworkEvents(xhrMem, span, spanUrl, sendStartTime, performanceEndTime);
17777
- span.addEvent(eventName, endTime);
17778
- plugin._addFinalSpanAttributes(span, xhrMem, spanUrl);
17779
- span.end(endTime);
17780
- plugin._tasksCount--;
17781
- }
17782
- plugin._clearResources();
17783
- }
17784
- function endSpan(eventName, xhr, isError, errorType) {
17785
- const xhrMem = plugin._xhrMem.get(xhr);
17786
- if (!xhrMem) {
17787
- return;
17788
- }
17789
- xhrMem.status = xhr.status;
17790
- xhrMem.statusText = xhr.statusText;
17791
- plugin._xhrMem.delete(xhr);
17792
- if (xhrMem.span) {
17793
- const span = xhrMem.span;
17794
- plugin._applyAttributesAfterXHR(span, xhr);
17795
- if (plugin._semconvStability & SemconvStability.STABLE) {
17796
- if (isError) {
17797
- if (errorType) {
17798
- span.setStatus({
17799
- code: SpanStatusCode.ERROR,
17800
- message: errorType,
17801
- });
17802
- span.setAttribute(ATTR_ERROR_TYPE, errorType);
17803
- }
17804
- }
17805
- else if (xhrMem.status && xhrMem.status >= 400) {
17806
- span.setStatus({ code: SpanStatusCode.ERROR });
17807
- span.setAttribute(ATTR_ERROR_TYPE, String(xhrMem.status));
17808
- }
17809
- }
17810
- }
17811
- const performanceEndTime = hrTime();
17812
- const endTime = Date.now();
17813
- // the timeout is needed as observer doesn't have yet information
17814
- // when event "load" is called. Also the time may differ depends on
17815
- // browser and speed of computer
17816
- setTimeout(() => {
17817
- endSpanTimeout(eventName, xhrMem, performanceEndTime, endTime);
17818
- }, OBSERVER_WAIT_TIME_MS);
17819
- }
17820
- function onError() {
17821
- endSpan(EventNames$1.EVENT_ERROR, this, true, 'error');
17822
- }
17823
- function onAbort() {
17824
- endSpan(EventNames$1.EVENT_ABORT, this, false);
17825
- }
17826
- function onTimeout() {
17827
- endSpan(EventNames$1.EVENT_TIMEOUT, this, true, 'timeout');
17828
- }
17829
- function onLoad() {
17830
- if (this.status < 299) {
17831
- endSpan(EventNames$1.EVENT_LOAD, this, false);
17832
- }
17833
- else {
17834
- endSpan(EventNames$1.EVENT_ERROR, this, false);
17835
- }
17836
- }
17837
- function unregister(xhr) {
17838
- xhr.removeEventListener('abort', onAbort);
17839
- xhr.removeEventListener('error', onError);
17840
- xhr.removeEventListener('load', onLoad);
17841
- xhr.removeEventListener('timeout', onTimeout);
17842
- const xhrMem = plugin._xhrMem.get(xhr);
17843
- if (xhrMem) {
17844
- xhrMem.callbackToRemoveEvents = undefined;
17845
- }
17846
- }
17847
- return (original) => {
17848
- return function patchSend(...args) {
17849
- const xhrMem = plugin._xhrMem.get(this);
17850
- if (!xhrMem) {
17851
- return original.apply(this, args);
17852
- }
17853
- const currentSpan = xhrMem.span;
17854
- const spanUrl = xhrMem.spanUrl;
17855
- if (currentSpan && spanUrl) {
17856
- if (plugin.getConfig().measureRequestSize && args?.[0]) {
17857
- const body = args[0];
17858
- const bodyLength = getXHRBodyLength(body);
17859
- if (bodyLength !== undefined) {
17860
- if (plugin._semconvStability & SemconvStability.OLD) {
17861
- currentSpan.setAttribute(ATTR_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED, bodyLength);
17862
- }
17863
- if (plugin._semconvStability & SemconvStability.STABLE) {
17864
- currentSpan.setAttribute(ATTR_HTTP_REQUEST_BODY_SIZE, bodyLength);
17865
- }
17866
- }
17867
- }
17868
- context.with(trace.setSpan(context.active(), currentSpan), () => {
17869
- plugin._tasksCount++;
17870
- xhrMem.sendStartTime = hrTime();
17871
- currentSpan.addEvent(EventNames$1.METHOD_SEND);
17872
- this.addEventListener('abort', onAbort);
17873
- this.addEventListener('error', onError);
17874
- this.addEventListener('load', onLoad);
17875
- this.addEventListener('timeout', onTimeout);
17876
- xhrMem.callbackToRemoveEvents = () => {
17877
- unregister(this);
17878
- if (xhrMem.createdResources) {
17879
- xhrMem.createdResources.observer.disconnect();
17880
- }
17881
- };
17882
- plugin._addHeaders(this, spanUrl);
17883
- plugin._addResourceObserver(this, spanUrl);
17884
- });
17885
- }
17886
- return original.apply(this, args);
17887
- };
17888
- };
17889
- }
17890
- /**
17891
- * implements enable function
17892
- */
17893
- enable() {
17894
- this._diag.debug('applying patch to', this.moduleName, this.version);
17895
- if (isWrapped(XMLHttpRequest.prototype.open)) {
17896
- this._unwrap(XMLHttpRequest.prototype, 'open');
17897
- this._diag.debug('removing previous patch from method open');
17898
- }
17899
- if (isWrapped(XMLHttpRequest.prototype.send)) {
17900
- this._unwrap(XMLHttpRequest.prototype, 'send');
17901
- this._diag.debug('removing previous patch from method send');
17902
- }
17903
- this._wrap(XMLHttpRequest.prototype, 'open', this._patchOpen());
17904
- this._wrap(XMLHttpRequest.prototype, 'send', this._patchSend());
17905
- }
17906
- /**
17907
- * implements disable function
17908
- */
17909
- disable() {
17910
- this._diag.debug('removing patch from', this.moduleName, this.version);
17911
- this._unwrap(XMLHttpRequest.prototype, 'open');
17912
- this._unwrap(XMLHttpRequest.prototype, 'send');
17913
- this._tasksCount = 0;
17914
- this._xhrMem = new WeakMap();
17915
- this._usedResources = new WeakSet();
17916
- }
17917
- }
17918
-
17919
- /*
17920
- * Copyright The OpenTelemetry Authors
17921
- *
17922
- * Licensed under the Apache License, Version 2.0 (the "License");
17923
- * you may not use this file except in compliance with the License.
17924
- * You may obtain a copy of the License at
17925
- *
17926
- * https://www.apache.org/licenses/LICENSE-2.0
17927
- *
17928
- * Unless required by applicable law or agreed to in writing, software
17929
- * distributed under the License is distributed on an "AS IS" BASIS,
17930
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17931
- * See the License for the specific language governing permissions and
17932
- * limitations under the License.
17933
- */
17934
- var AttributeNames$1;
17935
- (function (AttributeNames) {
17936
- AttributeNames["EVENT_TYPE"] = "event_type";
17937
- AttributeNames["TARGET_ELEMENT"] = "target_element";
17938
- AttributeNames["TARGET_XPATH"] = "target_xpath";
17939
- AttributeNames["HTTP_URL"] = "http.url";
17940
- })(AttributeNames$1 || (AttributeNames$1 = {}));
17941
-
17942
- /*
17943
- * Copyright The OpenTelemetry Authors
17944
- *
17945
- * Licensed under the Apache License, Version 2.0 (the "License");
17946
- * you may not use this file except in compliance with the License.
17947
- * You may obtain a copy of the License at
17948
- *
17949
- * https://www.apache.org/licenses/LICENSE-2.0
17950
- *
17951
- * Unless required by applicable law or agreed to in writing, software
17952
- * distributed under the License is distributed on an "AS IS" BASIS,
17953
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17954
- * See the License for the specific language governing permissions and
17955
- * limitations under the License.
17956
- */
17957
- // this is autogenerated file, see scripts/version-update.js
17958
- const PACKAGE_VERSION$1 = '0.53.0';
17959
- const PACKAGE_NAME$1 = '@opentelemetry/instrumentation-user-interaction';
17960
-
17961
- /*
17962
- * Copyright The OpenTelemetry Authors
17963
- *
17964
- * Licensed under the Apache License, Version 2.0 (the "License");
17965
- * you may not use this file except in compliance with the License.
17966
- * You may obtain a copy of the License at
17967
- *
17968
- * https://www.apache.org/licenses/LICENSE-2.0
17969
- *
17970
- * Unless required by applicable law or agreed to in writing, software
17971
- * distributed under the License is distributed on an "AS IS" BASIS,
17972
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17973
- * See the License for the specific language governing permissions and
17974
- * limitations under the License.
17975
- */
17976
- /// <reference types="zone.js" />
17977
- const ZONE_CONTEXT_KEY = 'OT_ZONE_CONTEXT';
17978
- const EVENT_NAVIGATION_NAME = 'Navigation:';
17979
- const DEFAULT_EVENT_NAMES = ['click'];
17980
- function defaultShouldPreventSpanCreation() {
17981
- return false;
17982
- }
17983
- /**
17984
- * This class represents a UserInteraction plugin for auto instrumentation.
17985
- * If zone.js is available then it patches the zone otherwise it patches
17986
- * addEventListener of HTMLElement
17987
- */
17988
- class UserInteractionInstrumentation extends InstrumentationBase {
17989
- version = PACKAGE_VERSION$1;
17990
- moduleName = 'user-interaction';
17991
- _spansData = new WeakMap();
17992
- // for addEventListener/removeEventListener state
17993
- _wrappedListeners = new WeakMap();
17994
- // for event bubbling
17995
- _eventsSpanMap = new WeakMap();
17996
- _eventNames;
17997
- _shouldPreventSpanCreation;
17998
- constructor(config = {}) {
17999
- super(PACKAGE_NAME$1, PACKAGE_VERSION$1, config);
18000
- this._eventNames = new Set(config?.eventNames ?? DEFAULT_EVENT_NAMES);
18001
- this._shouldPreventSpanCreation =
18002
- typeof config?.shouldPreventSpanCreation === 'function'
18003
- ? config.shouldPreventSpanCreation
18004
- : defaultShouldPreventSpanCreation;
18005
- }
18006
- init() { }
18007
- /**
18008
- * This will check if last task was timeout and will save the time to
18009
- * fix the user interaction when nothing happens
18010
- * This timeout comes from xhr plugin which is needed to collect information
18011
- * about last xhr main request from observer
18012
- * @param task
18013
- * @param span
18014
- */
18015
- _checkForTimeout(task, span) {
18016
- const spanData = this._spansData.get(span);
18017
- if (spanData) {
18018
- if (task.source === 'setTimeout') {
18019
- spanData.hrTimeLastTimeout = hrTime();
18020
- }
18021
- else if (task.source !== 'Promise.then' &&
18022
- task.source !== 'setTimeout') {
18023
- spanData.hrTimeLastTimeout = undefined;
18024
- }
18025
- }
18026
- }
18027
- /**
18028
- * Controls whether or not to create a span, based on the event type.
18029
- */
18030
- _allowEventName(eventName) {
18031
- return this._eventNames.has(eventName);
18032
- }
18033
- /**
18034
- * Creates a new span
18035
- * @param element
18036
- * @param eventName
18037
- * @param parentSpan
18038
- */
18039
- _createSpan(element, eventName, parentSpan) {
18040
- if (!(element instanceof HTMLElement)) {
18041
- return undefined;
18042
- }
18043
- if (!element.getAttribute) {
18044
- return undefined;
18045
- }
18046
- if (element.hasAttribute('disabled')) {
18047
- return undefined;
18048
- }
18049
- if (!this._allowEventName(eventName)) {
18050
- return undefined;
18051
- }
18052
- const xpath = getElementXPath(element, true);
18053
- try {
18054
- const span = this.tracer.startSpan(eventName, {
18055
- attributes: {
18056
- [AttributeNames$1.EVENT_TYPE]: eventName,
18057
- [AttributeNames$1.TARGET_ELEMENT]: element.tagName,
18058
- [AttributeNames$1.TARGET_XPATH]: xpath,
18059
- [AttributeNames$1.HTTP_URL]: window.location.href,
18060
- },
18061
- }, parentSpan
18062
- ? trace.setSpan(context.active(), parentSpan)
18063
- : undefined);
18064
- if (this._shouldPreventSpanCreation(eventName, element, span) === true) {
18065
- return undefined;
18066
- }
18067
- this._spansData.set(span, {
18068
- taskCount: 0,
18069
- });
18070
- return span;
18071
- }
18072
- catch (e) {
18073
- this._diag.error('failed to start create new user interaction span', e);
18074
- }
18075
- return undefined;
18076
- }
18077
- /**
18078
- * Decrement number of tasks that left in zone,
18079
- * This is needed to be able to end span when no more tasks left
18080
- * @param span
18081
- */
18082
- _decrementTask(span) {
18083
- const spanData = this._spansData.get(span);
18084
- if (spanData) {
18085
- spanData.taskCount--;
18086
- if (spanData.taskCount === 0) {
18087
- this._tryToEndSpan(span, spanData.hrTimeLastTimeout);
18088
- }
18089
- }
18090
- }
18091
- /**
18092
- * Return the current span
18093
- * @param zone
18094
- * @private
18095
- */
18096
- _getCurrentSpan(zone) {
18097
- const context = zone.get(ZONE_CONTEXT_KEY);
18098
- if (context) {
18099
- return trace.getSpan(context);
18100
- }
18101
- return context;
18102
- }
18103
- /**
18104
- * Increment number of tasks that are run within the same zone.
18105
- * This is needed to be able to end span when no more tasks left
18106
- * @param span
18107
- */
18108
- _incrementTask(span) {
18109
- const spanData = this._spansData.get(span);
18110
- if (spanData) {
18111
- spanData.taskCount++;
18112
- }
18113
- }
18114
- /**
18115
- * Returns true iff we should use the patched callback; false if it's already been patched
18116
- */
18117
- addPatchedListener(on, type, listener, wrappedListener) {
18118
- let listener2Type = this._wrappedListeners.get(listener);
18119
- if (!listener2Type) {
18120
- listener2Type = new Map();
18121
- this._wrappedListeners.set(listener, listener2Type);
18122
- }
18123
- let element2patched = listener2Type.get(type);
18124
- if (!element2patched) {
18125
- element2patched = new Map();
18126
- listener2Type.set(type, element2patched);
18127
- }
18128
- if (element2patched.has(on)) {
18129
- return false;
18130
- }
18131
- element2patched.set(on, wrappedListener);
18132
- return true;
18133
- }
18134
- /**
18135
- * Returns the patched version of the callback (or undefined)
18136
- */
18137
- removePatchedListener(on, type, listener) {
18138
- const listener2Type = this._wrappedListeners.get(listener);
18139
- if (!listener2Type) {
18140
- return undefined;
18141
- }
18142
- const element2patched = listener2Type.get(type);
18143
- if (!element2patched) {
18144
- return undefined;
18145
- }
18146
- const patched = element2patched.get(on);
18147
- if (patched) {
18148
- element2patched.delete(on);
18149
- if (element2patched.size === 0) {
18150
- listener2Type.delete(type);
18151
- if (listener2Type.size === 0) {
18152
- this._wrappedListeners.delete(listener);
18153
- }
18154
- }
18155
- }
18156
- return patched;
18157
- }
18158
- // utility method to deal with the Function|EventListener nature of addEventListener
18159
- _invokeListener(listener, target, args) {
18160
- if (typeof listener === 'function') {
18161
- return listener.apply(target, args);
18162
- }
18163
- else {
18164
- return listener.handleEvent(args[0]);
18165
- }
18166
- }
18167
- /**
18168
- * This patches the addEventListener of HTMLElement to be able to
18169
- * auto instrument the click events
18170
- * This is done when zone is not available
18171
- */
18172
- _patchAddEventListener() {
18173
- const plugin = this;
18174
- return (original) => {
18175
- return function addEventListenerPatched(type, listener, useCapture) {
18176
- // Forward calls with listener = null
18177
- if (!listener) {
18178
- return original.call(this, type, listener, useCapture);
18179
- }
18180
- // filter out null (typeof null === 'object')
18181
- const once = useCapture && typeof useCapture === 'object' && useCapture.once;
18182
- const patchedListener = function (...args) {
18183
- let parentSpan;
18184
- const event = args[0];
18185
- const target = event?.target;
18186
- if (event) {
18187
- parentSpan = plugin._eventsSpanMap.get(event);
18188
- }
18189
- if (once) {
18190
- plugin.removePatchedListener(this, type, listener);
18191
- }
18192
- const span = plugin._createSpan(target, type, parentSpan);
18193
- if (span) {
18194
- if (event) {
18195
- plugin._eventsSpanMap.set(event, span);
18196
- }
18197
- return context.with(trace.setSpan(context.active(), span), () => {
18198
- const result = plugin._invokeListener(listener, this, args);
18199
- // no zone so end span immediately
18200
- span.end();
18201
- return result;
18202
- });
18203
- }
18204
- else {
18205
- return plugin._invokeListener(listener, this, args);
18206
- }
18207
- };
18208
- if (plugin.addPatchedListener(this, type, listener, patchedListener)) {
18209
- return original.call(this, type, patchedListener, useCapture);
18210
- }
18211
- };
18212
- };
18213
- }
18214
- /**
18215
- * This patches the removeEventListener of HTMLElement to handle the fact that
18216
- * we patched the original callbacks
18217
- * This is done when zone is not available
18218
- */
18219
- _patchRemoveEventListener() {
18220
- const plugin = this;
18221
- return (original) => {
18222
- return function removeEventListenerPatched(type, listener, useCapture) {
18223
- const wrappedListener = plugin.removePatchedListener(this, type, listener);
18224
- if (wrappedListener) {
18225
- return original.call(this, type, wrappedListener, useCapture);
18226
- }
18227
- else {
18228
- return original.call(this, type, listener, useCapture);
18229
- }
18230
- };
18231
- };
18232
- }
18233
- /**
18234
- * Most browser provide event listener api via EventTarget in prototype chain.
18235
- * Exception to this is IE 11 which has it on the prototypes closest to EventTarget:
18236
- *
18237
- * * - has addEventListener in IE
18238
- * ** - has addEventListener in all other browsers
18239
- * ! - missing in IE
18240
- *
18241
- * HTMLElement -> Element -> Node * -> EventTarget **! -> Object
18242
- * Document -> Node * -> EventTarget **! -> Object
18243
- * Window * -> WindowProperties ! -> EventTarget **! -> Object
18244
- */
18245
- _getPatchableEventTargets() {
18246
- return window.EventTarget
18247
- ? [EventTarget.prototype]
18248
- : [Node.prototype, Window.prototype];
18249
- }
18250
- /**
18251
- * Patches the history api
18252
- */
18253
- _patchHistoryApi() {
18254
- this._unpatchHistoryApi();
18255
- this._wrap(history, 'replaceState', this._patchHistoryMethod());
18256
- this._wrap(history, 'pushState', this._patchHistoryMethod());
18257
- this._wrap(history, 'back', this._patchHistoryMethod());
18258
- this._wrap(history, 'forward', this._patchHistoryMethod());
18259
- this._wrap(history, 'go', this._patchHistoryMethod());
18260
- }
18261
- /**
18262
- * Patches the certain history api method
18263
- */
18264
- _patchHistoryMethod() {
18265
- const plugin = this;
18266
- return (original) => {
18267
- return function patchHistoryMethod(...args) {
18268
- const url = `${location.pathname}${location.hash}${location.search}`;
18269
- const result = original.apply(this, args);
18270
- const urlAfter = `${location.pathname}${location.hash}${location.search}`;
18271
- if (url !== urlAfter) {
18272
- plugin._updateInteractionName(urlAfter);
18273
- }
18274
- return result;
18275
- };
18276
- };
18277
- }
18278
- /**
18279
- * unpatch the history api methods
18280
- */
18281
- _unpatchHistoryApi() {
18282
- if (isWrapped(history.replaceState))
18283
- this._unwrap(history, 'replaceState');
18284
- if (isWrapped(history.pushState))
18285
- this._unwrap(history, 'pushState');
18286
- if (isWrapped(history.back))
18287
- this._unwrap(history, 'back');
18288
- if (isWrapped(history.forward))
18289
- this._unwrap(history, 'forward');
18290
- if (isWrapped(history.go))
18291
- this._unwrap(history, 'go');
18292
- }
18293
- /**
18294
- * Updates interaction span name
18295
- * @param url
18296
- */
18297
- _updateInteractionName(url) {
18298
- const span = trace.getSpan(context.active());
18299
- if (span && typeof span.updateName === 'function') {
18300
- span.updateName(`${EVENT_NAVIGATION_NAME} ${url}`);
18301
- }
18302
- }
18303
- /**
18304
- * Patches zone cancel task - this is done to be able to correctly
18305
- * decrement the number of remaining tasks
18306
- */
18307
- _patchZoneCancelTask() {
18308
- const plugin = this;
18309
- return (original) => {
18310
- return function patchCancelTask(task) {
18311
- const currentZone = Zone.current;
18312
- const currentSpan = plugin._getCurrentSpan(currentZone);
18313
- if (currentSpan && plugin._shouldCountTask(task, currentZone)) {
18314
- plugin._decrementTask(currentSpan);
18315
- }
18316
- return original.call(this, task);
18317
- };
18318
- };
18319
- }
18320
- /**
18321
- * Patches zone schedule task - this is done to be able to correctly
18322
- * increment the number of tasks running within current zone but also to
18323
- * save time in case of timeout running from xhr plugin when waiting for
18324
- * main request from PerformanceResourceTiming
18325
- */
18326
- _patchZoneScheduleTask() {
18327
- const plugin = this;
18328
- return (original) => {
18329
- return function patchScheduleTask(task) {
18330
- const currentZone = Zone.current;
18331
- const currentSpan = plugin._getCurrentSpan(currentZone);
18332
- if (currentSpan && plugin._shouldCountTask(task, currentZone)) {
18333
- plugin._incrementTask(currentSpan);
18334
- plugin._checkForTimeout(task, currentSpan);
18335
- }
18336
- return original.call(this, task);
18337
- };
18338
- };
18339
- }
18340
- /**
18341
- * Patches zone run task - this is done to be able to create a span when
18342
- * user interaction starts
18343
- * @private
18344
- */
18345
- _patchZoneRunTask() {
18346
- const plugin = this;
18347
- return (original) => {
18348
- return function patchRunTask(task, applyThis, applyArgs) {
18349
- const event = Array.isArray(applyArgs) && applyArgs[0] instanceof Event
18350
- ? applyArgs[0]
18351
- : undefined;
18352
- const target = event?.target;
18353
- let span;
18354
- const activeZone = this;
18355
- if (target) {
18356
- span = plugin._createSpan(target, task.eventName);
18357
- if (span) {
18358
- plugin._incrementTask(span);
18359
- return activeZone.run(() => {
18360
- try {
18361
- return context.with(trace.setSpan(context.active(), span), () => {
18362
- const currentZone = Zone.current;
18363
- task._zone = currentZone;
18364
- return original.call(currentZone, task, applyThis, applyArgs);
18365
- });
18366
- }
18367
- finally {
18368
- plugin._decrementTask(span);
18369
- }
18370
- });
18371
- }
18372
- }
18373
- else {
18374
- span = plugin._getCurrentSpan(activeZone);
18375
- }
18376
- try {
18377
- return original.call(activeZone, task, applyThis, applyArgs);
18378
- }
18379
- finally {
18380
- if (span && plugin._shouldCountTask(task, activeZone)) {
18381
- plugin._decrementTask(span);
18382
- }
18383
- }
18384
- };
18385
- };
18386
- }
18387
- /**
18388
- * Decides if task should be counted.
18389
- * @param task
18390
- * @param currentZone
18391
- * @private
18392
- */
18393
- _shouldCountTask(task, currentZone) {
18394
- if (task._zone) {
18395
- currentZone = task._zone;
18396
- }
18397
- if (!currentZone || !task.data || task.data.isPeriodic) {
18398
- return false;
18399
- }
18400
- const currentSpan = this._getCurrentSpan(currentZone);
18401
- if (!currentSpan) {
18402
- return false;
18403
- }
18404
- if (!this._spansData.get(currentSpan)) {
18405
- return false;
18406
- }
18407
- return task.type === 'macroTask' || task.type === 'microTask';
18408
- }
18409
- /**
18410
- * Will try to end span when such span still exists.
18411
- * @param span
18412
- * @param endTime
18413
- * @private
18414
- */
18415
- _tryToEndSpan(span, endTime) {
18416
- if (span) {
18417
- const spanData = this._spansData.get(span);
18418
- if (spanData) {
18419
- span.end(endTime);
18420
- this._spansData.delete(span);
18421
- }
18422
- }
18423
- }
18424
- /**
18425
- * implements enable function
18426
- */
18427
- enable() {
18428
- const ZoneWithPrototype = this._getZoneWithPrototype();
18429
- this._diag.debug('applying patch to', this.moduleName, this.version, 'zone:', !!ZoneWithPrototype);
18430
- if (ZoneWithPrototype) {
18431
- if (isWrapped(ZoneWithPrototype.prototype.runTask)) {
18432
- this._unwrap(ZoneWithPrototype.prototype, 'runTask');
18433
- this._diag.debug('removing previous patch from method runTask');
18434
- }
18435
- if (isWrapped(ZoneWithPrototype.prototype.scheduleTask)) {
18436
- this._unwrap(ZoneWithPrototype.prototype, 'scheduleTask');
18437
- this._diag.debug('removing previous patch from method scheduleTask');
18438
- }
18439
- if (isWrapped(ZoneWithPrototype.prototype.cancelTask)) {
18440
- this._unwrap(ZoneWithPrototype.prototype, 'cancelTask');
18441
- this._diag.debug('removing previous patch from method cancelTask');
18442
- }
18443
- this._zonePatched = true;
18444
- this._wrap(ZoneWithPrototype.prototype, 'runTask', this._patchZoneRunTask());
18445
- this._wrap(ZoneWithPrototype.prototype, 'scheduleTask', this._patchZoneScheduleTask());
18446
- this._wrap(ZoneWithPrototype.prototype, 'cancelTask', this._patchZoneCancelTask());
18447
- }
18448
- else {
18449
- this._zonePatched = false;
18450
- const targets = this._getPatchableEventTargets();
18451
- targets.forEach(target => {
18452
- if (isWrapped(target.addEventListener)) {
18453
- this._unwrap(target, 'addEventListener');
18454
- this._diag.debug('removing previous patch from method addEventListener');
18455
- }
18456
- if (isWrapped(target.removeEventListener)) {
18457
- this._unwrap(target, 'removeEventListener');
18458
- this._diag.debug('removing previous patch from method removeEventListener');
18459
- }
18460
- this._wrap(target, 'addEventListener', this._patchAddEventListener());
18461
- this._wrap(target, 'removeEventListener', this._patchRemoveEventListener());
18462
- });
18463
- }
18464
- this._patchHistoryApi();
18465
- }
18466
- /**
18467
- * implements unpatch function
18468
- */
18469
- disable() {
18470
- const ZoneWithPrototype = this._getZoneWithPrototype();
18471
- this._diag.debug('removing patch from', this.moduleName, this.version, 'zone:', !!ZoneWithPrototype);
18472
- if (ZoneWithPrototype && this._zonePatched) {
18473
- if (isWrapped(ZoneWithPrototype.prototype.runTask)) {
18474
- this._unwrap(ZoneWithPrototype.prototype, 'runTask');
18475
- }
18476
- if (isWrapped(ZoneWithPrototype.prototype.scheduleTask)) {
18477
- this._unwrap(ZoneWithPrototype.prototype, 'scheduleTask');
18478
- }
18479
- if (isWrapped(ZoneWithPrototype.prototype.cancelTask)) {
18480
- this._unwrap(ZoneWithPrototype.prototype, 'cancelTask');
18481
- }
18482
- }
18483
- else {
18484
- const targets = this._getPatchableEventTargets();
18485
- targets.forEach(target => {
18486
- if (isWrapped(target.addEventListener)) {
18487
- this._unwrap(target, 'addEventListener');
18488
- }
18489
- if (isWrapped(target.removeEventListener)) {
18490
- this._unwrap(target, 'removeEventListener');
18491
- }
18492
- });
18493
- }
18494
- this._unpatchHistoryApi();
18495
- }
18496
- /**
18497
- * returns Zone
18498
- */
18499
- _getZoneWithPrototype() {
18500
- const _window = window;
18501
- return _window.Zone;
18502
- }
18503
- }
18504
-
18505
- /*
18506
- * Copyright The OpenTelemetry Authors
18507
- *
18508
- * Licensed under the Apache License, Version 2.0 (the "License");
18509
- * you may not use this file except in compliance with the License.
18510
- * You may obtain a copy of the License at
18511
- *
18512
- * https://www.apache.org/licenses/LICENSE-2.0
18513
- *
18514
- * Unless required by applicable law or agreed to in writing, software
18515
- * distributed under the License is distributed on an "AS IS" BASIS,
18516
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18517
- * See the License for the specific language governing permissions and
18518
- * limitations under the License.
18519
- */
18520
- var AttributeNames;
18521
- (function (AttributeNames) {
18522
- AttributeNames["DOCUMENT_LOAD"] = "documentLoad";
18523
- AttributeNames["DOCUMENT_FETCH"] = "documentFetch";
18524
- AttributeNames["RESOURCE_FETCH"] = "resourceFetch";
18525
- })(AttributeNames || (AttributeNames = {}));
18526
-
18527
- /*
18528
- * Copyright The OpenTelemetry Authors
18529
- *
18530
- * Licensed under the Apache License, Version 2.0 (the "License");
18531
- * you may not use this file except in compliance with the License.
18532
- * You may obtain a copy of the License at
18533
- *
18534
- * https://www.apache.org/licenses/LICENSE-2.0
18535
- *
18536
- * Unless required by applicable law or agreed to in writing, software
18537
- * distributed under the License is distributed on an "AS IS" BASIS,
18538
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18539
- * See the License for the specific language governing permissions and
18540
- * limitations under the License.
18541
- */
18542
- // this is autogenerated file, see scripts/version-update.js
18543
- const PACKAGE_VERSION = '0.54.0';
18544
- const PACKAGE_NAME = '@opentelemetry/instrumentation-document-load';
18545
-
18546
- /*
18547
- * Copyright The OpenTelemetry Authors
18548
- *
18549
- * Licensed under the Apache License, Version 2.0 (the "License");
18550
- * you may not use this file except in compliance with the License.
18551
- * You may obtain a copy of the License at
18552
- *
18553
- * https://www.apache.org/licenses/LICENSE-2.0
18554
- *
18555
- * Unless required by applicable law or agreed to in writing, software
18556
- * distributed under the License is distributed on an "AS IS" BASIS,
18557
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18558
- * See the License for the specific language governing permissions and
18559
- * limitations under the License.
18560
- */
18561
- /*
18562
- * This file contains a copy of unstable semantic convention definitions
18563
- * used by this package.
18564
- * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv
18565
- */
18566
- /**
18567
- * Deprecated, use `http.response.header.content-length` instead.
18568
- *
18569
- * @example 3495
18570
- *
18571
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
18572
- *
18573
- * @deprecated Replaced by `http.response.header.content-length`.
18574
- */
18575
- /**
18576
- * Deprecated, use `url.full` instead.
18577
- *
18578
- * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv
18579
- *
18580
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
18581
- *
18582
- * @deprecated Replaced by `url.full`.
18583
- */
18584
- const ATTR_HTTP_URL = 'http.url';
18585
- /**
18586
- * Deprecated, use `user_agent.original` instead.
18587
- *
18588
- * @example CERN-LineMode/2.15 libwww/2.17b3
18589
- * @example Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1
18590
- *
18591
- * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
18592
- *
18593
- * @deprecated Replaced by `user_agent.original`.
18594
- */
18595
- const ATTR_HTTP_USER_AGENT = 'http.user_agent';
18596
-
18597
- /*
18598
- * Copyright The OpenTelemetry Authors
18599
- *
18600
- * Licensed under the Apache License, Version 2.0 (the "License");
18601
- * you may not use this file except in compliance with the License.
18602
- * You may obtain a copy of the License at
18603
- *
18604
- * https://www.apache.org/licenses/LICENSE-2.0
18605
- *
18606
- * Unless required by applicable law or agreed to in writing, software
18607
- * distributed under the License is distributed on an "AS IS" BASIS,
18608
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18609
- * See the License for the specific language governing permissions and
18610
- * limitations under the License.
18611
- */
18612
- var EventNames;
18613
- (function (EventNames) {
18614
- EventNames["FIRST_PAINT"] = "firstPaint";
18615
- EventNames["FIRST_CONTENTFUL_PAINT"] = "firstContentfulPaint";
18616
- })(EventNames || (EventNames = {}));
18617
-
18618
- /*
18619
- * Copyright The OpenTelemetry Authors
18620
- *
18621
- * Licensed under the Apache License, Version 2.0 (the "License");
18622
- * you may not use this file except in compliance with the License.
18623
- * You may obtain a copy of the License at
18624
- *
18625
- * https://www.apache.org/licenses/LICENSE-2.0
18626
- *
18627
- * Unless required by applicable law or agreed to in writing, software
18628
- * distributed under the License is distributed on an "AS IS" BASIS,
18629
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18630
- * See the License for the specific language governing permissions and
18631
- * limitations under the License.
18632
- */
18633
- const getPerformanceNavigationEntries = () => {
18634
- const entries = {};
18635
- const performanceNavigationTiming = otperformance.getEntriesByType?.('navigation')[0];
18636
- if (performanceNavigationTiming) {
18637
- const keys = Object.values(PerformanceTimingNames);
18638
- keys.forEach((key) => {
18639
- if (hasKey(performanceNavigationTiming, key)) {
18640
- const value = performanceNavigationTiming[key];
18641
- if (typeof value === 'number') {
18642
- entries[key] = value;
18643
- }
18644
- }
18645
- });
18646
- }
18647
- else {
18648
- // // fallback to previous version
18649
- const perf = otperformance;
18650
- const performanceTiming = perf.timing;
18651
- if (performanceTiming) {
18652
- const keys = Object.values(PerformanceTimingNames);
18653
- keys.forEach((key) => {
18654
- if (hasKey(performanceTiming, key)) {
18655
- const value = performanceTiming[key];
18656
- if (typeof value === 'number') {
18657
- entries[key] = value;
18658
- }
18659
- }
18660
- });
18661
- }
18662
- }
18663
- return entries;
18664
- };
18665
- const performancePaintNames = {
18666
- 'first-paint': EventNames.FIRST_PAINT,
18667
- 'first-contentful-paint': EventNames.FIRST_CONTENTFUL_PAINT,
18668
- };
18669
- const addSpanPerformancePaintEvents = (span) => {
18670
- const performancePaintTiming = otperformance.getEntriesByType?.('paint');
18671
- if (performancePaintTiming) {
18672
- performancePaintTiming.forEach(({ name, startTime }) => {
18673
- if (hasKey(performancePaintNames, name)) {
18674
- span.addEvent(performancePaintNames[name], startTime);
18675
- }
18676
- });
18677
- }
18678
- };
18679
-
18680
- /*
18681
- * Copyright The OpenTelemetry Authors
18682
- *
18683
- * Licensed under the Apache License, Version 2.0 (the "License");
18684
- * you may not use this file except in compliance with the License.
18685
- * You may obtain a copy of the License at
18686
- *
18687
- * https://www.apache.org/licenses/LICENSE-2.0
18688
- *
18689
- * Unless required by applicable law or agreed to in writing, software
18690
- * distributed under the License is distributed on an "AS IS" BASIS,
18691
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18692
- * See the License for the specific language governing permissions and
18693
- * limitations under the License.
18694
- */
18695
- /**
18696
- * This class represents a document load plugin
18697
- */
18698
- class DocumentLoadInstrumentation extends InstrumentationBase {
18699
- component = 'document-load';
18700
- version = '1';
18701
- moduleName = this.component;
18702
- _semconvStability;
18703
- constructor(config = {}) {
18704
- super(PACKAGE_NAME, PACKAGE_VERSION, config);
18705
- this._semconvStability = semconvStabilityFromStr('http', config?.semconvStabilityOptIn);
18706
- }
18707
- init() { }
18708
- /**
18709
- * callback to be executed when page is loaded
18710
- */
18711
- _onDocumentLoaded() {
18712
- // Timeout is needed as load event doesn't have yet the performance metrics for loadEnd.
18713
- // Support for event "loadend" is very limited and cannot be used
18714
- window.setTimeout(() => {
18715
- this._collectPerformance();
18716
- });
16171
+ return function patchCancelTask(task) {
16172
+ const currentZone = Zone.current;
16173
+ const currentSpan = plugin._getCurrentSpan(currentZone);
16174
+ if (currentSpan && plugin._shouldCountTask(task, currentZone)) {
16175
+ plugin._decrementTask(currentSpan);
16176
+ }
16177
+ return original.call(this, task);
16178
+ };
16179
+ };
18717
16180
  }
18718
16181
  /**
18719
- * Adds spans for all resources
18720
- * @param rootSpan
16182
+ * Patches zone schedule task - this is done to be able to correctly
16183
+ * increment the number of tasks running within current zone but also to
16184
+ * save time in case of timeout running from xhr plugin when waiting for
16185
+ * main request from PerformanceResourceTiming
18721
16186
  */
18722
- _addResourcesSpans(rootSpan) {
18723
- const resources = otperformance.getEntriesByType?.('resource');
18724
- if (resources) {
18725
- resources.forEach(resource => {
18726
- this._initResourceSpan(resource, rootSpan);
18727
- });
18728
- }
16187
+ _patchZoneScheduleTask() {
16188
+ const plugin = this;
16189
+ return (original) => {
16190
+ return function patchScheduleTask(task) {
16191
+ const currentZone = Zone.current;
16192
+ const currentSpan = plugin._getCurrentSpan(currentZone);
16193
+ if (currentSpan && plugin._shouldCountTask(task, currentZone)) {
16194
+ plugin._incrementTask(currentSpan);
16195
+ plugin._checkForTimeout(task, currentSpan);
16196
+ }
16197
+ return original.call(this, task);
16198
+ };
16199
+ };
18729
16200
  }
18730
16201
  /**
18731
- * Collects information about performance and creates appropriate spans
16202
+ * Patches zone run task - this is done to be able to create a span when
16203
+ * user interaction starts
16204
+ * @private
18732
16205
  */
18733
- _collectPerformance() {
18734
- const metaElement = Array.from(document.getElementsByTagName('meta')).find(e => e.getAttribute('name') === TRACE_PARENT_HEADER);
18735
- const entries = getPerformanceNavigationEntries();
18736
- const traceparent = (metaElement && metaElement.content) || '';
18737
- context.with(propagation.extract(ROOT_CONTEXT, { traceparent }), () => {
18738
- const rootSpan = this._startSpan(AttributeNames.DOCUMENT_LOAD, PerformanceTimingNames.FETCH_START, entries);
18739
- if (!rootSpan) {
18740
- return;
18741
- }
18742
- context.with(trace.setSpan(context.active(), rootSpan), () => {
18743
- const fetchSpan = this._startSpan(AttributeNames.DOCUMENT_FETCH, PerformanceTimingNames.FETCH_START, entries);
18744
- if (fetchSpan) {
18745
- if (this._semconvStability & SemconvStability.OLD) {
18746
- fetchSpan.setAttribute(ATTR_HTTP_URL, location.href);
16206
+ _patchZoneRunTask() {
16207
+ const plugin = this;
16208
+ return (original) => {
16209
+ return function patchRunTask(task, applyThis, applyArgs) {
16210
+ const event = Array.isArray(applyArgs) && applyArgs[0] instanceof Event
16211
+ ? applyArgs[0]
16212
+ : undefined;
16213
+ const target = event?.target;
16214
+ let span;
16215
+ const activeZone = this;
16216
+ if (target) {
16217
+ span = plugin._createSpan(target, task.eventName);
16218
+ if (span) {
16219
+ plugin._incrementTask(span);
16220
+ return activeZone.run(() => {
16221
+ try {
16222
+ return context.with(trace.setSpan(context.active(), span), () => {
16223
+ const currentZone = Zone.current;
16224
+ task._zone = currentZone;
16225
+ return original.call(currentZone, task, applyThis, applyArgs);
16226
+ });
16227
+ }
16228
+ finally {
16229
+ plugin._decrementTask(span);
16230
+ }
16231
+ });
18747
16232
  }
18748
- if (this._semconvStability & SemconvStability.STABLE) {
18749
- fetchSpan.setAttribute(ATTR_URL_FULL, location.href);
16233
+ }
16234
+ else {
16235
+ span = plugin._getCurrentSpan(activeZone);
16236
+ }
16237
+ try {
16238
+ return original.call(activeZone, task, applyThis, applyArgs);
16239
+ }
16240
+ finally {
16241
+ if (span && plugin._shouldCountTask(task, activeZone)) {
16242
+ plugin._decrementTask(span);
18750
16243
  }
18751
- context.with(trace.setSpan(context.active(), fetchSpan), () => {
18752
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
18753
- addSpanNetworkEvents(fetchSpan, entries, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
18754
- this._addCustomAttributesOnSpan(fetchSpan, this.getConfig().applyCustomAttributesOnSpan?.documentFetch);
18755
- this._endSpan(fetchSpan, PerformanceTimingNames.RESPONSE_END, entries);
18756
- });
18757
16244
  }
18758
- });
18759
- if (this._semconvStability & SemconvStability.OLD) {
18760
- rootSpan.setAttribute(ATTR_HTTP_URL, location.href);
18761
- rootSpan.setAttribute(ATTR_HTTP_USER_AGENT, navigator.userAgent);
18762
- }
18763
- if (this._semconvStability & SemconvStability.STABLE) {
18764
- rootSpan.setAttribute(ATTR_URL_FULL, location.href);
18765
- rootSpan.setAttribute(ATTR_USER_AGENT_ORIGINAL, navigator.userAgent);
18766
- }
18767
- this._addResourcesSpans(rootSpan);
18768
- if (!this.getConfig().ignoreNetworkEvents) {
18769
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.FETCH_START, entries);
18770
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.UNLOAD_EVENT_START, entries);
18771
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.UNLOAD_EVENT_END, entries);
18772
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.DOM_INTERACTIVE, entries);
18773
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.DOM_CONTENT_LOADED_EVENT_START, entries);
18774
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.DOM_CONTENT_LOADED_EVENT_END, entries);
18775
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.DOM_COMPLETE, entries);
18776
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.LOAD_EVENT_START, entries);
18777
- addSpanNetworkEvent(rootSpan, PerformanceTimingNames.LOAD_EVENT_END, entries);
18778
- }
18779
- if (!this.getConfig().ignorePerformancePaintEvents) {
18780
- addSpanPerformancePaintEvents(rootSpan);
18781
- }
18782
- this._addCustomAttributesOnSpan(rootSpan, this.getConfig().applyCustomAttributesOnSpan?.documentLoad);
18783
- this._endSpan(rootSpan, PerformanceTimingNames.LOAD_EVENT_END, entries);
18784
- });
16245
+ };
16246
+ };
18785
16247
  }
18786
16248
  /**
18787
- * Helper function for ending span
18788
- * @param span
18789
- * @param performanceName name of performance entry for time end
18790
- * @param entries
16249
+ * Decides if task should be counted.
16250
+ * @param task
16251
+ * @param currentZone
16252
+ * @private
18791
16253
  */
18792
- _endSpan(span, performanceName, entries) {
18793
- // span can be undefined when entries are missing the certain performance - the span will not be created
18794
- if (span) {
18795
- if (hasKey(entries, performanceName)) {
18796
- span.end(entries[performanceName]);
18797
- }
18798
- else {
18799
- // just end span
18800
- span.end();
18801
- }
16254
+ _shouldCountTask(task, currentZone) {
16255
+ if (task._zone) {
16256
+ currentZone = task._zone;
16257
+ }
16258
+ if (!currentZone || !task.data || task.data.isPeriodic) {
16259
+ return false;
16260
+ }
16261
+ const currentSpan = this._getCurrentSpan(currentZone);
16262
+ if (!currentSpan) {
16263
+ return false;
16264
+ }
16265
+ if (!this._spansData.get(currentSpan)) {
16266
+ return false;
18802
16267
  }
16268
+ return task.type === 'macroTask' || task.type === 'microTask';
18803
16269
  }
18804
16270
  /**
18805
- * Creates and ends a span with network information about resource added as timed events
18806
- * @param resource
18807
- * @param parentSpan
16271
+ * Will try to end span when such span still exists.
16272
+ * @param span
16273
+ * @param endTime
16274
+ * @private
18808
16275
  */
18809
- _initResourceSpan(resource, parentSpan) {
18810
- const span = this._startSpan(AttributeNames.RESOURCE_FETCH, PerformanceTimingNames.FETCH_START, resource, parentSpan);
16276
+ _tryToEndSpan(span, endTime) {
18811
16277
  if (span) {
18812
- if (this._semconvStability & SemconvStability.OLD) {
18813
- span.setAttribute(ATTR_HTTP_URL, resource.name);
18814
- }
18815
- if (this._semconvStability & SemconvStability.STABLE) {
18816
- span.setAttribute(ATTR_URL_FULL, resource.name);
16278
+ const spanData = this._spansData.get(span);
16279
+ if (spanData) {
16280
+ span.end(endTime);
16281
+ this._spansData.delete(span);
18817
16282
  }
18818
- const skipOldSemconvContentLengthAttrs = !(this._semconvStability & SemconvStability.OLD);
18819
- addSpanNetworkEvents(span, resource, this.getConfig().ignoreNetworkEvents, undefined, skipOldSemconvContentLengthAttrs);
18820
- this._addCustomAttributesOnResourceSpan(span, resource, this.getConfig().applyCustomAttributesOnSpan?.resourceFetch);
18821
- this._endSpan(span, PerformanceTimingNames.RESPONSE_END, resource);
18822
- }
18823
- }
18824
- /**
18825
- * Helper function for starting a span
18826
- * @param spanName name of span
18827
- * @param performanceName name of performance entry for time start
18828
- * @param entries
18829
- * @param parentSpan
18830
- */
18831
- _startSpan(spanName, performanceName, entries, parentSpan) {
18832
- if (hasKey(entries, performanceName) &&
18833
- typeof entries[performanceName] === 'number') {
18834
- const span = this.tracer.startSpan(spanName, {
18835
- startTime: entries[performanceName],
18836
- }, parentSpan ? trace.setSpan(context.active(), parentSpan) : undefined);
18837
- return span;
18838
16283
  }
18839
- return undefined;
18840
16284
  }
18841
16285
  /**
18842
- * executes callback {_onDocumentLoaded} when the page is loaded
16286
+ * implements enable function
18843
16287
  */
18844
- _waitForPageLoad() {
18845
- if (window.document.readyState === 'complete') {
18846
- this._onDocumentLoaded();
16288
+ enable() {
16289
+ const ZoneWithPrototype = this._getZoneWithPrototype();
16290
+ this._diag.debug('applying patch to', this.moduleName, this.version, 'zone:', !!ZoneWithPrototype);
16291
+ if (ZoneWithPrototype) {
16292
+ if (isWrapped(ZoneWithPrototype.prototype.runTask)) {
16293
+ this._unwrap(ZoneWithPrototype.prototype, 'runTask');
16294
+ this._diag.debug('removing previous patch from method runTask');
16295
+ }
16296
+ if (isWrapped(ZoneWithPrototype.prototype.scheduleTask)) {
16297
+ this._unwrap(ZoneWithPrototype.prototype, 'scheduleTask');
16298
+ this._diag.debug('removing previous patch from method scheduleTask');
16299
+ }
16300
+ if (isWrapped(ZoneWithPrototype.prototype.cancelTask)) {
16301
+ this._unwrap(ZoneWithPrototype.prototype, 'cancelTask');
16302
+ this._diag.debug('removing previous patch from method cancelTask');
16303
+ }
16304
+ this._zonePatched = true;
16305
+ this._wrap(ZoneWithPrototype.prototype, 'runTask', this._patchZoneRunTask());
16306
+ this._wrap(ZoneWithPrototype.prototype, 'scheduleTask', this._patchZoneScheduleTask());
16307
+ this._wrap(ZoneWithPrototype.prototype, 'cancelTask', this._patchZoneCancelTask());
18847
16308
  }
18848
16309
  else {
18849
- this._onDocumentLoaded = this._onDocumentLoaded.bind(this);
18850
- window.addEventListener('load', this._onDocumentLoaded);
18851
- }
18852
- }
18853
- /**
18854
- * adds custom attributes to root span if configured
18855
- */
18856
- _addCustomAttributesOnSpan(span, applyCustomAttributesOnSpan) {
18857
- if (applyCustomAttributesOnSpan) {
18858
- safeExecuteInTheMiddle(() => applyCustomAttributesOnSpan(span), error => {
18859
- if (!error) {
18860
- return;
16310
+ this._zonePatched = false;
16311
+ const targets = this._getPatchableEventTargets();
16312
+ targets.forEach(target => {
16313
+ if (isWrapped(target.addEventListener)) {
16314
+ this._unwrap(target, 'addEventListener');
16315
+ this._diag.debug('removing previous patch from method addEventListener');
16316
+ }
16317
+ if (isWrapped(target.removeEventListener)) {
16318
+ this._unwrap(target, 'removeEventListener');
16319
+ this._diag.debug('removing previous patch from method removeEventListener');
18861
16320
  }
18862
- this._diag.error('addCustomAttributesOnSpan', error);
16321
+ this._wrap(target, 'addEventListener', this._patchAddEventListener());
16322
+ this._wrap(target, 'removeEventListener', this._patchRemoveEventListener());
18863
16323
  });
18864
16324
  }
16325
+ this._patchHistoryApi();
18865
16326
  }
18866
16327
  /**
18867
- * adds custom attributes to span if configured
16328
+ * implements unpatch function
18868
16329
  */
18869
- _addCustomAttributesOnResourceSpan(span, resource, applyCustomAttributesOnSpan) {
18870
- if (applyCustomAttributesOnSpan) {
18871
- safeExecuteInTheMiddle(() => applyCustomAttributesOnSpan(span, resource), error => {
18872
- if (!error) {
18873
- return;
16330
+ disable() {
16331
+ const ZoneWithPrototype = this._getZoneWithPrototype();
16332
+ this._diag.debug('removing patch from', this.moduleName, this.version, 'zone:', !!ZoneWithPrototype);
16333
+ if (ZoneWithPrototype && this._zonePatched) {
16334
+ if (isWrapped(ZoneWithPrototype.prototype.runTask)) {
16335
+ this._unwrap(ZoneWithPrototype.prototype, 'runTask');
16336
+ }
16337
+ if (isWrapped(ZoneWithPrototype.prototype.scheduleTask)) {
16338
+ this._unwrap(ZoneWithPrototype.prototype, 'scheduleTask');
16339
+ }
16340
+ if (isWrapped(ZoneWithPrototype.prototype.cancelTask)) {
16341
+ this._unwrap(ZoneWithPrototype.prototype, 'cancelTask');
16342
+ }
16343
+ }
16344
+ else {
16345
+ const targets = this._getPatchableEventTargets();
16346
+ targets.forEach(target => {
16347
+ if (isWrapped(target.addEventListener)) {
16348
+ this._unwrap(target, 'addEventListener');
16349
+ }
16350
+ if (isWrapped(target.removeEventListener)) {
16351
+ this._unwrap(target, 'removeEventListener');
18874
16352
  }
18875
- this._diag.error('addCustomAttributesOnResourceSpan', error);
18876
16353
  });
18877
16354
  }
16355
+ this._unpatchHistoryApi();
18878
16356
  }
18879
16357
  /**
18880
- * implements enable function
18881
- */
18882
- enable() {
18883
- // remove previously attached load to avoid adding the same event twice
18884
- // in case of multiple enable calling.
18885
- window.removeEventListener('load', this._onDocumentLoaded);
18886
- this._waitForPageLoad();
18887
- }
18888
- /**
18889
- * implements disable function
16358
+ * returns Zone
18890
16359
  */
18891
- disable() {
18892
- window.removeEventListener('load', this._onDocumentLoaded);
16360
+ _getZoneWithPrototype() {
16361
+ const _window = window;
16362
+ return _window.Zone;
18893
16363
  }
18894
16364
  }
18895
16365
 
@@ -19949,6 +17419,65 @@ var UAParser = /*@__PURE__*/getDefaultExportFromCjs(uaParserExports);
19949
17419
  // Semantic convention attribute names
19950
17420
  const ATTR_SERVICE_NAME = 'service.name';
19951
17421
  const ATTR_SERVICE_VERSION = 'service.version';
17422
+ // Token de autenticación para OpenTelemetry Collector
17423
+ const AUTH_TOKEN = 'eAzROSTiqNd3i+M9Jw6q5Tld0jarZc617sJB//pvb5c=';
17424
+ // Instalar interceptores globalmente UNA SOLA VEZ antes de cualquier inicialización
17425
+ let interceptorsInstalled = false;
17426
+ function installAuthInterceptors() {
17427
+ if (interceptorsInstalled) {
17428
+ return;
17429
+ }
17430
+ interceptorsInstalled = true;
17431
+ // Guardar referencia al XHR original ANTES de que OpenTelemetry lo toque
17432
+ const RealXHR = window.XMLHttpRequest;
17433
+ if (!RealXHR) {
17434
+ console.error('[TracingService] XMLHttpRequest not available');
17435
+ return;
17436
+ }
17437
+ // Crear wrapper que agrega el header
17438
+ window.XMLHttpRequest = function () {
17439
+ const xhr = new RealXHR();
17440
+ const originalOpen = xhr.open;
17441
+ const originalSend = xhr.send;
17442
+ let isCollectorRequest = false;
17443
+ xhr.open = function (method, url, ...args) {
17444
+ const urlString = typeof url === 'string' ? url : url.toString();
17445
+ isCollectorRequest = urlString.includes('collector.jaak.ai');
17446
+ return originalOpen.apply(this, [method, url, ...args]);
17447
+ };
17448
+ xhr.send = function (...args) {
17449
+ if (isCollectorRequest) {
17450
+ this.setRequestHeader('Authorization', `Bearer ${AUTH_TOKEN}`);
17451
+ }
17452
+ return originalSend.apply(this, args);
17453
+ };
17454
+ return xhr;
17455
+ };
17456
+ // Copiar propiedades del constructor original
17457
+ for (const prop in RealXHR) {
17458
+ if (RealXHR.hasOwnProperty(prop)) {
17459
+ window.XMLHttpRequest[prop] = RealXHR[prop];
17460
+ }
17461
+ }
17462
+ // También interceptar fetch por si el SDK lo usa en lugar de XHR
17463
+ const originalFetch = window.fetch;
17464
+ window.fetch = function (input, init) {
17465
+ const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
17466
+ if (url.includes('collector.jaak.ai')) {
17467
+ const headers = new Headers(init?.headers || {});
17468
+ headers.set('Authorization', `Bearer ${AUTH_TOKEN}`);
17469
+ init = {
17470
+ ...init,
17471
+ headers: headers,
17472
+ };
17473
+ }
17474
+ return originalFetch.call(this, input, init);
17475
+ };
17476
+ // Deshabilitar sendBeacon globalmente porque no soporta headers personalizados
17477
+ navigator.sendBeacon = function () {
17478
+ return false; // Retornar false fuerza al SDK a usar XHR/Fetch como fallback
17479
+ };
17480
+ }
19952
17481
  class TracingService {
19953
17482
  provider = null;
19954
17483
  tracer = null;
@@ -19960,7 +17489,6 @@ class TracingService {
19960
17489
  customerId;
19961
17490
  tenantId;
19962
17491
  environment;
19963
- propagateTraceHeaderCorsUrls;
19964
17492
  enableAutoInstrumentation;
19965
17493
  spanProcessor = null;
19966
17494
  parser;
@@ -19975,19 +17503,43 @@ class TracingService {
19975
17503
  this.customerId = config.customerId;
19976
17504
  this.tenantId = config.tenantId;
19977
17505
  this.environment = config.environment || 'production';
19978
- this.propagateTraceHeaderCorsUrls = config.propagateTraceHeaderCorsUrls || [];
19979
17506
  this.enableAutoInstrumentation = config.enableAutoInstrumentation ?? false; // Default to false
19980
17507
  this.parser = new UAParser();
19981
17508
  }
19982
17509
  initialize() {
19983
17510
  try {
17511
+ // Instalar interceptores de autenticación ANTES de crear el exporter
17512
+ installAuthInterceptors();
19984
17513
  // Create OTLP exporter
19985
- const exporter = new OTLPTraceExporter({
17514
+ const baseExporter = new OTLPTraceExporter({
19986
17515
  url: this.collectorUrl,
19987
17516
  headers: {
19988
17517
  'Content-Type': 'application/json',
17518
+ 'Authorization': `Bearer ${AUTH_TOKEN}`,
19989
17519
  },
17520
+ // @ts-ignore - useSendBeacon no está en los tipos pero es soportada
17521
+ useSendBeacon: false,
19990
17522
  });
17523
+ // Wrap exporter to log export attempts
17524
+ const exporter = {
17525
+ export: (spans, resultCallback) => {
17526
+ if (this.debug) {
17527
+ console.log('[TracingService] 📤 Exporting', spans.length, 'spans to collector');
17528
+ }
17529
+ baseExporter.export(spans, (result) => {
17530
+ if (result.code !== 0) {
17531
+ console.error('[TracingService] ❌ Export failed:', result);
17532
+ }
17533
+ resultCallback(result);
17534
+ });
17535
+ },
17536
+ shutdown: async () => {
17537
+ return baseExporter.shutdown();
17538
+ },
17539
+ forceFlush: async () => {
17540
+ return baseExporter.forceFlush();
17541
+ },
17542
+ };
19991
17543
  // Create batch span processor for each exporter
19992
17544
  this.spanProcessor = new BatchSpanProcessor(exporter, {
19993
17545
  maxQueueSize: 100,
@@ -19995,24 +17547,10 @@ class TracingService {
19995
17547
  scheduledDelayMillis: 5000,
19996
17548
  exportTimeoutMillis: 30000,
19997
17549
  });
19998
- // Create resource attributes
19999
- const resourceAttributes = {
20000
- [ATTR_SERVICE_NAME]: this.serviceName,
20001
- [ATTR_SERVICE_VERSION]: this.serviceVersion,
20002
- 'deployment.environment': this.environment,
20003
- };
20004
- if (this.customerId) {
20005
- resourceAttributes['customer.id'] = this.customerId;
20006
- }
20007
- if (this.tenantId) {
20008
- resourceAttributes['tenant.id'] = this.tenantId;
20009
- }
20010
- // Create tracer provider with resource
17550
+ // Create tracer provider with span processor in constructor
20011
17551
  this.provider = new WebTracerProvider({
20012
- // Resource will be added via span attributes since Resource class is not available
17552
+ spanProcessors: [this.spanProcessor],
20013
17553
  });
20014
- // Add span processor
20015
- this.provider.addSpanProcessor?.(this.spanProcessor);
20016
17554
  // Configure context manager (Zone.js for async context propagation)
20017
17555
  const contextManager = new ZoneContextManager();
20018
17556
  // Configure propagators (W3C Trace Context + B3 for compatibility)
@@ -20026,19 +17564,7 @@ class TracingService {
20026
17564
  this.tracer = trace.getTracer(this.serviceName, this.serviceVersion);
20027
17565
  // Initialize auto-instrumentation if enabled
20028
17566
  if (this.enableAutoInstrumentation) {
20029
- this.initializeAutoInstrumentation(resourceAttributes);
20030
- }
20031
- if (this.debug) {
20032
- console.log('[TracingService] Initialized successfully', {
20033
- collectorUrl: this.collectorUrl,
20034
- serviceName: this.serviceName,
20035
- serviceVersion: this.serviceVersion,
20036
- environment: this.environment,
20037
- customerId: this.customerId,
20038
- tenantId: this.tenantId,
20039
- autoInstrumentation: this.enableAutoInstrumentation,
20040
- propagateUrls: this.propagateTraceHeaderCorsUrls,
20041
- });
17567
+ this.initializeAutoInstrumentation();
20042
17568
  }
20043
17569
  }
20044
17570
  catch (error) {
@@ -20046,37 +17572,15 @@ class TracingService {
20046
17572
  // Don't throw - telemetry should fail silently in production
20047
17573
  }
20048
17574
  }
20049
- initializeAutoInstrumentation(resourceAttributes) {
17575
+ initializeAutoInstrumentation() {
20050
17576
  try {
20051
- // Auto-instrumentation is disabled by default to reduce noise
20052
- // Enable via config.enableAutoInstrumentation = true if needed
17577
+ // NOTE: XHR and Fetch instrumentation are disabled because we manually intercept
17578
+ // them to add authentication headers. Enabling them causes conflicts.
17579
+ // NOTE: DocumentLoadInstrumentation is disabled because it captures events that
17580
+ // occurred before the component initialized, and cannot use custom trace IDs.
17581
+ // Only enable user interaction instrumentation
20053
17582
  registerInstrumentations({
20054
17583
  instrumentations: [
20055
- // Fetch API instrumentation
20056
- new FetchInstrumentation({
20057
- propagateTraceHeaderCorsUrls: this.propagateTraceHeaderCorsUrls,
20058
- clearTimingResources: true,
20059
- applyCustomAttributesOnSpan: (span, _request, response) => {
20060
- // Add resource attributes to each span
20061
- Object.entries(resourceAttributes).forEach(([key, value]) => {
20062
- span.setAttribute(key, value);
20063
- });
20064
- // Add custom attributes
20065
- if (response && 'status' in response) {
20066
- span.setAttribute('http.response.status_code', response.status);
20067
- }
20068
- },
20069
- }),
20070
- // XMLHttpRequest instrumentation
20071
- new XMLHttpRequestInstrumentation({
20072
- propagateTraceHeaderCorsUrls: this.propagateTraceHeaderCorsUrls,
20073
- applyCustomAttributesOnSpan: (span) => {
20074
- // Add resource attributes to each span
20075
- Object.entries(resourceAttributes).forEach(([key, value]) => {
20076
- span.setAttribute(key, value);
20077
- });
20078
- },
20079
- }),
20080
17584
  // User interaction instrumentation (clicks, etc.)
20081
17585
  new UserInteractionInstrumentation({
20082
17586
  eventNames: ['click', 'submit'],
@@ -20085,13 +17589,8 @@ class TracingService {
20085
17589
  return element.tagName === 'BUTTON' || element.tagName === 'A' || element.tagName === 'FORM';
20086
17590
  },
20087
17591
  }),
20088
- // Document load instrumentation
20089
- new DocumentLoadInstrumentation(),
20090
17592
  ],
20091
17593
  });
20092
- if (this.debug) {
20093
- console.log('[TracingService] Auto-instrumentation enabled');
20094
- }
20095
17594
  }
20096
17595
  catch (error) {
20097
17596
  console.error('[TracingService] Failed to initialize auto-instrumentation:', error);
@@ -20182,19 +17681,24 @@ class TracingService {
20182
17681
  }
20183
17682
  startSpan(name, attributes) {
20184
17683
  if (!this.tracer) {
20185
- // Return a no-op span if tracer is not initialized
17684
+ console.warn('[TracingService] Tracer not initialized, returning no-op span');
20186
17685
  return trace.getTracer('noop').startSpan('noop');
20187
17686
  }
20188
17687
  try {
20189
17688
  let currentContext = context.active();
20190
- // If we have a session trace ID, create a span context with it
20191
- if (this.sessionTraceId) {
20192
- const spanContext = {
17689
+ // If we have a session trace ID and there's no active span, create a root span context
17690
+ if (this.sessionTraceId && !trace.getSpan(currentContext)) {
17691
+ // Create a valid span context for the custom trace ID
17692
+ const remoteSpanContext = {
20193
17693
  traceId: this.sessionTraceId,
20194
17694
  spanId: this.generateSpanId(),
20195
- traceFlags: 0x01, // Sampled
17695
+ traceFlags: TraceFlags.SAMPLED,
17696
+ isRemote: true,
20196
17697
  };
20197
- currentContext = trace.setSpanContext(currentContext, spanContext);
17698
+ // Create a non-recording span with the custom trace context
17699
+ const remoteSpan = trace.wrapSpanContext(remoteSpanContext);
17700
+ // Set this span in the context so child spans inherit the trace ID
17701
+ currentContext = trace.setSpan(currentContext, remoteSpan);
20198
17702
  }
20199
17703
  // Get device info
20200
17704
  const deviceInfo = this.getDeviceInfo();
@@ -20251,20 +17755,15 @@ class TracingService {
20251
17755
  }
20252
17756
  }
20253
17757
  endSpan(span) {
20254
- if (!span)
17758
+ if (!span) {
17759
+ console.warn('[TracingService] endSpan called with null/undefined span');
20255
17760
  return;
17761
+ }
20256
17762
  try {
20257
17763
  span.end();
20258
- if (this.debug) {
20259
- const spanContext = span.spanContext();
20260
- console.log('[TracingService] Ended span', {
20261
- traceId: spanContext.traceId,
20262
- spanId: spanContext.spanId,
20263
- });
20264
- }
20265
17764
  }
20266
17765
  catch (error) {
20267
- console.error('[TracingService] Failed to end span:', error);
17766
+ console.error('[TracingService] Failed to end span:', error);
20268
17767
  }
20269
17768
  }
20270
17769
  addSpanEvent(span, name, attributes) {
@@ -20289,9 +17788,6 @@ class TracingService {
20289
17788
  code: SpanStatusCode.ERROR,
20290
17789
  message: error.message,
20291
17790
  });
20292
- if (this.debug) {
20293
- console.log('[TracingService] Recorded exception:', error);
20294
- }
20295
17791
  }
20296
17792
  catch (err) {
20297
17793
  console.error('[TracingService] Failed to record exception:', err);
@@ -20328,6 +17824,26 @@ class TracingService {
20328
17824
  this.endSpan(span);
20329
17825
  }
20330
17826
  }
17827
+ async traceAsync(name, fn, attributes) {
17828
+ return this.trace(name, fn, attributes);
17829
+ }
17830
+ /**
17831
+ * Flush all pending spans to the collector
17832
+ * Call this when capture/process is complete to send all traces
17833
+ */
17834
+ async flush() {
17835
+ try {
17836
+ if (!this.spanProcessor) {
17837
+ console.warn('[TracingService] No span processor available to flush');
17838
+ return;
17839
+ }
17840
+ await this.spanProcessor.forceFlush();
17841
+ }
17842
+ catch (error) {
17843
+ console.error('[TracingService] ❌ Failed to flush spans:', error);
17844
+ throw error;
17845
+ }
17846
+ }
20331
17847
  async cleanup() {
20332
17848
  try {
20333
17849
  if (this.spanProcessor) {
@@ -20337,9 +17853,6 @@ class TracingService {
20337
17853
  if (this.provider) {
20338
17854
  await this.provider.shutdown();
20339
17855
  }
20340
- if (this.debug) {
20341
- console.log('[TracingService] Cleaned up successfully');
20342
- }
20343
17856
  }
20344
17857
  catch (error) {
20345
17858
  console.error('[TracingService] Failed to cleanup:', error);
@@ -20976,8 +18489,8 @@ class LicenseValidationService {
20976
18489
  static ENVIRONMENT_URLS = {
20977
18490
  dev: 'https://api.dev.jaak.ai',
20978
18491
  qa: 'https://api.qa.jaak.ai',
20979
- staging: 'https://api-staging.jaak.ai',
20980
- prod: 'https://api.jaak.ai',
18492
+ sandbox: 'https://api.sandbox.jaak.ai',
18493
+ prod: 'https://services.api.jaak.ai',
20981
18494
  };
20982
18495
  constructor(environment = 'prod') {
20983
18496
  this.baseUrl = LicenseValidationService.ENVIRONMENT_URLS[environment];
@@ -21076,7 +18589,7 @@ class LicenseValidationService {
21076
18589
  }
21077
18590
  }
21078
18591
 
21079
- const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
18592
+ const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background-color:#000;border:none;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}video::-webkit-media-controls{display:none !important}video::-webkit-media-controls-panel{display:none !important}video::-webkit-media-controls-play-button{display:none !important}video::-webkit-media-controls-start-playback-button{display:none !important}video::-webkit-media-controls-enclosure{display:none !important}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
21080
18593
 
21081
18594
  const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H {
21082
18595
  constructor() {
@@ -21198,6 +18711,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
21198
18711
  MAX_FAILURES = 30;
21199
18712
  lastInferenceTime = 0;
21200
18713
  MIN_INFERENCE_INTERVAL = 50;
18714
+ MOBILE_MIN_INFERENCE_INTERVAL = 100; // Higher interval for mobile to prevent slow motion
21201
18715
  performanceHistory = [];
21202
18716
  PERFORMANCE_HISTORY_SIZE = 10;
21203
18717
  // Sistema simplificado de monitoreo de rendimiento
@@ -21271,6 +18785,10 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
21271
18785
  this.detectionService = this.serviceContainer.getDetectionService();
21272
18786
  this.tracingService = this.serviceContainer.getTracingService();
21273
18787
  this.metricsService = this.serviceContainer.getMetricsService();
18788
+ // Set the custom trace ID if provided via prop
18789
+ if (this.tracingService && this.traceId) {
18790
+ this.tracingService.setSessionTraceId(this.traceId);
18791
+ }
21274
18792
  // Record component initialization
21275
18793
  if (this.tracingService) {
21276
18794
  const span = this.tracingService.startSpan('component.initialize', {
@@ -22058,9 +19576,14 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22058
19576
  return;
22059
19577
  }
22060
19578
  this.frameSkipCounter = 0;
22061
- // Throttle inference
19579
+ // Throttle inference - use higher interval for mobile devices to prevent slow motion effect
22062
19580
  const currentTime = Date.now();
22063
- if (currentTime - this.lastInferenceTime < this.MIN_INFERENCE_INTERVAL) {
19581
+ const isMobileDevice = this.cameraInfoWithAutofocus.deviceType === 'mobile' ||
19582
+ /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
19583
+ const isTablet = this.cameraInfoWithAutofocus.deviceType === 'tablet' ||
19584
+ (/iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768);
19585
+ const minInterval = (isMobileDevice && !isTablet) ? this.MOBILE_MIN_INFERENCE_INTERVAL : this.MIN_INFERENCE_INTERVAL;
19586
+ if (currentTime - this.lastInferenceTime < minInterval) {
22064
19587
  if (captureState.step !== 'completed') {
22065
19588
  this.animationId = requestAnimationFrame(() => this.detectFrame());
22066
19589
  }
@@ -22213,7 +19736,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22213
19736
  isCapturing: false
22214
19737
  };
22215
19738
  const cameraInfo = this.cameraInfoWithAutofocus;
22216
- return (h("div", { key: '69b36b10f1a790caa352acd5e149fe012ddebd3d', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: 'b96d8b52f6bb366b1d6239922a95b100befa5735', class: "license-error-container" }, h("div", { key: '58fb20b1acae97631c35730ed395acf9fa583df2', class: "license-error-card" }, h("svg", { key: 'f2726621e000bad3c62b1106778bb50e32ece973', class: "license-error-icon", width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { key: '18a51f219cdc93f717867f61502c55b35d250532', d: "M12 22C12 22 20 18 20 12V5L12 2L4 5V12C4 18 12 22 12 22Z", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { key: '0f157178a69c10590dd55f55c2223fdef31c2569', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: '0352746bef8e2e5a6be0c3868406005aae574a71', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: 'c63de740aa94503f1cf5e1cd1b366b11bc3253b3', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: 'e36cefd08b510fc38f326de557ffc16425a0b324', class: "license-error-message" }, this.licenseError), h("p", { key: 'c77c6545b5186f7fb77a414120d3f6f5ba4a45f0', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: 'bef70b41a7ec454bed38c4162ce3cafc02c81071', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: '7fd679252453474021494c8dac3ec44da60b40eb', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: '369edcb3d7fcaa18059ae89f340f5e65bd0f0785', class: "video-container" }, h("video", { key: '88a67cf2451ebd53cb4fa709d34d11c7fa98cfc9', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: 'd309664c7a9e64f33dd45e0925f27768483b6795', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
19739
+ return (h("div", { key: 'df70f4fa13b2997a19312125c8b236651cb2b81e', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: 'c4f7b51515843177bc3063dd7cf9383e3a4c6c73', class: "license-error-container" }, h("div", { key: 'a4a7e95a23690f9f59c971dd2af9bd096ae13ef0', class: "license-error-card" }, h("svg", { key: '6489a82c60fc9c1a7d89c2b3a537c04c1766cbd4', class: "license-error-icon", width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { key: 'b90b16b0ee155c8baeee321237470de7b6fa1ff5', d: "M12 22C12 22 20 18 20 12V5L12 2L4 5V12C4 18 12 22 12 22Z", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { key: 'c90ec519befb073208dbc5e30e1237dda7f0a18f', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: 'b926e97a83e19c7ca9b66472fedd53b12d22b7d8', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: '1f1fce48179331b0150e0c55a6d5efcd0bf95762', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: '1f28787cea92c5160664bd8e445fb514ac55eff4', class: "license-error-message" }, this.licenseError), h("p", { key: '552aecf92fd34fbdd802fc80cdba46596edb115b', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: '8c44e1e33fbd22a2319acd6c6b27766bec4355f0', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: 'c2e139fdedcb8e8922f37e915caa7ae3a1b09cb9', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: 'c7876bbe35cd28b52433aab6e97de4a0282e25d5', class: "video-container" }, h("video", { key: 'a5fa99c086eb3730ceee7750ece0842539defa3d', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '2c7923dfa706f65cfc3fe71a6ec626cb2ccce7d4', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
22217
19740
  position: 'absolute',
22218
19741
  left: `${box.x}px`,
22219
19742
  top: `${box.y}px`,
@@ -22222,9 +19745,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22222
19745
  border: '2px solid #32406C',
22223
19746
  pointerEvents: 'none',
22224
19747
  boxSizing: 'border-box'
22225
- } })))), this.isMaskReady && (h("div", { key: 'fbfc808e22ec640ddd9e34d52fab476d7a9becc1', class: "overlay-mask" }, h("div", { key: '40846a04d852bbcc2ac6c4a0ca356adae1c67765', class: "card-outline" }, h("div", { key: '452fe1786b67d0f9194e5d03ad2aaee08868a5fd', class: "side side-top" }), h("div", { key: 'a462c388ea55cd022b9616571f0012bd5eb380d4', class: "side side-right" }), h("div", { key: 'bfa2232443e23f2e72f009c62f7a866b9ff1b084', class: "side side-bottom" }), h("div", { key: '581746eca6fde6340d78e8ab48d6e21d17e7dfd3', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '8e57ac550ea3718322ba954682f93239acbabc78', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '81cfab68789796d901afadc895d28f398e8c15cf', class: "back-capture-section" }, h("div", { key: 'd80455bd916c2d7ac47eb0ce3c62b0e5efbe4dff', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: 'c6d427cb32ecfb1ff40150d39f1d8ad7565f7156', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: 'cb57aec75ff91f2887fa258bd79b8efb98614d13', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: 'c76f356a34fcbc790ebe2d900ed61cc4a6a02e28', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: 'd8fe69623902a5f41587f630552ef28a352733c6', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
19748
+ } })))), this.isMaskReady && (h("div", { key: '3e1f77d89a00e4ad1519875cacd5c541c9b16f91', class: "overlay-mask" }, h("div", { key: '3c717afa809ef2fa102fdaab3418915602516d39', class: "card-outline" }, h("div", { key: 'd3dcd1a85290f3fb2216b1182dce9a4b62cc59c6', class: "side side-top" }), h("div", { key: '4280c1e0f0900ec69b905a6226c1afe9a0a993ad', class: "side side-right" }), h("div", { key: '9b88c21f5eb28d74872409335cd6ca83a284bd9b', class: "side side-bottom" }), h("div", { key: '46b4ef3fca60fcf807da8f574a43cba7f148165b', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '2222975293bebfd04fa2d4ac4878bce48fd35880', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '836fbeadb849cb9df66e03ef0cb791dd0e179df8', class: "back-capture-section" }, h("div", { key: 'f0e8119b79f30ffd40ae206783a83869196757ac', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: 'e245e800e2378989bfa011524cca66026ace52d9', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: 'd98a692f9ff883d05e24122b54c4e36f5f96e82f', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: 'c32b7784e2bbb89947219f0d458d0a4d62b5352a', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: 'bb935e91f07c4c1052576c52aa2a82a726877217', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
22226
19749
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
22227
- : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '08f4037c20b4dfed59553a7f29474940f5f3eb49', class: "camera-controls" }, h("button", { key: 'e873835d5d6587b19eb5e61e0073e4992fe115b6', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: '8fca7e29f868570bb99dd2d09ca7da807656dad0', class: "camera-selector-dropdown" }, h("div", { key: 'abfac31042d3b362c094a297429e0272dabb2511', class: "camera-selector-header" }, h("span", { key: 'ffcd0e3c262aa86c431617568c1070548d88f38a' }, "Seleccionar C\u00E1mara"), h("button", { key: '8351be02ccbfa818cab352a37a29d2cd5bfd53ef', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'b42d7a5855ec2f76bc105f7b03369b3d4c950762', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: 'cf3ca9fe1d626320ad2653a3db44cd86e998bcdf', class: "device-info" }, h("small", { key: '9b908dc6e759f1a5311b068dba10428ebd22cdc3' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '9aa48412eaac0b2adf19f1defb3bc835ab031d9f', class: "manual-capture-section" }, h("button", { key: '1828e293ae4e544b00d0dd17a86401ff0436de37', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'bbea1d654f80e537ff6616920fb6a2cb410e55f0', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '532f72395868ecf58bef350aed4da4e4fc0fa13c', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '555cbc7504660b722f23389899956cf979a27e6c', class: "flip-animation" }, h("div", { key: 'e5de939b02cfb65697c70f265492f1f30f75c771', class: "id-card-icon" }), h("div", { key: '35867c2fbdf463d5b28f0bd3a58313d0d6f15e7b', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '4a96d077e993012ed333384219ba27d5a68787ea', class: "success-animation" }, h("div", { key: '836809412d0674a0061aadaaa7c712a22f8770da', class: "check-icon" }), h("div", { key: 'd541dbdfa548760b196dd09dc44c3d1a6af8093c', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '89a9d99fbeedff1bbcf723ba13d551c3290150fe', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'f100984baef7602ea40cea9bb74b4c84fd1f6ed9', class: "status-spinner" })), h("div", { key: 'ad4161c71f438174117e306e5084bfdff3d18dce', class: "status-content" }, h("div", { key: '26310245b58f331075dd344a6497e90631d5d78c', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'f739148b45f7d43a3015cca3de8efc8b71d3d5e4', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '0397b96391dff4f0662c913068a62c714df168bf', class: "performance-monitor" }, h("div", { key: 'da3c3638b3c048a425bf691b29755762ad40aa5c', class: "performance-expanded" }, h("div", { key: '467f5e2dc207cfd9fd31cef24d434452b3247c5f', class: "metrics-row" }, h("div", { key: 'e620d9017402317e09ec554bf933a4f5a5d0b0de', class: "metric-compact" }, h("span", { key: '8d21fa081bbf3ec7ad54f553b60b0a64ae41fb01', class: "metric-label" }, "FPS"), h("span", { key: '8e99113c7b93c128d7e390900a63f16c5b9483c0', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '67927ff90810b0c4d6717d520ad50142d5d6c0dd', class: "metric-compact" }, h("span", { key: '4810964d65c18248f01aff90dca36d732b80a05c', class: "metric-label" }, "MEM"), h("span", { key: 'e82ff493a2bc1d3baf60c1f638154e9208d0991f', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '6ef07b3f3dc4c3d991f4bbae34e902a9efc1a359', class: "metrics-row" }, h("div", { key: 'b5eed3b30cb99d4d088a05494cda2eff0ba393cc', class: "metric-compact" }, h("span", { key: '52749839a61316b90f424b0920f4c82c6683dd29', class: "metric-label" }, "INF"), h("span", { key: '8509cf19af19b6ac2efc7ab68ac46d9d053c5464', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '34a8540d0840056a525a7afc35ca956943b527af', class: "metric-compact" }, h("span", { key: 'bdc2d8cd180b92ee7b84c8372aba5c2f33289669', class: "metric-label" }, "FRAME"), h("span", { key: '481a0735a5b7258fecdc1bab65a4d4018cc0e7b9', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '7b5aa0a6fe97970f09db23103f7f0301fd98c4f8', class: "metrics-row" }, h("div", { key: '1c691159409e021176557904a1ceec05abc329e1', class: "metric-compact" }, h("span", { key: '5ab6c25d80548aa4e63c79ecf88d2386393ae707', class: "metric-label" }, "DET"), h("span", { key: '7641532633bc764d4dc209ba7e1827a2f3f59338', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'feee52f464eeb965eeadfd944a65e94600591ed5', class: "metric-compact" }, h("span", { key: 'c7962650a7bf1bc86f8c733eb01d5eeb9e08d37e', class: "metric-label" }, "RATE"), h("span", { key: '337529444c8e7bacb47d686d0be33721a066eebe', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '49717c49e5316bfe10690733c5bf07eb0475a3e2', class: "watermark" }, h("img", { key: 'f86ff4364196627bb3f169e5ee1c14696126cd68', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
19750
+ : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '471a1292e9d093cce0a0d3fa7f96f3665de749fb', class: "camera-controls" }, h("button", { key: '406911235a06723310ff577c27e3858912e522c4', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: 'b8fd729b78a3c5cb52b7f17d031bb12b894aaf41', class: "camera-selector-dropdown" }, h("div", { key: '2b9b451440d6b6be4103419694ff6a53c92e68ad', class: "camera-selector-header" }, h("span", { key: '2271f4694aa6c0b32ab23a02a7a8d6d4c1bd4144' }, "Seleccionar C\u00E1mara"), h("button", { key: 'ccfc02eb031da17a4907cd835642785bc2ef5e77', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '073d6e9e09cde8523e926850dfa73704b579c899', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '8f914f855727a6ab02a2941fee91283bf3882df2', class: "device-info" }, h("small", { key: '295433a43a539034992f04a29355deed12082092' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'cc780583a636e7d4910851789710837c9e188d40', class: "manual-capture-section" }, h("button", { key: '40c5e212a3a4eab4d2edf44e29e6b4fe0e4c5e37', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '1245a13523250b5959a1c303ca20662c2d6750c7', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '10a0a26b346ecf0945688f82292720871f8dc0b7', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '68dc7effe82d2f043d778239e2aecb847d159818', class: "flip-animation" }, h("div", { key: '153e0c2229c39c5b9402b9610eaee586d98f84c1', class: "id-card-icon" }), h("div", { key: 'b60b249c43ac5f8417c15b8ce46f60d2cb3134d5', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: 'fefa7bf80546a463a54a275e425241545ace5c77', class: "success-animation" }, h("div", { key: 'cda9d64b3b30cc636d976c2c644a927a8ebe341e', class: "check-icon" }), h("div", { key: 'fd00554df841cdb6e1a167b7e6cc4a6b9b60957a', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: 'cd5fa1fbfa5e3a4e362281553dde2c37601b1078', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'cb0d76938d8ccab99632920ffc9d73a1fa7dec79', class: "status-spinner" })), h("div", { key: 'bcfdc2a24e12dc0bcc19ae0d647be5ce810994d5', class: "status-content" }, h("div", { key: 'a4b6dad22b40aed65a9c81e9581e61a9ca064e40', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '236084444d4d156b672f823349f95b462a8a9bba', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '7423d6c8c7e37b7baffc27fc243536e2659475cc', class: "performance-monitor" }, h("div", { key: '892736f4be3d1cd563ec919c5a504ca8e0d55db0', class: "performance-expanded" }, h("div", { key: 'aa0464f739f838ac4c9e553c79f4c7815f7f65cf', class: "metrics-row" }, h("div", { key: '5dca0c5fe0f91ecfaa25c5775c18a99d53eb8f73', class: "metric-compact" }, h("span", { key: '8e498b185cdefb97286356b56e45dc7b514f667e', class: "metric-label" }, "FPS"), h("span", { key: '3a90611c84b338314ae1503aef6208c67d1282ff', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '568e492ef7dad971f1613132028999a81f38f457', class: "metric-compact" }, h("span", { key: '222fd2b522dd9f7172ad9adb442b10c1ce4c6455', class: "metric-label" }, "MEM"), h("span", { key: '8cbe2cf9fd7dd9e22e9a0df6f214165a09e03045', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'e5d946afd1cc80a15a52c9ba1cb252e6e146e929', class: "metrics-row" }, h("div", { key: '65aaaa92e3ce7b5567560d94f98e16226ecf9fd5', class: "metric-compact" }, h("span", { key: '80c6ad0923e729912274a05fffca039e88aa5719', class: "metric-label" }, "INF"), h("span", { key: '4a87270ebdad3be718b86d1382b2a54092e53a16', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '41ddc923cdfab0012a2f5d3e19aee33dad6116fe', class: "metric-compact" }, h("span", { key: '84e9f4fb3d5bf60235d71d61dc1d6a8ad429293c', class: "metric-label" }, "FRAME"), h("span", { key: '88fd6964307399ac1547c7086f489af90a92a925', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '22409e8dfb349e66ac54c20c6043b414b7ddba34', class: "metrics-row" }, h("div", { key: 'bbe72cb477f4bc313e7978d98c217a4789765df1', class: "metric-compact" }, h("span", { key: '56df43d72df8d3549fa42b2bc32fa5491c3cdb41', class: "metric-label" }, "DET"), h("span", { key: '7ceedb73086eccaed0e25177d76218e9bae1262d', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '9407541b4f975b20843c19e7081d1c26bb3f4fd4', class: "metric-compact" }, h("span", { key: '511ffc66436ffe2f14300122213de11f50fbbc30', class: "metric-label" }, "RATE"), h("span", { key: '6a0c864b46314937043831be7646fbfa3d994c86', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '72f26e4248c87e428a10bbd7b67bd77a9a32f321', class: "watermark" }, h("img", { key: '32e3f23ca1ff81699dd2a4922f8f7d4aeaa3cc2b', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
22228
19751
  }
22229
19752
  // Utility methods
22230
19753
  updateDetectionBoxes(boxes) {
@@ -22732,7 +20255,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22732
20255
  catch (error) {
22733
20256
  }
22734
20257
  }
22735
- completeProcess(skippedBack = false) {
20258
+ async completeProcess(skippedBack = false) {
22736
20259
  this.stateManager.updateCaptureState({
22737
20260
  step: 'completed',
22738
20261
  showSuccessAnimation: true
@@ -22747,6 +20270,15 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22747
20270
  ...capturedImages,
22748
20271
  timestamp: new Date().toISOString()
22749
20272
  };
20273
+ // Flush all traces to collector before emitting capture completed
20274
+ if (this.tracingService) {
20275
+ try {
20276
+ await this.tracingService.flush();
20277
+ }
20278
+ catch (error) {
20279
+ console.error('[my-component] Failed to flush traces:', error);
20280
+ }
20281
+ }
22750
20282
  this.captureCompleted.emit(finalImages);
22751
20283
  setTimeout(() => {
22752
20284
  this.stateManager.updateCaptureState({ showSuccessAnimation: false });
@@ -22938,28 +20470,35 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
22938
20470
  }
22939
20471
  // Adaptive frame skipping based on performance
22940
20472
  getAdaptiveFrameSkip() {
20473
+ // Check if running on mobile device for more aggressive frame skipping
20474
+ const isMobileDevice = this.cameraInfoWithAutofocus.deviceType === 'mobile' ||
20475
+ /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
20476
+ const isTablet = this.cameraInfoWithAutofocus.deviceType === 'tablet' ||
20477
+ (/iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768);
20478
+ // Mobile-specific base frame skip (more aggressive to prevent slow motion effect)
20479
+ const mobileBaseSkip = isMobileDevice && !isTablet ? 4 : this.BASE_FRAME_SKIP;
22941
20480
  // Base conditions for high frame skip
22942
20481
  if (this.consecutiveFailures > 20)
22943
20482
  return this.MAX_FRAME_SKIP;
22944
20483
  if (this.performanceMetrics.inferenceTime > 200)
22945
- return 6;
20484
+ return Math.max(6, mobileBaseSkip);
22946
20485
  if (this.performanceMetrics.memoryUsage > 200)
22947
- return 5;
20486
+ return Math.max(5, mobileBaseSkip);
22948
20487
  // Calculate average processing time
22949
20488
  if (this.performanceHistory.length > 0) {
22950
20489
  const avgProcessingTime = this.performanceHistory.reduce((a, b) => a + b, 0) / this.performanceHistory.length;
22951
20490
  if (avgProcessingTime > 100)
22952
- return 4;
20491
+ return Math.max(4, mobileBaseSkip);
22953
20492
  if (avgProcessingTime > 80)
22954
- return 3;
20493
+ return Math.max(3, mobileBaseSkip);
22955
20494
  if (avgProcessingTime > 60)
22956
- return this.BASE_FRAME_SKIP + 1;
20495
+ return Math.max(this.BASE_FRAME_SKIP + 1, mobileBaseSkip);
22957
20496
  }
22958
20497
  // Low memory devices get higher frame skip
22959
20498
  if (this.performanceMetrics.memoryUsage > 150)
22960
- return 4;
22961
- // Performance is good, use base frame skip
22962
- return this.BASE_FRAME_SKIP;
20499
+ return Math.max(4, mobileBaseSkip);
20500
+ // Mobile devices use higher base frame skip for smoother video
20501
+ return mobileBaseSkip;
22963
20502
  }
22964
20503
  // Método para resetear la máscara a color blanco
22965
20504
  resetMaskToWhite() {