@dynatrace/react-native-plugin 2.327.2 → 2.331.1
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 +419 -164
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceConfigurationModule.kt +48 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +41 -8
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceReactPackage.kt +3 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRuntimeConfigurationStore.kt +14 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +103 -47
- package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +12 -4
- package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +15 -5
- package/files/default.config.js +7 -0
- package/files/plugin-runtime.gradle +7 -17
- package/files/plugin.gradle +1 -1
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/libs/react-navigation/ReactNavigation.js +53 -18
- package/ios/ConfigurationSubscriber.h +15 -0
- package/ios/DynatraceRNBridge.h +4 -0
- package/ios/DynatraceRNBridge.mm +125 -29
- package/lib/core/Dynatrace.js +8 -11
- package/lib/core/configuration/ConfigurationHandler.js +3 -0
- package/lib/next/Dynatrace.js +50 -33
- package/lib/next/DynatraceArgValidators.js +10 -0
- package/lib/next/DynatraceEventBus.js +35 -0
- package/lib/next/appstart/AppStartObserver.js +2 -3
- package/lib/next/configuration/INativeRuntimeConfiguration.js +7 -0
- package/lib/next/configuration/RuntimeConfigurationObserver.js +40 -0
- package/lib/next/events/EventBuilderUtil.js +7 -0
- package/lib/next/events/EventData.js +28 -0
- package/lib/next/events/EventPipeline.js +5 -11
- package/lib/next/events/ExceptionEventData.js +26 -0
- package/lib/next/events/HttpRequestEventData.js +174 -0
- package/lib/next/events/SessionPropertyEventData.js +22 -0
- package/lib/next/events/interface/IBaseEvent.js +2 -0
- package/lib/next/events/interface/IEventData.js +2 -0
- package/lib/next/events/interface/IExceptionEventData.js +2 -0
- package/lib/next/events/interface/IHttpRequestEventData.js +2 -0
- package/lib/next/events/interface/ISessionPropertyEventData.js +2 -0
- package/lib/next/events/modifier/BaseDataEventModifier.js +1 -3
- package/lib/next/events/modifier/EventModifierUtil.js +34 -41
- package/lib/next/events/modifier/ModifyEventValidation.js +117 -27
- package/lib/next/events/modifier/SendEventValidation.js +53 -22
- package/lib/next/events/modifier/StringLengthEventModifier.js +53 -0
- package/lib/next/events/spec/EventSpecContstants.js +9 -2
- package/package.json +11 -5
- package/public.js +9 -3
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Config.js +6 -2
- package/scripts/LineOffsetAnalyze.js +1 -4
- package/scripts/core/LineOffsetAnalyzeCall.js +39 -46
- package/src/lib/core/interface/NativeDynatraceBridge.ts +6 -2
- package/types.d.ts +408 -177
- package/lib/next/events/HttpRequestEventBuilder.js +0 -196
- package/lib/next/events/ViewInfoCreator.js +0 -27
- package/lib/next/events/modifier/EventLimitation.js +0 -69
- /package/lib/next/events/{IHttpRequestEventBuilder.js → interface/EventProperty.js} +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const SendEventValidation_1 = require("./modifier/SendEventValidation");
|
|
4
|
+
const EventModifierUtil_1 = require("./modifier/EventModifierUtil");
|
|
5
|
+
const EventBuilderUtil_1 = require("./EventBuilderUtil");
|
|
6
|
+
class EventData {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.rawEventProperties = {};
|
|
9
|
+
}
|
|
10
|
+
addEventProperty(key, value) {
|
|
11
|
+
this.rawEventProperties[key] = value;
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
withDuration(duration) {
|
|
15
|
+
this.duration = duration;
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
toJSON() {
|
|
19
|
+
const sanitizedEventProperties = SendEventValidation_1.SendEventValidation.modifyEvent(Object.assign(Object.assign({}, this.rawEventProperties), (0, EventBuilderUtil_1.includeIfDefined)("duration", this.duration)));
|
|
20
|
+
if (sanitizedEventProperties === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
(0, EventModifierUtil_1.flagEventProperties)(sanitizedEventProperties);
|
|
24
|
+
(0, EventModifierUtil_1.addIsApiReported)(sanitizedEventProperties);
|
|
25
|
+
return sanitizedEventProperties;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.default = EventData;
|
|
@@ -6,18 +6,21 @@ const ConsoleLogger_1 = require("../../core/logging/ConsoleLogger");
|
|
|
6
6
|
const BaseDataEventModifier_1 = require("./modifier/BaseDataEventModifier");
|
|
7
7
|
const ValueRestrictionModifier_1 = require("./modifier/ValueRestrictionModifier");
|
|
8
8
|
const ModifyEventValidation_1 = require("./modifier/ModifyEventValidation");
|
|
9
|
-
const ViewInfoCreator_1 = require("./ViewInfoCreator");
|
|
10
9
|
const EventSpecContstants_1 = require("./spec/EventSpecContstants");
|
|
10
|
+
const StringLengthEventModifier_1 = require("./modifier/StringLengthEventModifier");
|
|
11
11
|
class EventPipelineImpl {
|
|
12
12
|
constructor() {
|
|
13
13
|
this.customEventModifierChain = new ModifyEventValidation_1.ModifyEventValidation();
|
|
14
14
|
this.logger = new ConsoleLogger_1.ConsoleLogger('EventPipeline');
|
|
15
15
|
}
|
|
16
16
|
getEventModifierChain() {
|
|
17
|
+
const stringLengthEventModifier = new StringLengthEventModifier_1.StringLengthEventModifier();
|
|
17
18
|
return [
|
|
18
|
-
new BaseDataEventModifier_1.BaseDataEventModifier(
|
|
19
|
+
new BaseDataEventModifier_1.BaseDataEventModifier(),
|
|
20
|
+
stringLengthEventModifier,
|
|
19
21
|
this.customEventModifierChain,
|
|
20
22
|
ValueRestrictionModifier_1.ValueRestrictionModifier,
|
|
23
|
+
stringLengthEventModifier,
|
|
21
24
|
];
|
|
22
25
|
}
|
|
23
26
|
insertEvent(event) {
|
|
@@ -58,14 +61,5 @@ class EventPipelineImpl {
|
|
|
58
61
|
this.logger.debug('removeEventModifier()');
|
|
59
62
|
return this.customEventModifierChain.removeEventModifier(eventModifier);
|
|
60
63
|
}
|
|
61
|
-
generateViewData(name) {
|
|
62
|
-
this.logger.debug(`generateViewData(${name})`);
|
|
63
|
-
if (name != null) {
|
|
64
|
-
this.viewInfo = (0, ViewInfoCreator_1.createViewInfo)(name);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
releaseViewData() {
|
|
68
|
-
this.viewInfo = undefined;
|
|
69
|
-
}
|
|
70
64
|
}
|
|
71
65
|
exports.EventPipeline = new EventPipelineImpl();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const SendEventValidation_1 = require("./modifier/SendEventValidation");
|
|
4
|
+
const EventModifierUtil_1 = require("./modifier/EventModifierUtil");
|
|
5
|
+
const EventCreator_1 = require("./EventCreator");
|
|
6
|
+
class ExceptionEventData {
|
|
7
|
+
constructor(error) {
|
|
8
|
+
this.rawEventProperties = {};
|
|
9
|
+
this.error = error;
|
|
10
|
+
}
|
|
11
|
+
addEventProperty(key, value) {
|
|
12
|
+
this.rawEventProperties[key] = value;
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
toJSON() {
|
|
16
|
+
const sanitizedEventProperties = SendEventValidation_1.SendEventValidation.modifyEvent(Object.assign({}, this.rawEventProperties));
|
|
17
|
+
if (sanitizedEventProperties === null) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const exceptionEvent = Object.assign(Object.assign({}, (0, EventCreator_1.createErrorEvent)(this.error.name, this.error.message, this.error.stack)), sanitizedEventProperties);
|
|
21
|
+
(0, EventModifierUtil_1.flagEventProperties)(exceptionEvent);
|
|
22
|
+
(0, EventModifierUtil_1.addIsApiReported)(exceptionEvent);
|
|
23
|
+
return exceptionEvent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = ExceptionEventData;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ConsoleLogger_1 = require("../../core/logging/ConsoleLogger");
|
|
4
|
+
const TimestampProvider_1 = require("../provider/TimestampProvider");
|
|
5
|
+
const SendEventValidation_1 = require("./modifier/SendEventValidation");
|
|
6
|
+
const EventModifierUtil_1 = require("./modifier/EventModifierUtil");
|
|
7
|
+
const EventBuilderUtil_1 = require("./EventBuilderUtil");
|
|
8
|
+
const logger = new ConsoleLogger_1.ConsoleLogger('HttpRequestEventData');
|
|
9
|
+
class HttpRequestEventData {
|
|
10
|
+
constructor(url, requestMethod) {
|
|
11
|
+
this.url = url;
|
|
12
|
+
this.requestMethod = requestMethod;
|
|
13
|
+
this.duration = 0;
|
|
14
|
+
this.rawEventProperties = {};
|
|
15
|
+
this.hasDroppedProperties = false;
|
|
16
|
+
this.triedToOverwriteDuration = false;
|
|
17
|
+
this.requestMethod =
|
|
18
|
+
requestMethod.toUpperCase();
|
|
19
|
+
}
|
|
20
|
+
withDuration(duration) {
|
|
21
|
+
this.duration = duration;
|
|
22
|
+
this.triedToOverwriteDuration = true;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
withStatusCode(statusCode) {
|
|
26
|
+
this.statusCode = statusCode;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
withReasonPhrase(reasonPhrase) {
|
|
30
|
+
this.reasonPhrase = reasonPhrase;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
withError(error) {
|
|
34
|
+
this.error = error;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
withBytesSent(bytesSent) {
|
|
38
|
+
this.bytesSent = bytesSent;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
withBytesReceived(bytesReceived) {
|
|
42
|
+
this.bytesReceived = bytesReceived;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
withTraceparentHeader(traceparentHeader) {
|
|
46
|
+
this.traceparentHeader = traceparentHeader;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
addEventProperty(key, value) {
|
|
50
|
+
this.rawEventProperties[key] = value;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
toJSON() {
|
|
54
|
+
if (!this.hasValidMandatoryAttributes()) {
|
|
55
|
+
logger.debug('toJSON(): Dropped invalid event');
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const sanitizedDuration = this.sanitizeDuration();
|
|
59
|
+
const sanitizedStatusCode = this.sanitizeStatusCode();
|
|
60
|
+
const sanitizedBytesReceived = this.sanitizeBytesReceived();
|
|
61
|
+
const sanitizedBytesSent = this.sanitizeBytesSent();
|
|
62
|
+
const parsedTraceparentHeader = this.traceparentHeader &&
|
|
63
|
+
this.parseTraceparent(this.traceparentHeader);
|
|
64
|
+
const traceContextHint = !this.traceparentHeader
|
|
65
|
+
? "api_unused"
|
|
66
|
+
: parsedTraceparentHeader
|
|
67
|
+
? "api_set"
|
|
68
|
+
: "invalid";
|
|
69
|
+
const hasFailedRequest = this.isStatusCodeError() || !!this.error;
|
|
70
|
+
const sanitizedEventProperties = SendEventValidation_1.SendEventValidation.modifyEvent(this.rawEventProperties);
|
|
71
|
+
(0, EventModifierUtil_1.flagEventProperties)(sanitizedEventProperties);
|
|
72
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, sanitizedEventProperties), { ["url.full"]: this.url, ["network.protocol.name"]: 'http', ["http.request.method"]: this.requestMethod, ["request.trace_context_hint"]: traceContextHint, ["duration"]: sanitizedDuration, ["start_time"]: TimestampProvider_1.defaultTimestampProvider.getCurrentTimestamp() -
|
|
73
|
+
sanitizedDuration }), (this.triedToOverwriteDuration && {
|
|
74
|
+
["dt.support.api.overridden_fields"]: [
|
|
75
|
+
'duration',
|
|
76
|
+
],
|
|
77
|
+
})), (0, EventBuilderUtil_1.includeIfDefined)("http.response.status_code", sanitizedStatusCode)), (0, EventBuilderUtil_1.includeIfDefined)("http.response.reason_phrase", this.reasonPhrase)), (0, EventBuilderUtil_1.includeIfDefined)("request.bytes_sent", sanitizedBytesSent)), (0, EventBuilderUtil_1.includeIfDefined)("request.bytes_received", sanitizedBytesReceived)), { ["characteristics.has_request"]: true, ["characteristics.is_api_reported"]: true }), (0, EventBuilderUtil_1.includeIfTrue)("characteristics.has_failed_request", hasFailedRequest)), (0, EventBuilderUtil_1.includeIfTrue)("characteristics.has_error", hasFailedRequest)), (this.error !== undefined && Object.assign({ ["characteristics.has_exception"]: true, ["exception.type"]: this.error.name, ["exception.message"]: this.error.message }, (0, EventBuilderUtil_1.includeIfDefined)("exception.stack_trace", this.error.stack)))), (parsedTraceparentHeader && {
|
|
78
|
+
["trace.id"]: parsedTraceparentHeader.traceId,
|
|
79
|
+
["span.id"]: parsedTraceparentHeader.spanId,
|
|
80
|
+
})), (0, EventBuilderUtil_1.includeIfTrue)("dt.support.api.has_dropped_properties", this.hasDroppedProperties));
|
|
81
|
+
}
|
|
82
|
+
hasValidMandatoryAttributes() {
|
|
83
|
+
let isValid = true;
|
|
84
|
+
if (this.isInvalidUrl(this.url)) {
|
|
85
|
+
logger.debug(`hasValidMandatoryAttributes(): dropped event since given URL is malformed: ${this.url}`);
|
|
86
|
+
isValid = false;
|
|
87
|
+
}
|
|
88
|
+
if (!HttpRequestEventData.allowedRequestMethods.includes(this.requestMethod)) {
|
|
89
|
+
logger.debug(`hasValidMandatoryAttributes(): dropped event since given Request Method is invalid: ${this.requestMethod}`);
|
|
90
|
+
isValid = false;
|
|
91
|
+
}
|
|
92
|
+
return isValid;
|
|
93
|
+
}
|
|
94
|
+
isInvalidUrl(url) {
|
|
95
|
+
try {
|
|
96
|
+
if (!url.match(/^(https?):\/\/[^\s/$.?#-][^\s]*$/i)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
new URL(url);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
catch (_a) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
sanitizeStatusCode() {
|
|
107
|
+
if (this.statusCode !== undefined && this.statusCode < 0) {
|
|
108
|
+
logger.debug('HttpRequestEventData: dropping invalid Status Code');
|
|
109
|
+
this.hasDroppedProperties = true;
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
return this.statusCode;
|
|
113
|
+
}
|
|
114
|
+
sanitizeDuration() {
|
|
115
|
+
if (!Number.isFinite(this.duration) || this.duration < 0) {
|
|
116
|
+
logger.debug('HttpRequestEventData: overriding invalid Duration with 0');
|
|
117
|
+
this.hasDroppedProperties = true;
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
return this.duration;
|
|
121
|
+
}
|
|
122
|
+
sanitizeBytesSent() {
|
|
123
|
+
if (this.bytesSent && this.bytesSent < 0) {
|
|
124
|
+
logger.debug(`HttpRequestEventData: dropping invalid value for Bytes Sent: ${this.bytesSent}`);
|
|
125
|
+
this.hasDroppedProperties = true;
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
return this.bytesSent;
|
|
129
|
+
}
|
|
130
|
+
sanitizeBytesReceived() {
|
|
131
|
+
if (this.bytesReceived && this.bytesReceived < 0) {
|
|
132
|
+
logger.debug(`HttpRequestEventData: dropping invalid value for Bytes Received: ${this.bytesReceived}`);
|
|
133
|
+
this.hasDroppedProperties = true;
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
return this.bytesReceived;
|
|
137
|
+
}
|
|
138
|
+
isStatusCodeError() {
|
|
139
|
+
return (this.statusCode && 400 <= this.statusCode && this.statusCode <= 599);
|
|
140
|
+
}
|
|
141
|
+
parseTraceparent(header) {
|
|
142
|
+
const traceparentRegex = /^00-([0-9a-f]{32})-([0-9a-f]{16})-0[01]$/;
|
|
143
|
+
const match = header.match(traceparentRegex);
|
|
144
|
+
if (!match) {
|
|
145
|
+
logger.debug("The provided traceparent header does not match the format: '00-<trace-id-32-HEXDIG>-<parent-id-16-HEXDIG>-<trace-flags-2-HEXDIG>'");
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const [, traceId, spanId] = match;
|
|
149
|
+
if (this.allZeros(traceId)) {
|
|
150
|
+
logger.debug('Trace ID in traceparent header must not be all zeros');
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
if (this.allZeros(spanId)) {
|
|
154
|
+
logger.debug('Parent ID in traceparent header must not be all zeros');
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return { traceId, spanId };
|
|
158
|
+
}
|
|
159
|
+
allZeros(str) {
|
|
160
|
+
return /^0*$/.test(str);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.default = HttpRequestEventData;
|
|
164
|
+
HttpRequestEventData.allowedRequestMethods = [
|
|
165
|
+
'GET',
|
|
166
|
+
'HEAD',
|
|
167
|
+
'POST',
|
|
168
|
+
'PUT',
|
|
169
|
+
'DELETE',
|
|
170
|
+
'CONNECT',
|
|
171
|
+
'OPTIONS',
|
|
172
|
+
'TRACE',
|
|
173
|
+
'PATCH',
|
|
174
|
+
];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const SendEventValidation_1 = require("./modifier/SendEventValidation");
|
|
4
|
+
const EventModifierUtil_1 = require("./modifier/EventModifierUtil");
|
|
5
|
+
class SessionPropertyEventData {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.rawSessionProperties = {};
|
|
8
|
+
}
|
|
9
|
+
addSessionProperty(key, value) {
|
|
10
|
+
this.rawSessionProperties[key] = value;
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
toJSON() {
|
|
14
|
+
const event = SendEventValidation_1.SendSessionPropertyEventValidation.modifyEvent(this.rawSessionProperties);
|
|
15
|
+
if (event != null) {
|
|
16
|
+
event["characteristics.has_session_properties"] = true;
|
|
17
|
+
}
|
|
18
|
+
(0, EventModifierUtil_1.addIsApiReported)(event);
|
|
19
|
+
return event;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.default = SessionPropertyEventData;
|
|
@@ -5,8 +5,7 @@ const ConfigurationHandler_1 = require("../../../core/configuration/Configuratio
|
|
|
5
5
|
const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
|
|
6
6
|
const EventModifierUtil_1 = require("./EventModifierUtil");
|
|
7
7
|
class BaseDataEventModifier {
|
|
8
|
-
constructor(
|
|
9
|
-
this.viewInfo = viewInfo;
|
|
8
|
+
constructor() {
|
|
10
9
|
this.logger = new ConsoleLogger_1.ConsoleLogger('BaseDataEventModifier');
|
|
11
10
|
}
|
|
12
11
|
modifyEvent(event) {
|
|
@@ -14,7 +13,6 @@ class BaseDataEventModifier {
|
|
|
14
13
|
this.logger.debug(`modifyEvent(${JSON.stringify(event)}): Event is null!`);
|
|
15
14
|
return event;
|
|
16
15
|
}
|
|
17
|
-
Object.assign(event, this.viewInfo);
|
|
18
16
|
event["dt.rum.event.source.type"] = 'react_native';
|
|
19
17
|
const bundleName = ConfigurationHandler_1.ConfigurationHandler.getBundleName();
|
|
20
18
|
if (bundleName !== undefined) {
|
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isKeyCustomProperty = exports.isNotObject = exports.doesNotExceedKeySize = exports.restrictingValueSize = exports.isKeySyntaxAllowed = exports.getReactNativeVersion = exports.containEventPropertiesInArray = exports.addIsApiReported = exports.flagEventProperties = exports.containEventProperties = exports.containSessionProperties = exports.trimString = exports.isObject = void 0;
|
|
4
4
|
const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
|
|
5
|
-
const
|
|
5
|
+
const EventSpecContstants_1 = require("../spec/EventSpecContstants");
|
|
6
6
|
const logger = new ConsoleLogger_1.ConsoleLogger('EventModifierUtil');
|
|
7
|
-
const flattenAdditionalData = (obj, parent, res = {}) => {
|
|
8
|
-
for (const key in obj) {
|
|
9
|
-
const propName = parent != null ? parent + '.' + key : key;
|
|
10
|
-
const valueOfObject = obj[key];
|
|
11
|
-
if ((0, exports.isObject)(valueOfObject)) {
|
|
12
|
-
(0, exports.flattenAdditionalData)(valueOfObject, propName, res);
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
res[propName] = obj[key];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return res;
|
|
19
|
-
};
|
|
20
|
-
exports.flattenAdditionalData = flattenAdditionalData;
|
|
21
7
|
const isObject = (obj) => {
|
|
22
8
|
if (obj === null || typeof obj !== 'object') {
|
|
23
9
|
return false;
|
|
@@ -25,25 +11,17 @@ const isObject = (obj) => {
|
|
|
25
11
|
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
26
12
|
};
|
|
27
13
|
exports.isObject = isObject;
|
|
28
|
-
const trimString = (str, maxLength
|
|
14
|
+
const trimString = (key, str, maxLength) => {
|
|
29
15
|
const stringToTrim = str.toString();
|
|
30
16
|
if (stringToTrim.length <= maxLength) {
|
|
31
17
|
return stringToTrim;
|
|
32
18
|
}
|
|
33
19
|
else {
|
|
20
|
+
logger.debug(`trimString(): Limiting value of ${key} as maximum value length (${maxLength}) is reached!`);
|
|
34
21
|
return stringToTrim.substring(0, maxLength);
|
|
35
22
|
}
|
|
36
23
|
};
|
|
37
24
|
exports.trimString = trimString;
|
|
38
|
-
const trimStringValuesInObject = (jsonData) => {
|
|
39
|
-
for (const key in jsonData) {
|
|
40
|
-
if (Object.prototype.hasOwnProperty.call(jsonData, key)) {
|
|
41
|
-
jsonData[key] = trimStringValue(jsonData[key]);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return jsonData;
|
|
45
|
-
};
|
|
46
|
-
exports.trimStringValuesInObject = trimStringValuesInObject;
|
|
47
25
|
const containSessionProperties = (jsonData) => {
|
|
48
26
|
for (const key in jsonData) {
|
|
49
27
|
if (key.startsWith(`${"session_properties"}.`)) {
|
|
@@ -70,7 +48,7 @@ const flagEventProperties = (event) => {
|
|
|
70
48
|
};
|
|
71
49
|
exports.flagEventProperties = flagEventProperties;
|
|
72
50
|
const addIsApiReported = (event) => {
|
|
73
|
-
if (event
|
|
51
|
+
if (event != null) {
|
|
74
52
|
event["characteristics.is_api_reported"] = true;
|
|
75
53
|
}
|
|
76
54
|
};
|
|
@@ -101,22 +79,37 @@ const getReactNativeVersion = () => {
|
|
|
101
79
|
return undefined;
|
|
102
80
|
};
|
|
103
81
|
exports.getReactNativeVersion = getReactNativeVersion;
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
82
|
+
const isKeySyntaxAllowed = (entry) => {
|
|
83
|
+
const [key] = entry;
|
|
84
|
+
const rV = EventSpecContstants_1.KEY_NAME_REGEX.test(key);
|
|
85
|
+
if (!rV) {
|
|
86
|
+
logger.debug(`isKeySyntaxAllowed(): Filtering key ${key} as it doesnt fulfill character rules!`);
|
|
87
|
+
}
|
|
88
|
+
return rV;
|
|
110
89
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
90
|
+
exports.isKeySyntaxAllowed = isKeySyntaxAllowed;
|
|
91
|
+
const restrictingValueSize = (entry) => {
|
|
92
|
+
const [key, value] = entry;
|
|
93
|
+
if (typeof value === 'string' &&
|
|
94
|
+
value.length > EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH) {
|
|
95
|
+
logger.debug(`restrictingValueSize(): Limiting value of ${key} as maximum value length (${EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH}) is reached!`);
|
|
96
|
+
entry[1] = value.slice(0, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
|
|
114
97
|
}
|
|
115
|
-
|
|
116
|
-
|
|
98
|
+
};
|
|
99
|
+
exports.restrictingValueSize = restrictingValueSize;
|
|
100
|
+
const doesNotExceedKeySize = ([key]) => {
|
|
101
|
+
if (key.length <= EventSpecContstants_1.MAX_CUSTOM_EVENT_KEY_LENGTH) {
|
|
102
|
+
return true;
|
|
117
103
|
}
|
|
118
|
-
else
|
|
119
|
-
|
|
104
|
+
else {
|
|
105
|
+
logger.debug(`doesNotExceedKeySize(): Dropping key ${key} as maximum key length (${EventSpecContstants_1.MAX_CUSTOM_EVENT_KEY_LENGTH}) is reached!`);
|
|
106
|
+
return false;
|
|
120
107
|
}
|
|
121
|
-
return data;
|
|
122
108
|
};
|
|
109
|
+
exports.doesNotExceedKeySize = doesNotExceedKeySize;
|
|
110
|
+
const isNotObject = ([, val]) => typeof val !== 'object' || val === null;
|
|
111
|
+
exports.isNotObject = isNotObject;
|
|
112
|
+
const isKeyCustomProperty = (key) => key.startsWith("event_properties") ||
|
|
113
|
+
key.startsWith("session_properties");
|
|
114
|
+
exports.isKeyCustomProperty = isKeyCustomProperty;
|
|
115
|
+
const toVersionString = (v) => `${v.major}.${v.minor}.${v.patch}${v.prerelease ? `-${v.prerelease}` : ''}`;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ModifyEventValidation = void 0;
|
|
4
4
|
const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
|
|
5
5
|
const EventSpecContstants_1 = require("../spec/EventSpecContstants");
|
|
6
|
-
const EventLimitation_1 = require("./EventLimitation");
|
|
7
6
|
const EventModifierUtil_1 = require("./EventModifierUtil");
|
|
8
7
|
class ModifyEventValidation {
|
|
9
8
|
constructor() {
|
|
@@ -30,7 +29,7 @@ class ModifyEventValidation {
|
|
|
30
29
|
for (const modifier of this.customEventModifierChain) {
|
|
31
30
|
try {
|
|
32
31
|
const eventRv = modifier.modifyEvent(event);
|
|
33
|
-
if (eventRv
|
|
32
|
+
if (!eventRv) {
|
|
34
33
|
isDiscarded = true;
|
|
35
34
|
break;
|
|
36
35
|
}
|
|
@@ -53,29 +52,31 @@ class ModifyEventValidation {
|
|
|
53
52
|
}
|
|
54
53
|
return event;
|
|
55
54
|
}
|
|
56
|
-
|
|
55
|
+
isCustomPropertiesAllowed(key, hasSessionPropertyCharacteristics) {
|
|
57
56
|
if (hasSessionPropertyCharacteristics) {
|
|
58
57
|
if (key.startsWith(`${"event_properties"}.`)) {
|
|
59
58
|
this.logger.debug(`isPropertiesAllowed(): Filtering key ${key} as usage of event properties is not allowed!`);
|
|
60
|
-
return
|
|
59
|
+
return false;
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
else {
|
|
64
63
|
if (key.startsWith(`${"session_properties"}.`)) {
|
|
65
64
|
this.logger.debug(`isPropertiesAllowed(): Filtering key ${key} as usage of session properties is not allowed!`);
|
|
66
|
-
return
|
|
65
|
+
return false;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
|
-
return
|
|
68
|
+
return true;
|
|
70
69
|
}
|
|
71
|
-
isKeyNameForbidden(key) {
|
|
70
|
+
isKeyNameForbidden(key, isAdded = false) {
|
|
72
71
|
for (const namespace of EventSpecContstants_1.MODIFY_EVENT_WHITELIST_NAMESPACE) {
|
|
73
72
|
if (key.startsWith(`${namespace}.`)) {
|
|
74
73
|
return false;
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
if (
|
|
78
|
-
|
|
76
|
+
if (!isAdded) {
|
|
77
|
+
if (EventSpecContstants_1.MODIFY_EVENT_WHITELIST_FIELDS.includes(key)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
79
80
|
}
|
|
80
81
|
this.logger.debug(`isKeyNameForbidden(): Filtering key ${key} as this field is reserved and must not be overridden!`);
|
|
81
82
|
return true;
|
|
@@ -98,22 +99,16 @@ class ModifyEventValidation {
|
|
|
98
99
|
const restoredEntries = this.restoreRemovedEntries(Object.entries(originalEvent), userEnrichedEvent, overriddenKeys);
|
|
99
100
|
const validAndRestoredEntries = validEntries.concat(restoredEntries);
|
|
100
101
|
const { baseEntries, addedEntries } = this.determineAddedEntries(originalEvent, validAndRestoredEntries);
|
|
101
|
-
const
|
|
102
|
+
const limitedAddedEntries = this.validateAddedEntries(addedEntries);
|
|
102
103
|
if (originalEvent["characteristics.has_event_properties"] === undefined &&
|
|
103
|
-
(0, EventModifierUtil_1.containEventPropertiesInArray)(
|
|
104
|
-
|
|
104
|
+
(0, EventModifierUtil_1.containEventPropertiesInArray)(limitedAddedEntries)) {
|
|
105
|
+
limitedAddedEntries.push([
|
|
105
106
|
"characteristics.has_event_properties",
|
|
106
107
|
true,
|
|
107
108
|
]);
|
|
108
109
|
}
|
|
109
|
-
const finalEntries = baseEntries.concat(
|
|
110
|
-
const sizedEntries =
|
|
111
|
-
if (sizedEntries.length < userEnrichedEventEntries.length) {
|
|
112
|
-
sizedEntries.push([
|
|
113
|
-
"dt.support.api.has_dropped_custom_properties",
|
|
114
|
-
true,
|
|
115
|
-
]);
|
|
116
|
-
}
|
|
110
|
+
const finalEntries = baseEntries.concat(limitedAddedEntries);
|
|
111
|
+
const sizedEntries = this.enforcePropertyLimit(finalEntries);
|
|
117
112
|
if (Array.isArray(overriddenKeys) && overriddenKeys.length > 0) {
|
|
118
113
|
sizedEntries.push([
|
|
119
114
|
"dt.support.api.overridden_fields",
|
|
@@ -128,31 +123,68 @@ class ModifyEventValidation {
|
|
|
128
123
|
}
|
|
129
124
|
return Object.fromEntries(sizedEntries);
|
|
130
125
|
}
|
|
126
|
+
determineChangedContent(modifiedJSONEventEntries, originalJSONEvent) {
|
|
127
|
+
const changedEntries = [];
|
|
128
|
+
for (const [prop, value] of modifiedJSONEventEntries) {
|
|
129
|
+
const originalValue = originalJSONEvent[prop];
|
|
130
|
+
if (this.isModified(originalValue, value)) {
|
|
131
|
+
changedEntries.push([prop, value]);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return changedEntries;
|
|
136
|
+
}
|
|
131
137
|
determineValidEntries(userEnrichedEntries, originalJSONEvent, overriddenKeys) {
|
|
132
|
-
const
|
|
138
|
+
const validEntries = [];
|
|
139
|
+
let droppedCustomProperties = false;
|
|
140
|
+
let droppedProperties = false;
|
|
133
141
|
for (const [prop, value] of userEnrichedEntries) {
|
|
134
142
|
const originalValue = originalJSONEvent[prop];
|
|
135
143
|
if (!this.isModified(originalValue, value)) {
|
|
136
|
-
|
|
144
|
+
validEntries.push([prop, value]);
|
|
137
145
|
continue;
|
|
138
146
|
}
|
|
139
|
-
if (this.
|
|
147
|
+
if (!this.isCustomPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) {
|
|
148
|
+
droppedCustomProperties = true;
|
|
140
149
|
continue;
|
|
141
150
|
}
|
|
142
151
|
const isNewlyAdded = typeof originalValue === 'undefined';
|
|
143
|
-
const isForbiddenKey = this.isKeyNameForbidden(prop);
|
|
152
|
+
const isForbiddenKey = this.isKeyNameForbidden(prop, isNewlyAdded);
|
|
144
153
|
if (isForbiddenKey) {
|
|
145
154
|
if (!isNewlyAdded) {
|
|
146
|
-
|
|
155
|
+
validEntries.push([prop, originalValue]);
|
|
147
156
|
}
|
|
157
|
+
droppedProperties = true;
|
|
148
158
|
continue;
|
|
149
159
|
}
|
|
150
160
|
if (!isNewlyAdded && !overriddenKeys.includes(prop)) {
|
|
151
161
|
overriddenKeys.push(prop);
|
|
152
162
|
}
|
|
153
|
-
|
|
163
|
+
if (!isNewlyAdded &&
|
|
164
|
+
EventSpecContstants_1.MODIFY_EVENT_WHITELIST_STRING_FIELDS.includes(prop)) {
|
|
165
|
+
const maximumLength = Math.max(originalJSONEvent[prop].toString().length, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
|
|
166
|
+
validEntries.push([
|
|
167
|
+
prop,
|
|
168
|
+
(0, EventModifierUtil_1.trimString)(prop, value.toString(), maximumLength),
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
validEntries.push([prop, value]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (droppedCustomProperties) {
|
|
176
|
+
validEntries.push([
|
|
177
|
+
"dt.support.api.has_dropped_custom_properties",
|
|
178
|
+
true,
|
|
179
|
+
]);
|
|
154
180
|
}
|
|
155
|
-
|
|
181
|
+
if (droppedProperties) {
|
|
182
|
+
validEntries.push([
|
|
183
|
+
"dt.support.api.has_dropped_properties",
|
|
184
|
+
true,
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
return validEntries;
|
|
156
188
|
}
|
|
157
189
|
isModified(oldValue, newValue) {
|
|
158
190
|
if (Array.isArray(oldValue)) {
|
|
@@ -198,5 +230,63 @@ class ModifyEventValidation {
|
|
|
198
230
|
return entries;
|
|
199
231
|
}, resultEntries);
|
|
200
232
|
}
|
|
233
|
+
validateAddedEntries(addedEntries) {
|
|
234
|
+
const validEntries = [];
|
|
235
|
+
let droppedProperties = false;
|
|
236
|
+
let droppedCustomProperties = false;
|
|
237
|
+
for (const entry of addedEntries) {
|
|
238
|
+
if (!(0, EventModifierUtil_1.isNotObject)(entry) ||
|
|
239
|
+
!(0, EventModifierUtil_1.doesNotExceedKeySize)(entry) ||
|
|
240
|
+
!(0, EventModifierUtil_1.isKeySyntaxAllowed)(entry)) {
|
|
241
|
+
if ((0, EventModifierUtil_1.isKeyCustomProperty)(entry[0])) {
|
|
242
|
+
droppedCustomProperties = true;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
droppedProperties = true;
|
|
246
|
+
}
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
(0, EventModifierUtil_1.restrictingValueSize)(entry);
|
|
250
|
+
validEntries.push(entry);
|
|
251
|
+
}
|
|
252
|
+
if (droppedCustomProperties) {
|
|
253
|
+
validEntries.push([
|
|
254
|
+
"dt.support.api.has_dropped_custom_properties",
|
|
255
|
+
true,
|
|
256
|
+
]);
|
|
257
|
+
}
|
|
258
|
+
if (droppedProperties) {
|
|
259
|
+
validEntries.push([
|
|
260
|
+
"dt.support.api.has_dropped_properties",
|
|
261
|
+
true,
|
|
262
|
+
]);
|
|
263
|
+
}
|
|
264
|
+
return validEntries;
|
|
265
|
+
}
|
|
266
|
+
enforcePropertyLimit(entries) {
|
|
267
|
+
const result = [];
|
|
268
|
+
let propertyCount = 0;
|
|
269
|
+
let droppedCustomProperties = false;
|
|
270
|
+
entries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
271
|
+
for (const [key, value] of entries) {
|
|
272
|
+
if ((0, EventModifierUtil_1.isKeyCustomProperty)(key)) {
|
|
273
|
+
propertyCount++;
|
|
274
|
+
if (propertyCount > EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS) {
|
|
275
|
+
this.logger.debug(`enforcePropertyLimit(): Dropped ${key} because overall ` +
|
|
276
|
+
`property limit (${EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS}) is reached!`);
|
|
277
|
+
droppedCustomProperties = true;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
result.push([key, value]);
|
|
282
|
+
}
|
|
283
|
+
if (droppedCustomProperties) {
|
|
284
|
+
result.push([
|
|
285
|
+
"dt.support.api.has_dropped_custom_properties",
|
|
286
|
+
true,
|
|
287
|
+
]);
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
201
291
|
}
|
|
202
292
|
exports.ModifyEventValidation = ModifyEventValidation;
|