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