@webex/internal-plugin-metrics 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/new-metrics.js +3 -0
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/config.d.ts +3 -0
- package/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
- package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
- package/dist/unhandled-exception-telemetry/index.js +330 -0
- package/dist/unhandled-exception-telemetry/index.js.map +1 -0
- package/dist/unhandled-exception-telemetry/utils.js +105 -0
- package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
- package/package.json +3 -3
- package/src/config.js +3 -0
- package/src/new-metrics.ts +3 -0
- package/src/unhandled-exception-telemetry/index.ts +403 -0
- package/src/unhandled-exception-telemetry/utils.ts +101 -0
- package/test/unit/spec/new-metrics.ts +26 -6
- package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
- package/test/unit/spec/unhandled-exception-telemetry.ts +688 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _Object$keys = require("@babel/runtime-corejs2/core-js/object/keys");
|
|
4
|
+
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
|
|
5
|
+
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
|
|
6
|
+
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
|
|
7
|
+
var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
|
|
8
|
+
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
9
|
+
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
10
|
+
_Object$defineProperty(exports, "__esModule", {
|
|
11
|
+
value: true
|
|
12
|
+
});
|
|
13
|
+
exports.UNHANDLED_EXCEPTION_METRIC_NAME = void 0;
|
|
14
|
+
exports.startUnhandledExceptionTelemetry = startUnhandledExceptionTelemetry;
|
|
15
|
+
var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
|
|
16
|
+
var _get = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/reflect/get"));
|
|
17
|
+
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
|
|
18
|
+
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/is-array"));
|
|
19
|
+
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
20
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/typeof"));
|
|
21
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
22
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
|
|
23
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
24
|
+
var _commonTimers = require("@webex/common-timers");
|
|
25
|
+
var _uuid = _interopRequireDefault(require("uuid"));
|
|
26
|
+
var _utils = require("./utils");
|
|
27
|
+
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
28
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable require-jsdoc, valid-jsdoc */
|
|
29
|
+
var UNHANDLED_EXCEPTION_METRIC_NAME = exports.UNHANDLED_EXCEPTION_METRIC_NAME = 'JS_SDK_OBSERVED_CLIENT_UNHANDLED_EXCEPTION';
|
|
30
|
+
var DEDUPE_WINDOW_MS = 1000;
|
|
31
|
+
var MAX_ERROR_MESSAGE_LENGTH = 4096;
|
|
32
|
+
var MAX_ERROR_NAME_LENGTH = 256;
|
|
33
|
+
var MAX_METADATA_LENGTH = 32000;
|
|
34
|
+
var MAX_STACK_LENGTH = 8192;
|
|
35
|
+
var TELEMETRY_LOG_IDENTIFIER = 'Unhandled Exception Telemetry -->';
|
|
36
|
+
function logTelemetryFailure(webex, message) {
|
|
37
|
+
try {
|
|
38
|
+
var _webex$logger, _webex$logger$error;
|
|
39
|
+
(_webex$logger = webex.logger) === null || _webex$logger === void 0 ? void 0 : (_webex$logger$error = _webex$logger.error) === null || _webex$logger$error === void 0 ? void 0 : _webex$logger$error.call(_webex$logger, TELEMETRY_LOG_IDENTIFIER, message);
|
|
40
|
+
} catch (_unused) {
|
|
41
|
+
// Logging must not turn a telemetry failure into an application failure.
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* SDK-owned browser exception reporter with a single in-memory deduplication window.
|
|
47
|
+
*/
|
|
48
|
+
var UnhandledExceptionTelemetry = /*#__PURE__*/function () {
|
|
49
|
+
/**
|
|
50
|
+
* Registers browser listeners after the SDK is ready.
|
|
51
|
+
* @param webex SDK instance used for configuration and submission.
|
|
52
|
+
* @param eventTarget Browser window.
|
|
53
|
+
*/
|
|
54
|
+
function UnhandledExceptionTelemetry(webex, eventTarget) {
|
|
55
|
+
var _this = this;
|
|
56
|
+
(0, _classCallCheck2.default)(this, UnhandledExceptionTelemetry);
|
|
57
|
+
(0, _defineProperty2.default)(this, "pendingEvents", new _map.default());
|
|
58
|
+
(0, _defineProperty2.default)(this, "eventTarget", void 0);
|
|
59
|
+
(0, _defineProperty2.default)(this, "errorListener", function (event) {
|
|
60
|
+
return _this.captureError(event);
|
|
61
|
+
});
|
|
62
|
+
(0, _defineProperty2.default)(this, "preLoginId", void 0);
|
|
63
|
+
(0, _defineProperty2.default)(this, "rejectionListener", function (event) {
|
|
64
|
+
return _this.captureRejection(event);
|
|
65
|
+
});
|
|
66
|
+
(0, _defineProperty2.default)(this, "webex", void 0);
|
|
67
|
+
(0, _defineProperty2.default)(this, "flushTimer", void 0);
|
|
68
|
+
this.webex = webex;
|
|
69
|
+
this.eventTarget = eventTarget;
|
|
70
|
+
this.preLoginId = _uuid.default.v4();
|
|
71
|
+
eventTarget.addEventListener('error', this.errorListener, {
|
|
72
|
+
capture: true
|
|
73
|
+
});
|
|
74
|
+
eventTarget.addEventListener('unhandledrejection', this.rejectionListener, {
|
|
75
|
+
capture: true
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Removes global listeners and either flushes or discards pending events.
|
|
81
|
+
* @param flushPending Whether to submit pending telemetry before teardown.
|
|
82
|
+
* @returns {void}
|
|
83
|
+
*/
|
|
84
|
+
return (0, _createClass2.default)(UnhandledExceptionTelemetry, [{
|
|
85
|
+
key: "stop",
|
|
86
|
+
value: function stop(flushPending) {
|
|
87
|
+
var _this2 = this;
|
|
88
|
+
this.eventTarget.removeEventListener('error', this.errorListener, {
|
|
89
|
+
capture: true
|
|
90
|
+
});
|
|
91
|
+
this.eventTarget.removeEventListener('unhandledrejection', this.rejectionListener, {
|
|
92
|
+
capture: true
|
|
93
|
+
});
|
|
94
|
+
this.clearFlushTimer();
|
|
95
|
+
if (flushPending) {
|
|
96
|
+
this.pendingEvents.forEach(function (event) {
|
|
97
|
+
return _this2.submit(event);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
this.pendingEvents.clear();
|
|
101
|
+
}
|
|
102
|
+
}, {
|
|
103
|
+
key: "captureError",
|
|
104
|
+
value: function captureError(event) {
|
|
105
|
+
try {
|
|
106
|
+
var resourceTarget = event.target;
|
|
107
|
+
var currentSrc = resourceTarget ? (0, _get.default)(resourceTarget, 'currentSrc') : undefined;
|
|
108
|
+
var src = resourceTarget ? (0, _get.default)(resourceTarget, 'src') : undefined;
|
|
109
|
+
var href = resourceTarget ? (0, _get.default)(resourceTarget, 'href') : undefined;
|
|
110
|
+
var rawResourceUrl = typeof currentSrc === 'string' && currentSrc.length > 0 && currentSrc || typeof src === 'string' && src.length > 0 && src || typeof href === 'string' && href.length > 0 && href || undefined;
|
|
111
|
+
if (rawResourceUrl) {
|
|
112
|
+
var _ref;
|
|
113
|
+
var resourceUrl = (0, _utils.sanitizeResourceUrl)(rawResourceUrl);
|
|
114
|
+
if (!resourceUrl) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
var resourceType = String((_ref = resourceTarget && (0, _get.default)(resourceTarget, 'tagName')) !== null && _ref !== void 0 ? _ref : 'RESOURCE').toUpperCase();
|
|
118
|
+
this.capture({
|
|
119
|
+
kind: 'resource_error',
|
|
120
|
+
message: "Failed to load ".concat(resourceType, " resource"),
|
|
121
|
+
name: 'ResourceError',
|
|
122
|
+
resourceType: resourceType,
|
|
123
|
+
resourceUrl: resourceUrl
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
var error = event.error;
|
|
128
|
+
var message = 'Unknown uncaught error';
|
|
129
|
+
if (typeof (error === null || error === void 0 ? void 0 : error.message) === 'string') {
|
|
130
|
+
message = error.message;
|
|
131
|
+
} else if (typeof event.message === 'string') {
|
|
132
|
+
message = event.message;
|
|
133
|
+
}
|
|
134
|
+
this.capture({
|
|
135
|
+
column: event.colno,
|
|
136
|
+
filename: (0, _utils.removeUrlDetails)(event.filename),
|
|
137
|
+
kind: 'error',
|
|
138
|
+
line: event.lineno,
|
|
139
|
+
message: message,
|
|
140
|
+
name: typeof (error === null || error === void 0 ? void 0 : error.name) === 'string' ? error.name : 'Error',
|
|
141
|
+
stack: typeof (error === null || error === void 0 ? void 0 : error.stack) === 'string' ? error.stack : undefined
|
|
142
|
+
});
|
|
143
|
+
} catch (_unused2) {
|
|
144
|
+
logTelemetryFailure(this.webex, 'Failed to extract an uncaught error.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}, {
|
|
148
|
+
key: "captureRejection",
|
|
149
|
+
value: function captureRejection(event) {
|
|
150
|
+
try {
|
|
151
|
+
var reason = event.reason;
|
|
152
|
+
this.capture({
|
|
153
|
+
kind: 'unhandledrejection',
|
|
154
|
+
message: typeof (reason === null || reason === void 0 ? void 0 : reason.message) === 'string' ? reason.message : (0, _utils.stringifyReason)(reason),
|
|
155
|
+
name: typeof (reason === null || reason === void 0 ? void 0 : reason.name) === 'string' ? reason.name : 'UnhandledRejection',
|
|
156
|
+
stack: typeof (reason === null || reason === void 0 ? void 0 : reason.stack) === 'string' ? reason.stack : undefined
|
|
157
|
+
});
|
|
158
|
+
} catch (_unused3) {
|
|
159
|
+
logTelemetryFailure(this.webex, 'Failed to extract an unhandled rejection.');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}, {
|
|
163
|
+
key: "capture",
|
|
164
|
+
value: function capture(details) {
|
|
165
|
+
var _this3 = this;
|
|
166
|
+
try {
|
|
167
|
+
var _truncate, _ref2, _this$webex$config$ap, _this$webex$config, _this$webex$config2, _this$webex$config3;
|
|
168
|
+
var error = _objectSpread(_objectSpread({}, details), {}, {
|
|
169
|
+
name: (_truncate = (0, _utils.truncate)((0, _utils.removeUrlDetailsFromText)(details.name), MAX_ERROR_NAME_LENGTH)) !== null && _truncate !== void 0 ? _truncate : 'Error',
|
|
170
|
+
message: (0, _utils.truncate)((0, _utils.removeUrlDetailsFromText)(details.message), MAX_ERROR_MESSAGE_LENGTH),
|
|
171
|
+
stack: (0, _utils.truncate)((0, _utils.removeUrlDetailsFromText)(details.stack), MAX_STACK_LENGTH)
|
|
172
|
+
});
|
|
173
|
+
var fingerprint = (0, _utils.createFingerprint)([error.kind, error.name, error.message, error.stack, error.filename, error.line, error.column, error.resourceUrl].join('|'));
|
|
174
|
+
var capturedAt = new Date().getTime();
|
|
175
|
+
var existingEvent = this.pendingEvents.get(fingerprint);
|
|
176
|
+
if (existingEvent) {
|
|
177
|
+
var isWithinDedupeWindow = capturedAt - existingEvent.capturedAt < DEDUPE_WINDOW_MS;
|
|
178
|
+
if (isWithinDedupeWindow) {
|
|
179
|
+
existingEvent.occurrenceCount += 1;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A throttled timer can leave an expired event pending. Its completed window must be
|
|
184
|
+
// submitted before this fingerprint is replaced with a new event and a new window.
|
|
185
|
+
this.pendingEvents.delete(fingerprint);
|
|
186
|
+
this.submit(existingEvent);
|
|
187
|
+
}
|
|
188
|
+
var event = {
|
|
189
|
+
schemaVersion: 1,
|
|
190
|
+
capturedAt: capturedAt,
|
|
191
|
+
eventId: _uuid.default.v4(),
|
|
192
|
+
occurrenceCount: 1,
|
|
193
|
+
common: {
|
|
194
|
+
appName: (_ref2 = (_this$webex$config$ap = (_this$webex$config = this.webex.config) === null || _this$webex$config === void 0 ? void 0 : _this$webex$config.appName) !== null && _this$webex$config$ap !== void 0 ? _this$webex$config$ap : (_this$webex$config2 = this.webex.config) === null || _this$webex$config2 === void 0 ? void 0 : _this$webex$config2.sdkType) !== null && _ref2 !== void 0 ? _ref2 : 'webex-js-sdk',
|
|
195
|
+
appVersion: (_this$webex$config3 = this.webex.config) === null || _this$webex$config3 === void 0 ? void 0 : _this$webex$config3.appVersion,
|
|
196
|
+
runtime: 'browser',
|
|
197
|
+
sdkVersion: this.webex.version
|
|
198
|
+
},
|
|
199
|
+
error: _objectSpread(_objectSpread({}, error), {}, {
|
|
200
|
+
fingerprint: fingerprint
|
|
201
|
+
})
|
|
202
|
+
};
|
|
203
|
+
this.addMetadata(event);
|
|
204
|
+
this.pendingEvents.set(fingerprint, event);
|
|
205
|
+
if (this.flushTimer === undefined) {
|
|
206
|
+
this.flushTimer = (0, _commonTimers.safeSetTimeout)(function () {
|
|
207
|
+
return _this3.flush();
|
|
208
|
+
}, DEDUPE_WINDOW_MS);
|
|
209
|
+
}
|
|
210
|
+
} catch (_unused4) {
|
|
211
|
+
logTelemetryFailure(this.webex, 'Failed to capture an exception.');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}, {
|
|
215
|
+
key: "addMetadata",
|
|
216
|
+
value: function addMetadata(event) {
|
|
217
|
+
var _this$webex$config4, _this$webex$config4$m, _this$webex$config4$m2;
|
|
218
|
+
var getMetadata = (_this$webex$config4 = this.webex.config) === null || _this$webex$config4 === void 0 ? void 0 : (_this$webex$config4$m = _this$webex$config4.metrics) === null || _this$webex$config4$m === void 0 ? void 0 : (_this$webex$config4$m2 = _this$webex$config4$m.unhandledExceptionTelemetry) === null || _this$webex$config4$m2 === void 0 ? void 0 : _this$webex$config4$m2.getMetadata;
|
|
219
|
+
if (!getMetadata) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
var metadata = getMetadata();
|
|
224
|
+
if (metadata === undefined) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
var serializedMetadata = (0, _stringify.default)(metadata);
|
|
228
|
+
if (serializedMetadata === undefined || serializedMetadata.length > MAX_METADATA_LENGTH) {
|
|
229
|
+
event.metadataCaptureStatus = serializedMetadata === undefined ? 'invalid_type' : 'too_large';
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
var parsedMetadata = JSON.parse(serializedMetadata);
|
|
233
|
+
if (parsedMetadata === null || (0, _typeof2.default)(parsedMetadata) !== 'object' || (0, _isArray.default)(parsedMetadata)) {
|
|
234
|
+
event.metadataCaptureStatus = 'invalid_type';
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
event.metadata = parsedMetadata;
|
|
238
|
+
} catch (_unused5) {
|
|
239
|
+
event.metadataCaptureStatus = 'provider_error';
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}, {
|
|
243
|
+
key: "flush",
|
|
244
|
+
value: function flush() {
|
|
245
|
+
var _this4 = this;
|
|
246
|
+
var now = new Date().getTime();
|
|
247
|
+
var nextFlushInMs;
|
|
248
|
+
this.clearFlushTimer();
|
|
249
|
+
this.pendingEvents.forEach(function (event, fingerprint) {
|
|
250
|
+
var _nextFlushInMs;
|
|
251
|
+
var remainingWindowMs = DEDUPE_WINDOW_MS - (now - event.capturedAt);
|
|
252
|
+
if (remainingWindowMs <= 0) {
|
|
253
|
+
_this4.pendingEvents.delete(fingerprint);
|
|
254
|
+
_this4.submit(event);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
nextFlushInMs = Math.min((_nextFlushInMs = nextFlushInMs) !== null && _nextFlushInMs !== void 0 ? _nextFlushInMs : remainingWindowMs, remainingWindowMs);
|
|
258
|
+
});
|
|
259
|
+
if (nextFlushInMs !== undefined) {
|
|
260
|
+
this.flushTimer = (0, _commonTimers.safeSetTimeout)(function () {
|
|
261
|
+
return _this4.flush();
|
|
262
|
+
}, nextFlushInMs);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}, {
|
|
266
|
+
key: "submit",
|
|
267
|
+
value: function submit(event) {
|
|
268
|
+
var _this$webex$internal,
|
|
269
|
+
_this$webex$internal$,
|
|
270
|
+
_this5 = this;
|
|
271
|
+
var submitClientMetrics = (_this$webex$internal = this.webex.internal) === null || _this$webex$internal === void 0 ? void 0 : (_this$webex$internal$ = _this$webex$internal.metrics) === null || _this$webex$internal$ === void 0 ? void 0 : _this$webex$internal$.submitClientMetrics;
|
|
272
|
+
if (!submitClientMetrics) {
|
|
273
|
+
logTelemetryFailure(this.webex, 'submitClientMetrics is unavailable.');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
var _this$webex$internal2;
|
|
278
|
+
_promise.default.resolve(submitClientMetrics.call((_this$webex$internal2 = this.webex.internal) === null || _this$webex$internal2 === void 0 ? void 0 : _this$webex$internal2.metrics, UNHANDLED_EXCEPTION_METRIC_NAME, {
|
|
279
|
+
tags: {
|
|
280
|
+
app_name: event.common.appName,
|
|
281
|
+
exception_kind: event.error.kind,
|
|
282
|
+
runtime: event.common.runtime
|
|
283
|
+
},
|
|
284
|
+
fields: {
|
|
285
|
+
captured_at: event.capturedAt,
|
|
286
|
+
error_fingerprint: event.error.fingerprint,
|
|
287
|
+
error_name: event.error.name,
|
|
288
|
+
event_id: event.eventId,
|
|
289
|
+
occurrence_count: event.occurrenceCount
|
|
290
|
+
},
|
|
291
|
+
eventPayload: event
|
|
292
|
+
}, this.webex.canAuthorize === true ? undefined : this.preLoginId)).catch(function () {
|
|
293
|
+
logTelemetryFailure(_this5.webex, 'Failed to submit exception telemetry.');
|
|
294
|
+
});
|
|
295
|
+
} catch (_unused6) {
|
|
296
|
+
logTelemetryFailure(this.webex, 'Failed to submit exception telemetry.');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}, {
|
|
300
|
+
key: "clearFlushTimer",
|
|
301
|
+
value: function clearFlushTimer() {
|
|
302
|
+
if (this.flushTimer !== undefined) {
|
|
303
|
+
clearTimeout(this.flushTimer);
|
|
304
|
+
this.flushTimer = undefined;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}]);
|
|
308
|
+
}();
|
|
309
|
+
var activeTelemetry;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Starts browser exception telemetry after SDK readiness.
|
|
313
|
+
* @param webex Initialized SDK instance.
|
|
314
|
+
* @returns {void}
|
|
315
|
+
*/
|
|
316
|
+
function startUnhandledExceptionTelemetry(webex) {
|
|
317
|
+
var _webex$config, _webex$config$metrics, _webex$config$metrics2, _activeTelemetry;
|
|
318
|
+
var shouldStart = ((_webex$config = webex.config) === null || _webex$config === void 0 ? void 0 : (_webex$config$metrics = _webex$config.metrics) === null || _webex$config$metrics === void 0 ? void 0 : (_webex$config$metrics2 = _webex$config$metrics.unhandledExceptionTelemetry) === null || _webex$config$metrics2 === void 0 ? void 0 : _webex$config$metrics2.enabled) === true && typeof window !== 'undefined' && typeof window.addEventListener === 'function';
|
|
319
|
+
(_activeTelemetry = activeTelemetry) === null || _activeTelemetry === void 0 ? void 0 : _activeTelemetry.stop(shouldStart);
|
|
320
|
+
activeTelemetry = undefined;
|
|
321
|
+
if (!shouldStart) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
activeTelemetry = new UnhandledExceptionTelemetry(webex, window);
|
|
326
|
+
} catch (_unused7) {
|
|
327
|
+
logTelemetryFailure(webex, 'Failed to start exception telemetry.');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_commonTimers","require","_uuid","_interopRequireDefault","_utils","ownKeys","e","r","t","_Object$keys","_Object$getOwnPropertySymbols","o","filter","_Object$getOwnPropertyDescriptor","enumerable","push","apply","_objectSpread","arguments","length","Object","forEach","_defineProperty2","default","_Object$getOwnPropertyDescriptors","_Object$defineProperties","_Object$defineProperty","UNHANDLED_EXCEPTION_METRIC_NAME","exports","DEDUPE_WINDOW_MS","MAX_ERROR_MESSAGE_LENGTH","MAX_ERROR_NAME_LENGTH","MAX_METADATA_LENGTH","MAX_STACK_LENGTH","TELEMETRY_LOG_IDENTIFIER","logTelemetryFailure","webex","message","_webex$logger","_webex$logger$error","logger","error","call","_unused","UnhandledExceptionTelemetry","eventTarget","_this","_classCallCheck2","_map","event","captureError","captureRejection","preLoginId","uuid","v4","addEventListener","errorListener","capture","rejectionListener","_createClass2","key","value","stop","flushPending","_this2","removeEventListener","clearFlushTimer","pendingEvents","submit","clear","resourceTarget","target","currentSrc","_get","undefined","src","href","rawResourceUrl","_ref","resourceUrl","sanitizeResourceUrl","resourceType","String","toUpperCase","kind","concat","name","column","colno","filename","removeUrlDetails","line","lineno","stack","_unused2","reason","stringifyReason","_unused3","details","_this3","_truncate","_ref2","_this$webex$config$ap","_this$webex$config","_this$webex$config2","_this$webex$config3","truncate","removeUrlDetailsFromText","fingerprint","createFingerprint","join","capturedAt","Date","getTime","existingEvent","get","isWithinDedupeWindow","occurrenceCount","delete","schemaVersion","eventId","common","appName","config","sdkType","appVersion","runtime","sdkVersion","version","addMetadata","set","flushTimer","safeSetTimeout","flush","_unused4","_this$webex$config4","_this$webex$config4$m","_this$webex$config4$m2","getMetadata","metrics","unhandledExceptionTelemetry","metadata","serializedMetadata","_stringify","metadataCaptureStatus","parsedMetadata","JSON","parse","_typeof2","_isArray","_unused5","_this4","now","nextFlushInMs","_nextFlushInMs","remainingWindowMs","Math","min","_this$webex$internal","_this$webex$internal$","_this5","submitClientMetrics","internal","_this$webex$internal2","_promise","resolve","tags","app_name","exception_kind","fields","captured_at","error_fingerprint","error_name","event_id","occurrence_count","eventPayload","canAuthorize","catch","_unused6","clearTimeout","activeTelemetry","startUnhandledExceptionTelemetry","_webex$config","_webex$config$metrics","_webex$config$metrics2","_activeTelemetry","shouldStart","enabled","window","_unused7"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable require-jsdoc, valid-jsdoc */\n\nimport {safeSetTimeout} from '@webex/common-timers';\nimport uuid from 'uuid';\n\nimport {\n createFingerprint,\n removeUrlDetails,\n removeUrlDetailsFromText,\n sanitizeResourceUrl,\n stringifyReason,\n truncate,\n} from './utils';\n\nexport const UNHANDLED_EXCEPTION_METRIC_NAME = 'JS_SDK_OBSERVED_CLIENT_UNHANDLED_EXCEPTION';\n\nconst DEDUPE_WINDOW_MS = 1_000;\nconst MAX_ERROR_MESSAGE_LENGTH = 4_096;\nconst MAX_ERROR_NAME_LENGTH = 256;\nconst MAX_METADATA_LENGTH = 32_000;\nconst MAX_STACK_LENGTH = 8_192;\n\nconst TELEMETRY_LOG_IDENTIFIER = 'Unhandled Exception Telemetry -->';\n\ntype ErrorDetails = {\n column?: number;\n filename?: string;\n kind: 'error' | 'unhandledrejection' | 'resource_error';\n line?: number;\n message?: string;\n name: string;\n /** Uppercase DOM tag name, such as SCRIPT, LINK, or IMG; RESOURCE when unavailable. */\n resourceType?: string;\n resourceUrl?: string;\n stack?: string;\n};\n\nexport type UnhandledExceptionEvent = {\n schemaVersion: 1;\n capturedAt: number;\n eventId: string;\n occurrenceCount: number;\n common: {\n appName: string;\n appVersion?: string;\n runtime: 'browser';\n sdkVersion?: string;\n };\n error: ErrorDetails & {fingerprint: string};\n metadata?: Record<string, unknown>;\n metadataCaptureStatus?: 'invalid_type' | 'provider_error' | 'too_large';\n};\n\ntype WebexForUnhandledExceptionTelemetry = {\n canAuthorize?: boolean;\n version?: string;\n config?: {\n appName?: string;\n appVersion?: string;\n sdkType?: string;\n metrics?: {\n unhandledExceptionTelemetry?: {\n enabled?: boolean;\n getMetadata?: () => Record<string, unknown> | undefined;\n };\n };\n };\n internal?: {\n metrics?: {\n submitClientMetrics?: (name: string, properties: object, preLoginId?: string) => unknown;\n };\n };\n logger?: {\n error?: (...args: unknown[]) => unknown;\n };\n};\n\nfunction logTelemetryFailure(webex: WebexForUnhandledExceptionTelemetry, message: string): void {\n try {\n webex.logger?.error?.(TELEMETRY_LOG_IDENTIFIER, message);\n } catch {\n // Logging must not turn a telemetry failure into an application failure.\n }\n}\n\n/**\n * SDK-owned browser exception reporter with a single in-memory deduplication window.\n */\nclass UnhandledExceptionTelemetry {\n private readonly pendingEvents = new Map<string, UnhandledExceptionEvent>();\n private readonly eventTarget: Window;\n private readonly errorListener = (event: ErrorEvent) => this.captureError(event);\n private readonly preLoginId: string;\n private readonly rejectionListener = (event: PromiseRejectionEvent) =>\n this.captureRejection(event);\n\n private readonly webex: WebexForUnhandledExceptionTelemetry;\n private flushTimer?: number | NodeJS.Timeout;\n\n /**\n * Registers browser listeners after the SDK is ready.\n * @param webex SDK instance used for configuration and submission.\n * @param eventTarget Browser window.\n */\n constructor(webex: WebexForUnhandledExceptionTelemetry, eventTarget: Window) {\n this.webex = webex;\n this.eventTarget = eventTarget;\n this.preLoginId = uuid.v4();\n eventTarget.addEventListener('error', this.errorListener, {capture: true});\n eventTarget.addEventListener('unhandledrejection', this.rejectionListener, {capture: true});\n }\n\n /**\n * Removes global listeners and either flushes or discards pending events.\n * @param flushPending Whether to submit pending telemetry before teardown.\n * @returns {void}\n */\n stop(flushPending: boolean): void {\n this.eventTarget.removeEventListener('error', this.errorListener, {capture: true});\n this.eventTarget.removeEventListener('unhandledrejection', this.rejectionListener, {\n capture: true,\n });\n this.clearFlushTimer();\n\n if (flushPending) {\n this.pendingEvents.forEach((event) => this.submit(event));\n }\n\n this.pendingEvents.clear();\n }\n\n private captureError(event: ErrorEvent): void {\n try {\n const resourceTarget = event.target;\n const currentSrc = resourceTarget ? Reflect.get(resourceTarget, 'currentSrc') : undefined;\n const src = resourceTarget ? Reflect.get(resourceTarget, 'src') : undefined;\n const href = resourceTarget ? Reflect.get(resourceTarget, 'href') : undefined;\n const rawResourceUrl =\n (typeof currentSrc === 'string' && currentSrc.length > 0 && currentSrc) ||\n (typeof src === 'string' && src.length > 0 && src) ||\n (typeof href === 'string' && href.length > 0 && href) ||\n undefined;\n\n if (rawResourceUrl) {\n const resourceUrl = sanitizeResourceUrl(rawResourceUrl);\n\n if (!resourceUrl) {\n return;\n }\n\n const resourceType = String(\n (resourceTarget && Reflect.get(resourceTarget, 'tagName')) ?? 'RESOURCE'\n ).toUpperCase();\n\n this.capture({\n kind: 'resource_error',\n message: `Failed to load ${resourceType} resource`,\n name: 'ResourceError',\n resourceType,\n resourceUrl,\n });\n\n return;\n }\n\n const {error} = event;\n let message = 'Unknown uncaught error';\n\n if (typeof error?.message === 'string') {\n message = error.message;\n } else if (typeof event.message === 'string') {\n message = event.message;\n }\n\n this.capture({\n column: event.colno,\n filename: removeUrlDetails(event.filename),\n kind: 'error',\n line: event.lineno,\n message,\n name: typeof error?.name === 'string' ? error.name : 'Error',\n stack: typeof error?.stack === 'string' ? error.stack : undefined,\n });\n } catch {\n logTelemetryFailure(this.webex, 'Failed to extract an uncaught error.');\n }\n }\n\n private captureRejection(event: PromiseRejectionEvent): void {\n try {\n const {reason} = event;\n\n this.capture({\n kind: 'unhandledrejection',\n message: typeof reason?.message === 'string' ? reason.message : stringifyReason(reason),\n name: typeof reason?.name === 'string' ? reason.name : 'UnhandledRejection',\n stack: typeof reason?.stack === 'string' ? reason.stack : undefined,\n });\n } catch {\n logTelemetryFailure(this.webex, 'Failed to extract an unhandled rejection.');\n }\n }\n\n private capture(details: ErrorDetails): void {\n try {\n const error = {\n ...details,\n name: truncate(removeUrlDetailsFromText(details.name), MAX_ERROR_NAME_LENGTH) ?? 'Error',\n message: truncate(removeUrlDetailsFromText(details.message), MAX_ERROR_MESSAGE_LENGTH),\n stack: truncate(removeUrlDetailsFromText(details.stack), MAX_STACK_LENGTH),\n };\n const fingerprint = createFingerprint(\n [\n error.kind,\n error.name,\n error.message,\n error.stack,\n error.filename,\n error.line,\n error.column,\n error.resourceUrl,\n ].join('|')\n );\n const capturedAt = new Date().getTime();\n const existingEvent = this.pendingEvents.get(fingerprint);\n\n if (existingEvent) {\n const isWithinDedupeWindow = capturedAt - existingEvent.capturedAt < DEDUPE_WINDOW_MS;\n\n if (isWithinDedupeWindow) {\n existingEvent.occurrenceCount += 1;\n\n return;\n }\n\n // A throttled timer can leave an expired event pending. Its completed window must be\n // submitted before this fingerprint is replaced with a new event and a new window.\n this.pendingEvents.delete(fingerprint);\n this.submit(existingEvent);\n }\n\n const event: UnhandledExceptionEvent = {\n schemaVersion: 1,\n capturedAt,\n eventId: uuid.v4(),\n occurrenceCount: 1,\n common: {\n appName: this.webex.config?.appName ?? this.webex.config?.sdkType ?? 'webex-js-sdk',\n appVersion: this.webex.config?.appVersion,\n runtime: 'browser',\n sdkVersion: this.webex.version,\n },\n error: {...error, fingerprint},\n };\n\n this.addMetadata(event);\n this.pendingEvents.set(fingerprint, event);\n\n if (this.flushTimer === undefined) {\n this.flushTimer = safeSetTimeout(() => this.flush(), DEDUPE_WINDOW_MS);\n }\n } catch {\n logTelemetryFailure(this.webex, 'Failed to capture an exception.');\n }\n }\n\n private addMetadata(event: UnhandledExceptionEvent): void {\n const getMetadata = this.webex.config?.metrics?.unhandledExceptionTelemetry?.getMetadata;\n\n if (!getMetadata) {\n return;\n }\n\n try {\n const metadata = getMetadata();\n\n if (metadata === undefined) {\n return;\n }\n\n const serializedMetadata = JSON.stringify(metadata);\n\n if (serializedMetadata === undefined || serializedMetadata.length > MAX_METADATA_LENGTH) {\n event.metadataCaptureStatus =\n serializedMetadata === undefined ? 'invalid_type' : 'too_large';\n\n return;\n }\n\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n if (\n parsedMetadata === null ||\n typeof parsedMetadata !== 'object' ||\n Array.isArray(parsedMetadata)\n ) {\n event.metadataCaptureStatus = 'invalid_type';\n\n return;\n }\n\n event.metadata = parsedMetadata;\n } catch {\n event.metadataCaptureStatus = 'provider_error';\n }\n }\n\n private flush(): void {\n const now = new Date().getTime();\n let nextFlushInMs: number | undefined;\n\n this.clearFlushTimer();\n this.pendingEvents.forEach((event, fingerprint) => {\n const remainingWindowMs = DEDUPE_WINDOW_MS - (now - event.capturedAt);\n\n if (remainingWindowMs <= 0) {\n this.pendingEvents.delete(fingerprint);\n this.submit(event);\n\n return;\n }\n\n nextFlushInMs = Math.min(nextFlushInMs ?? remainingWindowMs, remainingWindowMs);\n });\n\n if (nextFlushInMs !== undefined) {\n this.flushTimer = safeSetTimeout(() => this.flush(), nextFlushInMs);\n }\n }\n\n private submit(event: UnhandledExceptionEvent): void {\n const submitClientMetrics = this.webex.internal?.metrics?.submitClientMetrics;\n\n if (!submitClientMetrics) {\n logTelemetryFailure(this.webex, 'submitClientMetrics is unavailable.');\n\n return;\n }\n\n try {\n Promise.resolve(\n submitClientMetrics.call(\n this.webex.internal?.metrics,\n UNHANDLED_EXCEPTION_METRIC_NAME,\n {\n tags: {\n app_name: event.common.appName,\n exception_kind: event.error.kind,\n runtime: event.common.runtime,\n },\n fields: {\n captured_at: event.capturedAt,\n error_fingerprint: event.error.fingerprint,\n error_name: event.error.name,\n event_id: event.eventId,\n occurrence_count: event.occurrenceCount,\n },\n eventPayload: event,\n },\n this.webex.canAuthorize === true ? undefined : this.preLoginId\n )\n ).catch(() => {\n logTelemetryFailure(this.webex, 'Failed to submit exception telemetry.');\n });\n } catch {\n logTelemetryFailure(this.webex, 'Failed to submit exception telemetry.');\n }\n }\n\n private clearFlushTimer(): void {\n if (this.flushTimer !== undefined) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n }\n}\n\nlet activeTelemetry: UnhandledExceptionTelemetry | undefined;\n\n/**\n * Starts browser exception telemetry after SDK readiness.\n * @param webex Initialized SDK instance.\n * @returns {void}\n */\nexport function startUnhandledExceptionTelemetry(webex: WebexForUnhandledExceptionTelemetry): void {\n const shouldStart =\n webex.config?.metrics?.unhandledExceptionTelemetry?.enabled === true &&\n typeof window !== 'undefined' &&\n typeof window.addEventListener === 'function';\n\n activeTelemetry?.stop(shouldStart);\n activeTelemetry = undefined;\n\n if (!shouldStart) {\n return;\n }\n\n try {\n activeTelemetry = new UnhandledExceptionTelemetry(webex, window);\n } catch {\n logTelemetryFailure(webex, 'Failed to start exception telemetry.');\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAAA,aAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,MAAA,GAAAH,OAAA;AAOiB,SAAAI,QAAAC,CAAA,EAAAC,CAAA,QAAAC,CAAA,GAAAC,YAAA,CAAAH,CAAA,OAAAI,6BAAA,QAAAC,CAAA,GAAAD,6BAAA,CAAAJ,CAAA,GAAAC,CAAA,KAAAI,CAAA,GAAAA,CAAA,CAAAC,MAAA,WAAAL,CAAA,WAAAM,gCAAA,CAAAP,CAAA,EAAAC,CAAA,EAAAO,UAAA,OAAAN,CAAA,CAAAO,IAAA,CAAAC,KAAA,CAAAR,CAAA,EAAAG,CAAA,YAAAH,CAAA;AAAA,SAAAS,cAAAX,CAAA,aAAAC,CAAA,MAAAA,CAAA,GAAAW,SAAA,CAAAC,MAAA,EAAAZ,CAAA,UAAAC,CAAA,WAAAU,SAAA,CAAAX,CAAA,IAAAW,SAAA,CAAAX,CAAA,QAAAA,CAAA,OAAAF,OAAA,CAAAe,MAAA,CAAAZ,CAAA,OAAAa,OAAA,WAAAd,CAAA,QAAAe,gBAAA,CAAAC,OAAA,EAAAjB,CAAA,EAAAC,CAAA,EAAAC,CAAA,CAAAD,CAAA,SAAAiB,iCAAA,GAAAC,wBAAA,CAAAnB,CAAA,EAAAkB,iCAAA,CAAAhB,CAAA,KAAAH,OAAA,CAAAe,MAAA,CAAAZ,CAAA,GAAAa,OAAA,WAAAd,CAAA,IAAAmB,sBAAA,CAAApB,CAAA,EAAAC,CAAA,EAAAM,gCAAA,CAAAL,CAAA,EAAAD,CAAA,iBAAAD,CAAA,IAZjB;AAcO,IAAMqB,+BAA+B,GAAAC,OAAA,CAAAD,+BAAA,GAAG,4CAA4C;AAE3F,IAAME,gBAAgB,GAAG,IAAK;AAC9B,IAAMC,wBAAwB,GAAG,IAAK;AACtC,IAAMC,qBAAqB,GAAG,GAAG;AACjC,IAAMC,mBAAmB,GAAG,KAAM;AAClC,IAAMC,gBAAgB,GAAG,IAAK;AAE9B,IAAMC,wBAAwB,GAAG,mCAAmC;AAuDpE,SAASC,mBAAmBA,CAACC,KAA0C,EAAEC,OAAe,EAAQ;EAC9F,IAAI;IAAA,IAAAC,aAAA,EAAAC,mBAAA;IACF,CAAAD,aAAA,GAAAF,KAAK,CAACI,MAAM,cAAAF,aAAA,wBAAAC,mBAAA,GAAZD,aAAA,CAAcG,KAAK,cAAAF,mBAAA,uBAAnBA,mBAAA,CAAAG,IAAA,CAAAJ,aAAA,EAAsBJ,wBAAwB,EAAEG,OAAO,CAAC;EAC1D,CAAC,CAAC,OAAAM,OAAA,EAAM;IACN;EAAA;AAEJ;;AAEA;AACA;AACA;AAFA,IAGMC,2BAA2B;EAW/B;AACF;AACA;AACA;AACA;EACE,SAAAA,4BAAYR,KAA0C,EAAES,WAAmB,EAAE;IAAA,IAAAC,KAAA;IAAA,IAAAC,gBAAA,CAAAxB,OAAA,QAAAqB,2BAAA;IAAA,IAAAtB,gBAAA,CAAAC,OAAA,yBAf5C,IAAAyB,IAAA,CAAAzB,OAAA,CAAyC,CAAC;IAAA,IAAAD,gBAAA,CAAAC,OAAA;IAAA,IAAAD,gBAAA,CAAAC,OAAA,yBAE1C,UAAC0B,KAAiB;MAAA,OAAKH,KAAI,CAACI,YAAY,CAACD,KAAK,CAAC;IAAA;IAAA,IAAA3B,gBAAA,CAAAC,OAAA;IAAA,IAAAD,gBAAA,CAAAC,OAAA,6BAE3C,UAAC0B,KAA4B;MAAA,OAChEH,KAAI,CAACK,gBAAgB,CAACF,KAAK,CAAC;IAAA;IAAA,IAAA3B,gBAAA,CAAAC,OAAA;IAAA,IAAAD,gBAAA,CAAAC,OAAA;IAW5B,IAAI,CAACa,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACS,WAAW,GAAGA,WAAW;IAC9B,IAAI,CAACO,UAAU,GAAGC,aAAI,CAACC,EAAE,CAAC,CAAC;IAC3BT,WAAW,CAACU,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,aAAa,EAAE;MAACC,OAAO,EAAE;IAAI,CAAC,CAAC;IAC1EZ,WAAW,CAACU,gBAAgB,CAAC,oBAAoB,EAAE,IAAI,CAACG,iBAAiB,EAAE;MAACD,OAAO,EAAE;IAAI,CAAC,CAAC;EAC7F;;EAEA;AACF;AACA;AACA;AACA;EAJE,WAAAE,aAAA,CAAApC,OAAA,EAAAqB,2BAAA;IAAAgB,GAAA;IAAAC,KAAA,EAKA,SAAAC,IAAIA,CAACC,YAAqB,EAAQ;MAAA,IAAAC,MAAA;MAChC,IAAI,CAACnB,WAAW,CAACoB,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAACT,aAAa,EAAE;QAACC,OAAO,EAAE;MAAI,CAAC,CAAC;MAClF,IAAI,CAACZ,WAAW,CAACoB,mBAAmB,CAAC,oBAAoB,EAAE,IAAI,CAACP,iBAAiB,EAAE;QACjFD,OAAO,EAAE;MACX,CAAC,CAAC;MACF,IAAI,CAACS,eAAe,CAAC,CAAC;MAEtB,IAAIH,YAAY,EAAE;QAChB,IAAI,CAACI,aAAa,CAAC9C,OAAO,CAAC,UAAC4B,KAAK;UAAA,OAAKe,MAAI,CAACI,MAAM,CAACnB,KAAK,CAAC;QAAA,EAAC;MAC3D;MAEA,IAAI,CAACkB,aAAa,CAACE,KAAK,CAAC,CAAC;IAC5B;EAAC;IAAAT,GAAA;IAAAC,KAAA,EAED,SAAQX,YAAYA,CAACD,KAAiB,EAAQ;MAC5C,IAAI;QACF,IAAMqB,cAAc,GAAGrB,KAAK,CAACsB,MAAM;QACnC,IAAMC,UAAU,GAAGF,cAAc,GAAG,IAAAG,IAAA,CAAAlD,OAAA,EAAY+C,cAAc,EAAE,YAAY,CAAC,GAAGI,SAAS;QACzF,IAAMC,GAAG,GAAGL,cAAc,GAAG,IAAAG,IAAA,CAAAlD,OAAA,EAAY+C,cAAc,EAAE,KAAK,CAAC,GAAGI,SAAS;QAC3E,IAAME,IAAI,GAAGN,cAAc,GAAG,IAAAG,IAAA,CAAAlD,OAAA,EAAY+C,cAAc,EAAE,MAAM,CAAC,GAAGI,SAAS;QAC7E,IAAMG,cAAc,GACjB,OAAOL,UAAU,KAAK,QAAQ,IAAIA,UAAU,CAACrD,MAAM,GAAG,CAAC,IAAIqD,UAAU,IACrE,OAAOG,GAAG,KAAK,QAAQ,IAAIA,GAAG,CAACxD,MAAM,GAAG,CAAC,IAAIwD,GAAI,IACjD,OAAOC,IAAI,KAAK,QAAQ,IAAIA,IAAI,CAACzD,MAAM,GAAG,CAAC,IAAIyD,IAAK,IACrDF,SAAS;QAEX,IAAIG,cAAc,EAAE;UAAA,IAAAC,IAAA;UAClB,IAAMC,WAAW,GAAG,IAAAC,0BAAmB,EAACH,cAAc,CAAC;UAEvD,IAAI,CAACE,WAAW,EAAE;YAChB;UACF;UAEA,IAAME,YAAY,GAAGC,MAAM,EAAAJ,IAAA,GACxBR,cAAc,IAAI,IAAAG,IAAA,CAAAlD,OAAA,EAAY+C,cAAc,EAAE,SAAS,CAAC,cAAAQ,IAAA,cAAAA,IAAA,GAAK,UAChE,CAAC,CAACK,WAAW,CAAC,CAAC;UAEf,IAAI,CAAC1B,OAAO,CAAC;YACX2B,IAAI,EAAE,gBAAgB;YACtB/C,OAAO,oBAAAgD,MAAA,CAAoBJ,YAAY,cAAW;YAClDK,IAAI,EAAE,eAAe;YACrBL,YAAY,EAAZA,YAAY;YACZF,WAAW,EAAXA;UACF,CAAC,CAAC;UAEF;QACF;QAEA,IAAOtC,KAAK,GAAIQ,KAAK,CAAdR,KAAK;QACZ,IAAIJ,OAAO,GAAG,wBAAwB;QAEtC,IAAI,QAAOI,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEJ,OAAO,MAAK,QAAQ,EAAE;UACtCA,OAAO,GAAGI,KAAK,CAACJ,OAAO;QACzB,CAAC,MAAM,IAAI,OAAOY,KAAK,CAACZ,OAAO,KAAK,QAAQ,EAAE;UAC5CA,OAAO,GAAGY,KAAK,CAACZ,OAAO;QACzB;QAEA,IAAI,CAACoB,OAAO,CAAC;UACX8B,MAAM,EAAEtC,KAAK,CAACuC,KAAK;UACnBC,QAAQ,EAAE,IAAAC,uBAAgB,EAACzC,KAAK,CAACwC,QAAQ,CAAC;UAC1CL,IAAI,EAAE,OAAO;UACbO,IAAI,EAAE1C,KAAK,CAAC2C,MAAM;UAClBvD,OAAO,EAAPA,OAAO;UACPiD,IAAI,EAAE,QAAO7C,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAE6C,IAAI,MAAK,QAAQ,GAAG7C,KAAK,CAAC6C,IAAI,GAAG,OAAO;UAC5DO,KAAK,EAAE,QAAOpD,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEoD,KAAK,MAAK,QAAQ,GAAGpD,KAAK,CAACoD,KAAK,GAAGnB;QAC1D,CAAC,CAAC;MACJ,CAAC,CAAC,OAAAoB,QAAA,EAAM;QACN3D,mBAAmB,CAAC,IAAI,CAACC,KAAK,EAAE,sCAAsC,CAAC;MACzE;IACF;EAAC;IAAAwB,GAAA;IAAAC,KAAA,EAED,SAAQV,gBAAgBA,CAACF,KAA4B,EAAQ;MAC3D,IAAI;QACF,IAAO8C,MAAM,GAAI9C,KAAK,CAAf8C,MAAM;QAEb,IAAI,CAACtC,OAAO,CAAC;UACX2B,IAAI,EAAE,oBAAoB;UAC1B/C,OAAO,EAAE,QAAO0D,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAE1D,OAAO,MAAK,QAAQ,GAAG0D,MAAM,CAAC1D,OAAO,GAAG,IAAA2D,sBAAe,EAACD,MAAM,CAAC;UACvFT,IAAI,EAAE,QAAOS,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAET,IAAI,MAAK,QAAQ,GAAGS,MAAM,CAACT,IAAI,GAAG,oBAAoB;UAC3EO,KAAK,EAAE,QAAOE,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEF,KAAK,MAAK,QAAQ,GAAGE,MAAM,CAACF,KAAK,GAAGnB;QAC5D,CAAC,CAAC;MACJ,CAAC,CAAC,OAAAuB,QAAA,EAAM;QACN9D,mBAAmB,CAAC,IAAI,CAACC,KAAK,EAAE,2CAA2C,CAAC;MAC9E;IACF;EAAC;IAAAwB,GAAA;IAAAC,KAAA,EAED,SAAQJ,OAAOA,CAACyC,OAAqB,EAAQ;MAAA,IAAAC,MAAA;MAC3C,IAAI;QAAA,IAAAC,SAAA,EAAAC,KAAA,EAAAC,qBAAA,EAAAC,kBAAA,EAAAC,mBAAA,EAAAC,mBAAA;QACF,IAAMhE,KAAK,GAAAxB,aAAA,CAAAA,aAAA,KACNiF,OAAO;UACVZ,IAAI,GAAAc,SAAA,GAAE,IAAAM,eAAQ,EAAC,IAAAC,+BAAwB,EAACT,OAAO,CAACZ,IAAI,CAAC,EAAEvD,qBAAqB,CAAC,cAAAqE,SAAA,cAAAA,SAAA,GAAI,OAAO;UACxF/D,OAAO,EAAE,IAAAqE,eAAQ,EAAC,IAAAC,+BAAwB,EAACT,OAAO,CAAC7D,OAAO,CAAC,EAAEP,wBAAwB,CAAC;UACtF+D,KAAK,EAAE,IAAAa,eAAQ,EAAC,IAAAC,+BAAwB,EAACT,OAAO,CAACL,KAAK,CAAC,EAAE5D,gBAAgB;QAAC,EAC3E;QACD,IAAM2E,WAAW,GAAG,IAAAC,wBAAiB,EACnC,CACEpE,KAAK,CAAC2C,IAAI,EACV3C,KAAK,CAAC6C,IAAI,EACV7C,KAAK,CAACJ,OAAO,EACbI,KAAK,CAACoD,KAAK,EACXpD,KAAK,CAACgD,QAAQ,EACdhD,KAAK,CAACkD,IAAI,EACVlD,KAAK,CAAC8C,MAAM,EACZ9C,KAAK,CAACsC,WAAW,CAClB,CAAC+B,IAAI,CAAC,GAAG,CACZ,CAAC;QACD,IAAMC,UAAU,GAAG,IAAIC,IAAI,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC;QACvC,IAAMC,aAAa,GAAG,IAAI,CAAC/C,aAAa,CAACgD,GAAG,CAACP,WAAW,CAAC;QAEzD,IAAIM,aAAa,EAAE;UACjB,IAAME,oBAAoB,GAAGL,UAAU,GAAGG,aAAa,CAACH,UAAU,GAAGlF,gBAAgB;UAErF,IAAIuF,oBAAoB,EAAE;YACxBF,aAAa,CAACG,eAAe,IAAI,CAAC;YAElC;UACF;;UAEA;UACA;UACA,IAAI,CAAClD,aAAa,CAACmD,MAAM,CAACV,WAAW,CAAC;UACtC,IAAI,CAACxC,MAAM,CAAC8C,aAAa,CAAC;QAC5B;QAEA,IAAMjE,KAA8B,GAAG;UACrCsE,aAAa,EAAE,CAAC;UAChBR,UAAU,EAAVA,UAAU;UACVS,OAAO,EAAEnE,aAAI,CAACC,EAAE,CAAC,CAAC;UAClB+D,eAAe,EAAE,CAAC;UAClBI,MAAM,EAAE;YACNC,OAAO,GAAArB,KAAA,IAAAC,qBAAA,IAAAC,kBAAA,GAAE,IAAI,CAACnE,KAAK,CAACuF,MAAM,cAAApB,kBAAA,uBAAjBA,kBAAA,CAAmBmB,OAAO,cAAApB,qBAAA,cAAAA,qBAAA,IAAAE,mBAAA,GAAI,IAAI,CAACpE,KAAK,CAACuF,MAAM,cAAAnB,mBAAA,uBAAjBA,mBAAA,CAAmBoB,OAAO,cAAAvB,KAAA,cAAAA,KAAA,GAAI,cAAc;YACnFwB,UAAU,GAAApB,mBAAA,GAAE,IAAI,CAACrE,KAAK,CAACuF,MAAM,cAAAlB,mBAAA,uBAAjBA,mBAAA,CAAmBoB,UAAU;YACzCC,OAAO,EAAE,SAAS;YAClBC,UAAU,EAAE,IAAI,CAAC3F,KAAK,CAAC4F;UACzB,CAAC;UACDvF,KAAK,EAAAxB,aAAA,CAAAA,aAAA,KAAMwB,KAAK;YAAEmE,WAAW,EAAXA;UAAW;QAC/B,CAAC;QAED,IAAI,CAACqB,WAAW,CAAChF,KAAK,CAAC;QACvB,IAAI,CAACkB,aAAa,CAAC+D,GAAG,CAACtB,WAAW,EAAE3D,KAAK,CAAC;QAE1C,IAAI,IAAI,CAACkF,UAAU,KAAKzD,SAAS,EAAE;UACjC,IAAI,CAACyD,UAAU,GAAG,IAAAC,4BAAc,EAAC;YAAA,OAAMjC,MAAI,CAACkC,KAAK,CAAC,CAAC;UAAA,GAAExG,gBAAgB,CAAC;QACxE;MACF,CAAC,CAAC,OAAAyG,QAAA,EAAM;QACNnG,mBAAmB,CAAC,IAAI,CAACC,KAAK,EAAE,iCAAiC,CAAC;MACpE;IACF;EAAC;IAAAwB,GAAA;IAAAC,KAAA,EAED,SAAQoE,WAAWA,CAAChF,KAA8B,EAAQ;MAAA,IAAAsF,mBAAA,EAAAC,qBAAA,EAAAC,sBAAA;MACxD,IAAMC,WAAW,IAAAH,mBAAA,GAAG,IAAI,CAACnG,KAAK,CAACuF,MAAM,cAAAY,mBAAA,wBAAAC,qBAAA,GAAjBD,mBAAA,CAAmBI,OAAO,cAAAH,qBAAA,wBAAAC,sBAAA,GAA1BD,qBAAA,CAA4BI,2BAA2B,cAAAH,sBAAA,uBAAvDA,sBAAA,CAAyDC,WAAW;MAExF,IAAI,CAACA,WAAW,EAAE;QAChB;MACF;MAEA,IAAI;QACF,IAAMG,QAAQ,GAAGH,WAAW,CAAC,CAAC;QAE9B,IAAIG,QAAQ,KAAKnE,SAAS,EAAE;UAC1B;QACF;QAEA,IAAMoE,kBAAkB,GAAG,IAAAC,UAAA,CAAAxH,OAAA,EAAesH,QAAQ,CAAC;QAEnD,IAAIC,kBAAkB,KAAKpE,SAAS,IAAIoE,kBAAkB,CAAC3H,MAAM,GAAGa,mBAAmB,EAAE;UACvFiB,KAAK,CAAC+F,qBAAqB,GACzBF,kBAAkB,KAAKpE,SAAS,GAAG,cAAc,GAAG,WAAW;UAEjE;QACF;QAEA,IAAMuE,cAAc,GAAGC,IAAI,CAACC,KAAK,CAACL,kBAAkB,CAAC;QAErD,IACEG,cAAc,KAAK,IAAI,IACvB,IAAAG,QAAA,CAAA7H,OAAA,EAAO0H,cAAc,MAAK,QAAQ,IAClC,IAAAI,QAAA,CAAA9H,OAAA,EAAc0H,cAAc,CAAC,EAC7B;UACAhG,KAAK,CAAC+F,qBAAqB,GAAG,cAAc;UAE5C;QACF;QAEA/F,KAAK,CAAC4F,QAAQ,GAAGI,cAAc;MACjC,CAAC,CAAC,OAAAK,QAAA,EAAM;QACNrG,KAAK,CAAC+F,qBAAqB,GAAG,gBAAgB;MAChD;IACF;EAAC;IAAApF,GAAA;IAAAC,KAAA,EAED,SAAQwE,KAAKA,CAAA,EAAS;MAAA,IAAAkB,MAAA;MACpB,IAAMC,GAAG,GAAG,IAAIxC,IAAI,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC;MAChC,IAAIwC,aAAiC;MAErC,IAAI,CAACvF,eAAe,CAAC,CAAC;MACtB,IAAI,CAACC,aAAa,CAAC9C,OAAO,CAAC,UAAC4B,KAAK,EAAE2D,WAAW,EAAK;QAAA,IAAA8C,cAAA;QACjD,IAAMC,iBAAiB,GAAG9H,gBAAgB,IAAI2H,GAAG,GAAGvG,KAAK,CAAC8D,UAAU,CAAC;QAErE,IAAI4C,iBAAiB,IAAI,CAAC,EAAE;UAC1BJ,MAAI,CAACpF,aAAa,CAACmD,MAAM,CAACV,WAAW,CAAC;UACtC2C,MAAI,CAACnF,MAAM,CAACnB,KAAK,CAAC;UAElB;QACF;QAEAwG,aAAa,GAAGG,IAAI,CAACC,GAAG,EAAAH,cAAA,GAACD,aAAa,cAAAC,cAAA,cAAAA,cAAA,GAAIC,iBAAiB,EAAEA,iBAAiB,CAAC;MACjF,CAAC,CAAC;MAEF,IAAIF,aAAa,KAAK/E,SAAS,EAAE;QAC/B,IAAI,CAACyD,UAAU,GAAG,IAAAC,4BAAc,EAAC;UAAA,OAAMmB,MAAI,CAAClB,KAAK,CAAC,CAAC;QAAA,GAAEoB,aAAa,CAAC;MACrE;IACF;EAAC;IAAA7F,GAAA;IAAAC,KAAA,EAED,SAAQO,MAAMA,CAACnB,KAA8B,EAAQ;MAAA,IAAA6G,oBAAA;QAAAC,qBAAA;QAAAC,MAAA;MACnD,IAAMC,mBAAmB,IAAAH,oBAAA,GAAG,IAAI,CAAC1H,KAAK,CAAC8H,QAAQ,cAAAJ,oBAAA,wBAAAC,qBAAA,GAAnBD,oBAAA,CAAqBnB,OAAO,cAAAoB,qBAAA,uBAA5BA,qBAAA,CAA8BE,mBAAmB;MAE7E,IAAI,CAACA,mBAAmB,EAAE;QACxB9H,mBAAmB,CAAC,IAAI,CAACC,KAAK,EAAE,qCAAqC,CAAC;QAEtE;MACF;MAEA,IAAI;QAAA,IAAA+H,qBAAA;QACFC,QAAA,CAAA7I,OAAA,CAAQ8I,OAAO,CACbJ,mBAAmB,CAACvH,IAAI,EAAAyH,qBAAA,GACtB,IAAI,CAAC/H,KAAK,CAAC8H,QAAQ,cAAAC,qBAAA,uBAAnBA,qBAAA,CAAqBxB,OAAO,EAC5BhH,+BAA+B,EAC/B;UACE2I,IAAI,EAAE;YACJC,QAAQ,EAAEtH,KAAK,CAACwE,MAAM,CAACC,OAAO;YAC9B8C,cAAc,EAAEvH,KAAK,CAACR,KAAK,CAAC2C,IAAI;YAChC0C,OAAO,EAAE7E,KAAK,CAACwE,MAAM,CAACK;UACxB,CAAC;UACD2C,MAAM,EAAE;YACNC,WAAW,EAAEzH,KAAK,CAAC8D,UAAU;YAC7B4D,iBAAiB,EAAE1H,KAAK,CAACR,KAAK,CAACmE,WAAW;YAC1CgE,UAAU,EAAE3H,KAAK,CAACR,KAAK,CAAC6C,IAAI;YAC5BuF,QAAQ,EAAE5H,KAAK,CAACuE,OAAO;YACvBsD,gBAAgB,EAAE7H,KAAK,CAACoE;UAC1B,CAAC;UACD0D,YAAY,EAAE9H;QAChB,CAAC,EACD,IAAI,CAACb,KAAK,CAAC4I,YAAY,KAAK,IAAI,GAAGtG,SAAS,GAAG,IAAI,CAACtB,UACtD,CACF,CAAC,CAAC6H,KAAK,CAAC,YAAM;UACZ9I,mBAAmB,CAAC6H,MAAI,CAAC5H,KAAK,EAAE,uCAAuC,CAAC;QAC1E,CAAC,CAAC;MACJ,CAAC,CAAC,OAAA8I,QAAA,EAAM;QACN/I,mBAAmB,CAAC,IAAI,CAACC,KAAK,EAAE,uCAAuC,CAAC;MAC1E;IACF;EAAC;IAAAwB,GAAA;IAAAC,KAAA,EAED,SAAQK,eAAeA,CAAA,EAAS;MAC9B,IAAI,IAAI,CAACiE,UAAU,KAAKzD,SAAS,EAAE;QACjCyG,YAAY,CAAC,IAAI,CAAChD,UAAU,CAAC;QAC7B,IAAI,CAACA,UAAU,GAAGzD,SAAS;MAC7B;IACF;EAAC;AAAA;AAGH,IAAI0G,eAAwD;;AAE5D;AACA;AACA;AACA;AACA;AACO,SAASC,gCAAgCA,CAACjJ,KAA0C,EAAQ;EAAA,IAAAkJ,aAAA,EAAAC,qBAAA,EAAAC,sBAAA,EAAAC,gBAAA;EACjG,IAAMC,WAAW,GACf,EAAAJ,aAAA,GAAAlJ,KAAK,CAACuF,MAAM,cAAA2D,aAAA,wBAAAC,qBAAA,GAAZD,aAAA,CAAc3C,OAAO,cAAA4C,qBAAA,wBAAAC,sBAAA,GAArBD,qBAAA,CAAuB3C,2BAA2B,cAAA4C,sBAAA,uBAAlDA,sBAAA,CAAoDG,OAAO,MAAK,IAAI,IACpE,OAAOC,MAAM,KAAK,WAAW,IAC7B,OAAOA,MAAM,CAACrI,gBAAgB,KAAK,UAAU;EAE/C,CAAAkI,gBAAA,GAAAL,eAAe,cAAAK,gBAAA,uBAAfA,gBAAA,CAAiB3H,IAAI,CAAC4H,WAAW,CAAC;EAClCN,eAAe,GAAG1G,SAAS;EAE3B,IAAI,CAACgH,WAAW,EAAE;IAChB;EACF;EAEA,IAAI;IACFN,eAAe,GAAG,IAAIxI,2BAA2B,CAACR,KAAK,EAAEwJ,MAAM,CAAC;EAClE,CAAC,CAAC,OAAAC,QAAA,EAAM;IACN1J,mBAAmB,CAACC,KAAK,EAAE,sCAAsC,CAAC;EACpE;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
5
|
+
_Object$defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.createFingerprint = createFingerprint;
|
|
9
|
+
exports.removeUrlDetails = removeUrlDetails;
|
|
10
|
+
exports.removeUrlDetailsFromText = removeUrlDetailsFromText;
|
|
11
|
+
exports.sanitizeResourceUrl = sanitizeResourceUrl;
|
|
12
|
+
exports.stringifyReason = stringifyReason;
|
|
13
|
+
exports.truncate = truncate;
|
|
14
|
+
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
|
|
15
|
+
/* eslint-disable require-jsdoc */
|
|
16
|
+
|
|
17
|
+
var MAX_RESOURCE_URL_LENGTH = 2048;
|
|
18
|
+
function truncate(value, maxLength) {
|
|
19
|
+
return value === null || value === void 0 ? void 0 : value.slice(0, maxLength);
|
|
20
|
+
}
|
|
21
|
+
function removeUrlDetails(value) {
|
|
22
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
var withoutQueryOrFragment = value.split(/[?#]/, 1)[0];
|
|
26
|
+
|
|
27
|
+
// Strip URL userinfo from the authority. For example,
|
|
28
|
+
// https://userinfo@host/path becomes https://host/path.
|
|
29
|
+
return withoutQueryOrFragment.replace(/^((?:[a-z][a-z0-9+.-]*:)?\/\/)[^/?#]*@/i, '$1');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Keep HTTP(S) and relative resource URLs, remove credentials/query/fragment details, and cap them.
|
|
33
|
+
// For example, https://host/app.js?token=x becomes https://host/app.js, while
|
|
34
|
+
// data:image/svg+xml,<svg>...</svg> is rejected because its scheme is not HTTP(S).
|
|
35
|
+
function sanitizeResourceUrl(value) {
|
|
36
|
+
var _exec, _exec$;
|
|
37
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
var url = value.trim();
|
|
41
|
+
var scheme = (_exec = /^([a-z][a-z0-9+.-]*):/i.exec(url)) === null || _exec === void 0 ? void 0 : (_exec$ = _exec[1]) === null || _exec$ === void 0 ? void 0 : _exec$.toLowerCase();
|
|
42
|
+
if (scheme && scheme !== 'http' && scheme !== 'https') {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return truncate(removeUrlDetails(url), MAX_RESOURCE_URL_LENGTH);
|
|
46
|
+
}
|
|
47
|
+
function removeUrlDetailsFromText(value) {
|
|
48
|
+
// Redact non-HTTP(S) schemes and strip credentials, queries, and fragments from other URLs.
|
|
49
|
+
// Examples: data:text/plain,secret -> [redacted-url], https://host/api?token=x ->
|
|
50
|
+
// https://host/api, api/messages?token=x -> api/messages, and GET app.js?token=x -> GET app.js.
|
|
51
|
+
return value
|
|
52
|
+
// Handles root and dot-relative paths such as /api?token=x and ../app.js#fragment.
|
|
53
|
+
// These run before the scheme matcher so query values such as x:10 are not treated as URLs.
|
|
54
|
+
=== null || value
|
|
55
|
+
// Handles root and dot-relative paths such as /api?token=x and ../app.js#fragment.
|
|
56
|
+
// These run before the scheme matcher so query values such as x:10 are not treated as URLs.
|
|
57
|
+
=== void 0 ? void 0 : value
|
|
58
|
+
// Handles root and dot-relative paths such as /api?token=x and ../app.js#fragment.
|
|
59
|
+
// These run before the scheme matcher so query values such as x:10 are not treated as URLs.
|
|
60
|
+
.replace(/(^|[\s("'=[{])((?:\/|\.\.?\/)[^\s)"'\]}]+)/g, function (_, prefix, url) {
|
|
61
|
+
var _removeUrlDetails;
|
|
62
|
+
return "".concat(prefix).concat((_removeUrlDetails = removeUrlDetails(url)) !== null && _removeUrlDetails !== void 0 ? _removeUrlDetails : url);
|
|
63
|
+
}).replace(
|
|
64
|
+
// Handles bare paths with a slash or file extension, such as api/messages?x=1 or app.js#x.
|
|
65
|
+
/(^|[\s("'=[{])((?:(?:[a-z0-9._~%-]+\/)+(?:[a-z0-9._~%-]+)?|[a-z0-9._~%-]+\.[a-z0-9._~%-]+)[?#][^\s)"'\]}]+)/gi, function (_, prefix, url) {
|
|
66
|
+
var _removeUrlDetails2;
|
|
67
|
+
return "".concat(prefix).concat((_removeUrlDetails2 = removeUrlDetails(url)) !== null && _removeUrlDetails2 !== void 0 ? _removeUrlDetails2 : url);
|
|
68
|
+
}).replace(
|
|
69
|
+
// Handles extensionless single-segment paths after an HTTP method, such as GET api?token=x.
|
|
70
|
+
/\b(DELETE|GET|HEAD|OPTIONS|PATCH|POST|PUT)(\s+)([a-z0-9._~%-]+[?#][^\s)"'\]}]+)/gi, function (_, method, spacing, url) {
|
|
71
|
+
var _removeUrlDetails3;
|
|
72
|
+
return "".concat(method).concat(spacing).concat((_removeUrlDetails3 = removeUrlDetails(url)) !== null && _removeUrlDetails3 !== void 0 ? _removeUrlDetails3 : url);
|
|
73
|
+
}).replace(
|
|
74
|
+
// Handles URLs with a scheme, including assigned values such as url=https://host/path?x=1.
|
|
75
|
+
// HTTP(S) details are stripped; data:, blob:, and other schemes are fully redacted.
|
|
76
|
+
/(^|[\s("'=[{,;])(([a-z][a-z0-9+.-]*):[^\s)"'\]}]+)/gi, function (_, prefix, url, scheme) {
|
|
77
|
+
var _removeUrlDetails4;
|
|
78
|
+
return "".concat(prefix).concat(['http', 'https'].includes(scheme.toLowerCase()) ? (_removeUrlDetails4 = removeUrlDetails(url)) !== null && _removeUrlDetails4 !== void 0 ? _removeUrlDetails4 : url : '[redacted-url]');
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function createFingerprint(value) {
|
|
82
|
+
// DJB2-style hash: multiply by 33, add each UTF-16 code unit, and constrain the result to 32 bits.
|
|
83
|
+
// It provides a small stable deduplication key; it is not intended for cryptographic use.
|
|
84
|
+
var hash = 5381;
|
|
85
|
+
for (var index = 0; index < value.length; index += 1) {
|
|
86
|
+
hash = (hash * 33 + value.charCodeAt(index)) % 4294967296;
|
|
87
|
+
}
|
|
88
|
+
return hash.toString(16).padStart(8, '0');
|
|
89
|
+
}
|
|
90
|
+
function stringifyReason(reason) {
|
|
91
|
+
if (typeof reason === 'string') {
|
|
92
|
+
return reason;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
var _JSON$stringify;
|
|
96
|
+
return (_JSON$stringify = (0, _stringify.default)(reason)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : String(reason);
|
|
97
|
+
} catch (_unused) {
|
|
98
|
+
try {
|
|
99
|
+
return String(reason);
|
|
100
|
+
} catch (_unused2) {
|
|
101
|
+
return 'Unserializable rejection reason';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["MAX_RESOURCE_URL_LENGTH","truncate","value","maxLength","slice","removeUrlDetails","length","undefined","withoutQueryOrFragment","split","replace","sanitizeResourceUrl","_exec","_exec$","url","trim","scheme","exec","toLowerCase","removeUrlDetailsFromText","_","prefix","_removeUrlDetails","concat","_removeUrlDetails2","method","spacing","_removeUrlDetails3","_removeUrlDetails4","includes","createFingerprint","hash","index","charCodeAt","toString","padStart","stringifyReason","reason","_JSON$stringify","_stringify","default","String","_unused","_unused2"],"sources":["utils.ts"],"sourcesContent":["/* eslint-disable require-jsdoc */\n\nconst MAX_RESOURCE_URL_LENGTH = 2_048;\n\nexport function truncate(value: string | undefined, maxLength: number): string | undefined {\n return value?.slice(0, maxLength);\n}\n\nexport function removeUrlDetails(value: unknown): string | undefined {\n if (typeof value !== 'string' || value.length === 0) {\n return undefined;\n }\n\n const withoutQueryOrFragment = value.split(/[?#]/, 1)[0];\n\n // Strip URL userinfo from the authority. For example,\n // https://userinfo@host/path becomes https://host/path.\n return withoutQueryOrFragment.replace(/^((?:[a-z][a-z0-9+.-]*:)?\\/\\/)[^/?#]*@/i, '$1');\n}\n\n// Keep HTTP(S) and relative resource URLs, remove credentials/query/fragment details, and cap them.\n// For example, https://host/app.js?token=x becomes https://host/app.js, while\n// data:image/svg+xml,<svg>...</svg> is rejected because its scheme is not HTTP(S).\nexport function sanitizeResourceUrl(value: unknown): string | undefined {\n if (typeof value !== 'string' || value.length === 0) {\n return undefined;\n }\n\n const url = value.trim();\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(url)?.[1]?.toLowerCase();\n\n if (scheme && scheme !== 'http' && scheme !== 'https') {\n return undefined;\n }\n\n return truncate(removeUrlDetails(url), MAX_RESOURCE_URL_LENGTH);\n}\n\nexport function removeUrlDetailsFromText(value: string | undefined): string | undefined {\n // Redact non-HTTP(S) schemes and strip credentials, queries, and fragments from other URLs.\n // Examples: data:text/plain,secret -> [redacted-url], https://host/api?token=x ->\n // https://host/api, api/messages?token=x -> api/messages, and GET app.js?token=x -> GET app.js.\n return (\n value\n // Handles root and dot-relative paths such as /api?token=x and ../app.js#fragment.\n // These run before the scheme matcher so query values such as x:10 are not treated as URLs.\n ?.replace(\n /(^|[\\s(\"'=[{])((?:\\/|\\.\\.?\\/)[^\\s)\"'\\]}]+)/g,\n (_, prefix, url) => `${prefix}${removeUrlDetails(url) ?? url}`\n )\n .replace(\n // Handles bare paths with a slash or file extension, such as api/messages?x=1 or app.js#x.\n /(^|[\\s(\"'=[{])((?:(?:[a-z0-9._~%-]+\\/)+(?:[a-z0-9._~%-]+)?|[a-z0-9._~%-]+\\.[a-z0-9._~%-]+)[?#][^\\s)\"'\\]}]+)/gi,\n (_, prefix, url) => `${prefix}${removeUrlDetails(url) ?? url}`\n )\n .replace(\n // Handles extensionless single-segment paths after an HTTP method, such as GET api?token=x.\n /\\b(DELETE|GET|HEAD|OPTIONS|PATCH|POST|PUT)(\\s+)([a-z0-9._~%-]+[?#][^\\s)\"'\\]}]+)/gi,\n (_, method, spacing, url) => `${method}${spacing}${removeUrlDetails(url) ?? url}`\n )\n .replace(\n // Handles URLs with a scheme, including assigned values such as url=https://host/path?x=1.\n // HTTP(S) details are stripped; data:, blob:, and other schemes are fully redacted.\n /(^|[\\s(\"'=[{,;])(([a-z][a-z0-9+.-]*):[^\\s)\"'\\]}]+)/gi,\n (_, prefix, url, scheme) =>\n `${prefix}${\n ['http', 'https'].includes(scheme.toLowerCase())\n ? removeUrlDetails(url) ?? url\n : '[redacted-url]'\n }`\n )\n );\n}\n\nexport function createFingerprint(value: string): string {\n // DJB2-style hash: multiply by 33, add each UTF-16 code unit, and constrain the result to 32 bits.\n // It provides a small stable deduplication key; it is not intended for cryptographic use.\n let hash = 5381;\n\n for (let index = 0; index < value.length; index += 1) {\n hash = (hash * 33 + value.charCodeAt(index)) % 4_294_967_296;\n }\n\n return hash.toString(16).padStart(8, '0');\n}\n\nexport function stringifyReason(reason: unknown): string {\n if (typeof reason === 'string') {\n return reason;\n }\n\n try {\n return JSON.stringify(reason) ?? String(reason);\n } catch {\n try {\n return String(reason);\n } catch {\n return 'Unserializable rejection reason';\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@webex/test-helper-chai": "3.12.0-llmrefactor.2",
|
|
30
30
|
"@webex/test-helper-mocha": "3.12.0-llmrefactor.2",
|
|
31
31
|
"@webex/test-helper-mock-webex": "3.12.0-llmrefactor.1",
|
|
32
|
-
"@webex/test-helper-test-users": "3.12.0-llmrefactor.
|
|
32
|
+
"@webex/test-helper-test-users": "3.12.0-llmrefactor.0",
|
|
33
33
|
"eslint": "^8.24.0",
|
|
34
34
|
"prettier": "^2.7.1",
|
|
35
35
|
"sinon": "^9.2.4"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@webex/event-dictionary-ts": "^1.0.2220",
|
|
41
41
|
"@webex/test-helper-chai": "3.12.0-llmrefactor.2",
|
|
42
42
|
"@webex/test-helper-mock-webex": "3.12.0-llmrefactor.1",
|
|
43
|
-
"@webex/webex-core": "3.12.0-llmrefactor.
|
|
43
|
+
"@webex/webex-core": "3.12.0-llmrefactor.3",
|
|
44
44
|
"ip-anonymize": "^0.1.0",
|
|
45
45
|
"isbot": "5.2.1",
|
|
46
46
|
"lodash": "^4.17.21",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"test:style": "eslint ./src/**/*.*",
|
|
55
55
|
"test:unit": "webex-legacy-tools test --unit --runner mocha"
|
|
56
56
|
},
|
|
57
|
-
"version": "3.12.0-llmrefactor.
|
|
57
|
+
"version": "3.12.0-llmrefactor.3"
|
|
58
58
|
}
|
package/src/config.js
CHANGED
package/src/new-metrics.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {setMetricTimings} from './call-diagnostic/call-diagnostic-metrics.util';
|
|
|
32
32
|
import {generateCommonErrorMetadata} from './utils';
|
|
33
33
|
import {isAutomatedUser as detectAutomatedUser} from './automated-user';
|
|
34
34
|
import PrivacyAndSecurityPermissionEnricher from './privacy-and-security-permission-enricher';
|
|
35
|
+
import {startUnhandledExceptionTelemetry} from './unhandled-exception-telemetry';
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Metrics plugin to centralize all types of metrics.
|
|
@@ -115,6 +116,8 @@ class Metrics extends WebexPlugin {
|
|
|
115
116
|
shouldDelay: this.delaySubmitClientEvents,
|
|
116
117
|
overrides: this.delayedClientEventsOverrides,
|
|
117
118
|
});
|
|
119
|
+
// @ts-ignore
|
|
120
|
+
startUnhandledExceptionTelemetry(this.webex);
|
|
118
121
|
});
|
|
119
122
|
}
|
|
120
123
|
|