@dynatrace/react-native-plugin 2.327.1 → 2.329.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.
Files changed (53) hide show
  1. package/README.md +426 -169
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceConfigurationModule.kt +48 -0
  4. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +41 -8
  5. package/android/src/main/java/com/dynatrace/android/agent/DynatraceReactPackage.kt +3 -0
  6. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRuntimeConfigurationStore.kt +14 -0
  7. package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +103 -47
  8. package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +12 -4
  9. package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +15 -5
  10. package/files/default.config.js +7 -0
  11. package/files/plugin-runtime.gradle +7 -17
  12. package/files/plugin.gradle +1 -1
  13. package/instrumentation/DynatraceInstrumentation.js +1 -1
  14. package/instrumentation/libs/react-native/Touchables.js +9 -0
  15. package/instrumentation/libs/react-navigation/ReactNavigation.js +53 -18
  16. package/ios/ConfigurationSubscriber.h +15 -0
  17. package/ios/DynatraceRNBridge.h +4 -0
  18. package/ios/DynatraceRNBridge.mm +220 -33
  19. package/lib/core/Dynatrace.js +8 -11
  20. package/lib/core/configuration/ConfigurationHandler.js +3 -0
  21. package/lib/next/Dynatrace.js +14 -32
  22. package/lib/next/DynatraceEventBus.js +35 -0
  23. package/lib/next/appstart/AppStartObserver.js +12 -16
  24. package/lib/next/configuration/INativeRuntimeConfiguration.js +7 -0
  25. package/lib/next/configuration/RuntimeConfigurationObserver.js +40 -0
  26. package/lib/next/events/EventBuilderUtil.js +7 -0
  27. package/lib/next/events/EventData.js +28 -0
  28. package/lib/next/events/EventPipeline.js +5 -11
  29. package/lib/next/events/ExceptionEventData.js +26 -0
  30. package/lib/next/events/{HttpRequestEventBuilder.js → HttpRequestEventData.js} +28 -52
  31. package/lib/next/events/SessionPropertyEventData.js +22 -0
  32. package/lib/next/events/interface/IBaseEvent.js +2 -0
  33. package/lib/next/events/interface/IEventData.js +2 -0
  34. package/lib/next/events/interface/IExceptionEventData.js +2 -0
  35. package/lib/next/events/interface/IHttpRequestEventData.js +2 -0
  36. package/lib/next/events/interface/ISessionPropertyEventData.js +2 -0
  37. package/lib/next/events/modifier/BaseDataEventModifier.js +1 -3
  38. package/lib/next/events/modifier/EventModifierUtil.js +34 -41
  39. package/lib/next/events/modifier/ModifyEventValidation.js +118 -26
  40. package/lib/next/events/modifier/SendEventValidation.js +53 -22
  41. package/lib/next/events/modifier/StringLengthEventModifier.js +53 -0
  42. package/lib/next/events/spec/EventSpecContstants.js +9 -2
  43. package/package.json +8 -3
  44. package/public.js +9 -3
  45. package/react-native-dynatrace.podspec +1 -1
  46. package/scripts/Config.js +6 -2
  47. package/scripts/LineOffsetAnalyze.js +1 -4
  48. package/scripts/core/LineOffsetAnalyzeCall.js +39 -46
  49. package/src/lib/core/interface/NativeDynatraceBridge.ts +6 -2
  50. package/types.d.ts +388 -158
  51. package/lib/next/events/ViewInfoCreator.js +0 -27
  52. package/lib/next/events/modifier/EventLimitation.js +0 -69
  53. /package/lib/next/events/{IHttpRequestEventBuilder.js → interface/EventProperty.js} +0 -0
@@ -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() {
@@ -53,29 +52,31 @@ class ModifyEventValidation {
53
52
  }
54
53
  return event;
55
54
  }
56
- isPropertiesAllowed(key, hasSessionPropertyCharacteristics) {
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 true;
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 true;
65
+ return false;
67
66
  }
68
67
  }
69
- return false;
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 (EventSpecContstants_1.MODIFY_EVENT_WHITELIST_FIELDS.includes(key)) {
78
- return false;
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 limitedEntries = new EventLimitation_1.EventLimitation().limitEventEntries(addedEntries);
102
+ const limitedAddedEntries = this.validateAddedEntries(addedEntries);
102
103
  if (originalEvent["characteristics.has_event_properties"] === undefined &&
103
- (0, EventModifierUtil_1.containEventPropertiesInArray)(limitedEntries)) {
104
- limitedEntries.push([
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(limitedEntries);
110
- const sizedEntries = new EventLimitation_1.EventLimitation().limitEventProperties(finalEntries);
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,70 @@ 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 newEntries = [];
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
- newEntries.push([prop, value]);
144
+ validEntries.push([prop, value]);
137
145
  continue;
138
146
  }
139
- if (this.isPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) {
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
- newEntries.push([prop, originalValue]);
155
+ validEntries.push([prop, originalValue]);
156
+ }
157
+ else {
158
+ droppedProperties = true;
147
159
  }
148
160
  continue;
149
161
  }
150
162
  if (!isNewlyAdded && !overriddenKeys.includes(prop)) {
151
163
  overriddenKeys.push(prop);
152
164
  }
153
- newEntries.push([prop, value]);
165
+ if (!isNewlyAdded &&
166
+ EventSpecContstants_1.MODIFY_EVENT_WHITELIST_STRING_FIELDS.includes(prop)) {
167
+ const maximumLength = Math.max(originalJSONEvent[prop].toString().length, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
168
+ validEntries.push([
169
+ prop,
170
+ (0, EventModifierUtil_1.trimString)(prop, value.toString(), maximumLength),
171
+ ]);
172
+ }
173
+ else {
174
+ validEntries.push([prop, value]);
175
+ }
176
+ }
177
+ if (droppedCustomProperties) {
178
+ validEntries.push([
179
+ "dt.support.api.has_dropped_custom_properties",
180
+ true,
181
+ ]);
154
182
  }
155
- return newEntries;
183
+ if (droppedProperties) {
184
+ validEntries.push([
185
+ "dt.support.api.has_dropped_properties",
186
+ true,
187
+ ]);
188
+ }
189
+ return validEntries;
156
190
  }
157
191
  isModified(oldValue, newValue) {
158
192
  if (Array.isArray(oldValue)) {
@@ -198,5 +232,63 @@ class ModifyEventValidation {
198
232
  return entries;
199
233
  }, resultEntries);
200
234
  }
235
+ validateAddedEntries(addedEntries) {
236
+ const validEntries = [];
237
+ let droppedProperties = false;
238
+ let droppedCustomProperties = false;
239
+ for (const entry of addedEntries) {
240
+ if (!(0, EventModifierUtil_1.isNotObject)(entry) ||
241
+ !(0, EventModifierUtil_1.doesNotExceedKeySize)(entry) ||
242
+ !(0, EventModifierUtil_1.isKeySyntaxAllowed)(entry)) {
243
+ if ((0, EventModifierUtil_1.isKeyCustomProperty)(entry[0])) {
244
+ droppedCustomProperties = true;
245
+ }
246
+ else {
247
+ droppedProperties = true;
248
+ }
249
+ continue;
250
+ }
251
+ (0, EventModifierUtil_1.restrictingValueSize)(entry);
252
+ validEntries.push(entry);
253
+ }
254
+ if (droppedCustomProperties) {
255
+ validEntries.push([
256
+ "dt.support.api.has_dropped_custom_properties",
257
+ true,
258
+ ]);
259
+ }
260
+ if (droppedProperties) {
261
+ validEntries.push([
262
+ "dt.support.api.has_dropped_properties",
263
+ true,
264
+ ]);
265
+ }
266
+ return validEntries;
267
+ }
268
+ enforcePropertyLimit(entries) {
269
+ const result = [];
270
+ let propertyCount = 0;
271
+ let droppedCustomProperties = false;
272
+ entries.sort((a, b) => a[0].localeCompare(b[0]));
273
+ for (const [key, value] of entries) {
274
+ if ((0, EventModifierUtil_1.isKeyCustomProperty)(key)) {
275
+ propertyCount++;
276
+ if (propertyCount > EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS) {
277
+ this.logger.debug(`enforcePropertyLimit(): Dropped ${key} because overall ` +
278
+ `property limit (${EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS}) is reached!`);
279
+ droppedCustomProperties = true;
280
+ continue;
281
+ }
282
+ }
283
+ result.push([key, value]);
284
+ }
285
+ if (droppedCustomProperties) {
286
+ result.push([
287
+ "dt.support.api.has_dropped_custom_properties",
288
+ true,
289
+ ]);
290
+ }
291
+ return result;
292
+ }
201
293
  }
202
294
  exports.ModifyEventValidation = ModifyEventValidation;
@@ -5,13 +5,13 @@ const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
5
5
  const TimestampProvider_1 = require("../../provider/TimestampProvider");
6
6
  const EventTimestamp_1 = require("../EventTimestamp");
7
7
  const EventSpecContstants_1 = require("../spec/EventSpecContstants");
8
- const EventLimitation_1 = require("./EventLimitation");
8
+ const EventModifierUtil_1 = require("./EventModifierUtil");
9
9
  class SendEventValidationImpl {
10
10
  constructor(timestampProvider, namespaceWhitelist, fieldWhitelist, loggerName) {
11
11
  this.logger = new ConsoleLogger_1.ConsoleLogger(loggerName);
12
12
  this.timestampProvider = timestampProvider;
13
- this.fieldWhitelist = fieldWhitelist;
14
13
  this.namespaceWhitelist = namespaceWhitelist;
14
+ this.fieldWhitelist = fieldWhitelist;
15
15
  }
16
16
  modifyEvent(event) {
17
17
  this.logger.debug(`modifyEvent(${JSON.stringify(event)})`);
@@ -22,19 +22,10 @@ class SendEventValidationImpl {
22
22
  return Object.assign({}, new EventTimestamp_1.EventTimestamp(this.timestampProvider).getEventTimeInfo());
23
23
  }
24
24
  const timeNow = this.timestampProvider.getCurrentTimestamp();
25
- const eventCopy = Object.entries(event).slice();
26
- const filteredEvent = eventCopy.filter(this.isKeyNameAllowed, this);
27
- const limitedEntries = new EventLimitation_1.EventLimitation().limitEventEntries(filteredEvent);
28
- const sizedEntries = new EventLimitation_1.EventLimitation().limitEventProperties(limitedEntries);
29
- if (sizedEntries.length < eventCopy.length) {
30
- sizedEntries.push([
31
- "dt.support.api.has_dropped_custom_properties",
32
- true,
33
- ]);
34
- }
35
- this.sanitizeDuration(sizedEntries);
36
- this.applyOverriddenKeys(sizedEntries);
37
- const jsonObject = Object.fromEntries(sizedEntries);
25
+ const filteredEvent = this.checkEventEntries(Object.entries(event).slice());
26
+ this.sanitizeDuration(filteredEvent);
27
+ this.applyOverriddenKeys(filteredEvent);
28
+ const jsonObject = Object.fromEntries(filteredEvent);
38
29
  if (jsonObject["duration"] !== undefined) {
39
30
  jsonObject["start_time"] =
40
31
  timeNow - jsonObject["duration"];
@@ -47,7 +38,7 @@ class SendEventValidationImpl {
47
38
  }
48
39
  applyOverriddenKeys(eventEntries) {
49
40
  const overriddenKeys = [];
50
- for (const [key, value] of eventEntries) {
41
+ for (const [key] of eventEntries) {
51
42
  if (this.fieldWhitelist.includes(key)) {
52
43
  overriddenKeys.push(key);
53
44
  }
@@ -68,18 +59,58 @@ class SendEventValidationImpl {
68
59
  value < 0) {
69
60
  entry[1] = 0;
70
61
  event.push([
71
- "dt.support.api.has_dropped_custom_properties",
62
+ "dt.support.api.has_dropped_properties",
72
63
  true,
73
64
  ]);
65
+ break;
74
66
  }
75
- if (typeof value === 'number' && !isFinite(value)) {
76
- event.push([
77
- "dt.support.has_nfn_values",
78
- true,
79
- ]);
67
+ }
68
+ }
69
+ }
70
+ checkEventEntries(allEntries) {
71
+ const fieldEntries = allEntries.slice();
72
+ fieldEntries.sort((a, b) => a[0].localeCompare(b[0]));
73
+ const validEntries = [];
74
+ let droppedProperties = false;
75
+ let droppedCustomProperties = false;
76
+ let amountOfCustomProperties = 0;
77
+ fieldEntries.forEach((entry) => {
78
+ if (!this.isKeyNameAllowed(entry) ||
79
+ !(0, EventModifierUtil_1.isNotObject)(entry) ||
80
+ !(0, EventModifierUtil_1.doesNotExceedKeySize)(entry) ||
81
+ !(0, EventModifierUtil_1.isKeySyntaxAllowed)(entry)) {
82
+ if ((0, EventModifierUtil_1.isKeyCustomProperty)(entry[0])) {
83
+ droppedCustomProperties = true;
84
+ }
85
+ else {
86
+ droppedProperties = true;
80
87
  }
88
+ return;
81
89
  }
90
+ if ((0, EventModifierUtil_1.isKeyCustomProperty)(entry[0])) {
91
+ amountOfCustomProperties++;
92
+ if (amountOfCustomProperties > EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS) {
93
+ this.logger.debug(`limitEventProperties(): Dropped ${entry[0]} because overall property limit is reached!`);
94
+ droppedCustomProperties = true;
95
+ return;
96
+ }
97
+ }
98
+ (0, EventModifierUtil_1.restrictingValueSize)(entry);
99
+ validEntries.push(entry);
100
+ });
101
+ if (droppedCustomProperties) {
102
+ validEntries.push([
103
+ "dt.support.api.has_dropped_custom_properties",
104
+ true,
105
+ ]);
106
+ }
107
+ if (droppedProperties) {
108
+ validEntries.push([
109
+ "dt.support.api.has_dropped_properties",
110
+ true,
111
+ ]);
82
112
  }
113
+ return validEntries;
83
114
  }
84
115
  isKeyNameAllowed(entry) {
85
116
  const [key] = entry;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StringLengthEventModifier = void 0;
4
+ const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
5
+ const EventSpecContstants_1 = require("../spec/EventSpecContstants");
6
+ const EventModifierUtil_1 = require("./EventModifierUtil");
7
+ class StringLengthEventModifier {
8
+ constructor() {
9
+ this.logger = new ConsoleLogger_1.ConsoleLogger('StringLengthEventModifier');
10
+ }
11
+ modifyEvent(event) {
12
+ if (event == null) {
13
+ this.logger.debug(`modifyEvent(${JSON.stringify(event)}): Event is null!`);
14
+ return event;
15
+ }
16
+ if (event["characteristics.is_api_reported"] ===
17
+ true) {
18
+ this.trimStringValuesInObject(event);
19
+ }
20
+ else {
21
+ this.trimStringValuesInObject(event, EventSpecContstants_1.EVENT_WHITELIST_SIZE);
22
+ }
23
+ return event;
24
+ }
25
+ trimStringValuesInObject(jsonData, keyWhitelist = []) {
26
+ for (const key in jsonData) {
27
+ if (!keyWhitelist.includes(key) &&
28
+ Object.prototype.hasOwnProperty.call(jsonData, key)) {
29
+ jsonData[key] = this.trimStringValue(key, jsonData[key]);
30
+ }
31
+ }
32
+ return jsonData;
33
+ }
34
+ trimStringValuesInArray(key, arrayData) {
35
+ arrayData.forEach((value, index, array) => {
36
+ array[index] = this.trimStringValue(key, value);
37
+ });
38
+ return arrayData;
39
+ }
40
+ trimStringValue(key, data) {
41
+ if (typeof data === 'string') {
42
+ return (0, EventModifierUtil_1.trimString)(key, data, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
43
+ }
44
+ else if (Array.isArray(data)) {
45
+ return this.trimStringValuesInArray(key, data);
46
+ }
47
+ else if ((0, EventModifierUtil_1.isObject)(data)) {
48
+ return this.trimStringValuesInObject(data);
49
+ }
50
+ return data;
51
+ }
52
+ }
53
+ exports.StringLengthEventModifier = StringLengthEventModifier;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALL_APP_START_KEYS = exports.MODIFY_EVENT_WHITELIST_NAMESPACE = exports.MODIFY_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_FIELDS = exports.SEND_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_NAMESPACES = exports.SEND_EVENT_WHITELIST_NAMESPACES = exports.AllCharacteristicsKeys = exports.KEY_NAME_REGEX = exports.MAX_CUSTOM_EVENT_VALUE_LENGTH = exports.MAX_CUSTOM_EVENT_KEY_LENGTH = exports.MAX_CUSTOM_EVENT_FIELDS = void 0;
4
- const SPECIFICATION_VERSION = '0.22';
3
+ exports.ALL_APP_START_KEYS = exports.EVENT_WHITELIST_SIZE = exports.MODIFY_EVENT_WHITELIST_NAMESPACE = exports.MODIFY_EVENT_WHITELIST_STRING_FIELDS = exports.MODIFY_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_FIELDS = exports.SEND_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_NAMESPACES = exports.SEND_EVENT_WHITELIST_NAMESPACES = exports.AllCharacteristicsKeys = exports.KEY_NAME_REGEX = exports.MAX_CUSTOM_EVENT_VALUE_LENGTH = exports.MAX_CUSTOM_EVENT_KEY_LENGTH = exports.MAX_CUSTOM_EVENT_FIELDS = void 0;
4
+ const SPECIFICATION_VERSION = '0.23';
5
5
  exports.MAX_CUSTOM_EVENT_FIELDS = 50;
6
6
  exports.MAX_CUSTOM_EVENT_KEY_LENGTH = 100;
7
7
  exports.MAX_CUSTOM_EVENT_VALUE_LENGTH = 5000;
@@ -43,10 +43,17 @@ exports.MODIFY_EVENT_WHITELIST_FIELDS = [
43
43
  "exception.stack_trace",
44
44
  "url.full",
45
45
  ];
46
+ exports.MODIFY_EVENT_WHITELIST_STRING_FIELDS = [
47
+ "exception.stack_trace",
48
+ "url.full",
49
+ ];
46
50
  exports.MODIFY_EVENT_WHITELIST_NAMESPACE = [
47
51
  "session_properties",
48
52
  "event_properties",
49
53
  ];
54
+ exports.EVENT_WHITELIST_SIZE = [
55
+ "exception.stack_trace",
56
+ ];
50
57
  const appStartKeyMap = {
51
58
  ["app_start.react_native.content_appeared"]: null,
52
59
  ["app_start.react_native.download.end_time"]: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynatrace/react-native-plugin",
3
- "version": "2.327.1",
3
+ "version": "2.329.1",
4
4
  "description": "This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.",
5
5
  "main": "index.js",
6
6
  "types": "types.d.ts",
@@ -26,8 +26,9 @@
26
26
  "test": "jest --runInBand",
27
27
  "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
28
28
  "test:local": "npm run lint && node runner.js test",
29
+ "test:examples": "node tests/jsdoc_examples/RunJestTest.js",
29
30
  "tsc:local": "tsc -p tsconfig.local.json",
30
- "tsc:types": "tsc -p tsconfig.types.json && rollup -c rollup.config.types.js",
31
+ "tsc:types": "tsc -p tsconfig.types.json && rollup -c rollup.config.types.mjs",
31
32
  "tsc": "tsc",
32
33
  "tsc:prod": "tsc -p tsconfig.release.json",
33
34
  "lint": "eslint --cache src/**/*.ts --ignore-pattern .gitignore",
@@ -47,7 +48,7 @@
47
48
  "author": "Dynatrace",
48
49
  "license": "SEE LICENSE IN LICENSE.md",
49
50
  "dependencies": {
50
- "@babel/runtime": "^7.28.4",
51
+ "@babel/runtime": "^7.28.6",
51
52
  "jscodeshift": "^17.3.0",
52
53
  "plist": "^3.1.0",
53
54
  "proxy-polyfill": "^0.3.2",
@@ -76,6 +77,8 @@
76
77
  "@babel/preset-env": "^7.27.2",
77
78
  "@babel/preset-react": "^7.27.1",
78
79
  "@react-native/babel-preset": "^0.80.1",
80
+ "@react-navigation/core": "^7.13.0",
81
+ "@react-navigation/drawer": "^7.7.2",
79
82
  "@testing-library/react-native": "^13.2.0",
80
83
  "@types/jest": "^30.0.0",
81
84
  "@types/jscodeshift": "^17.3.0",
@@ -157,7 +160,9 @@
157
160
  "lib/metro/*.js",
158
161
  "lib/next/*.js",
159
162
  "lib/next/appstart/*.js",
163
+ "lib/next/configuration/*.js",
160
164
  "lib/next/events/*.js",
165
+ "lib/next/events/interface/*.js",
161
166
  "lib/next/events/modifier/*.js",
162
167
  "lib/next/events/spec/*.js",
163
168
  "lib/next/provider/*.js",
package/public.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpRequestEventBuilder = exports.DynatraceWebRequestTiming = exports.UserPrivacyOptions = exports.LogLevel = exports.Platform = exports.ConfigurationBuilder = exports.ManualStartupConfiguration = exports.DataCollectionLevel = exports.Dynatrace = void 0;
3
+ exports.ExceptionEventData = exports.SessionPropertyEventData = exports.EventData = exports.HttpRequestEventData = exports.DynatraceWebRequestTiming = exports.UserPrivacyOptions = exports.LogLevel = exports.Platform = exports.ConfigurationBuilder = exports.ManualStartupConfiguration = exports.DataCollectionLevel = exports.Dynatrace = void 0;
4
4
  var Dynatrace_1 = require("./lib/core/Dynatrace");
5
5
  Object.defineProperty(exports, "Dynatrace", { enumerable: true, get: function () { return Dynatrace_1.Dynatrace; } });
6
6
  var DataCollectionLevel_1 = require("./lib/core/model/DataCollectionLevel");
@@ -17,6 +17,12 @@ var UserPrivacyOptions_1 = require("./lib/core/UserPrivacyOptions");
17
17
  Object.defineProperty(exports, "UserPrivacyOptions", { enumerable: true, get: function () { return UserPrivacyOptions_1.UserPrivacyOptions; } });
18
18
  var DynatraceWebRequestTiming_1 = require("./lib/core/DynatraceWebRequestTiming");
19
19
  Object.defineProperty(exports, "DynatraceWebRequestTiming", { enumerable: true, get: function () { return DynatraceWebRequestTiming_1.DynatraceWebRequestTiming; } });
20
- var HttpRequestEventBuilder_1 = require("./lib/next/events/HttpRequestEventBuilder");
21
- Object.defineProperty(exports, "HttpRequestEventBuilder", { enumerable: true, get: function () { return HttpRequestEventBuilder_1.default; } });
20
+ var HttpRequestEventData_1 = require("./lib/next/events/HttpRequestEventData");
21
+ Object.defineProperty(exports, "HttpRequestEventData", { enumerable: true, get: function () { return HttpRequestEventData_1.default; } });
22
+ var EventData_1 = require("./lib/next/events/EventData");
23
+ Object.defineProperty(exports, "EventData", { enumerable: true, get: function () { return EventData_1.default; } });
24
+ var SessionPropertyEventData_1 = require("./lib/next/events/SessionPropertyEventData");
25
+ Object.defineProperty(exports, "SessionPropertyEventData", { enumerable: true, get: function () { return SessionPropertyEventData_1.default; } });
26
+ var ExceptionEventData_1 = require("./lib/next/events/ExceptionEventData");
27
+ Object.defineProperty(exports, "ExceptionEventData", { enumerable: true, get: function () { return ExceptionEventData_1.default; } });
22
28
  require("./react-augmentation");
@@ -111,7 +111,7 @@ Pod::Spec.new do |s|
111
111
  #
112
112
 
113
113
  s.dependency "React"
114
- s.dependency 'Dynatrace', '~> 8.327.1.1020'
114
+ s.dependency 'Dynatrace', '~> 8.329.1.1017'
115
115
 
116
116
  # Allows for better compatibility for older and newer versions
117
117
  if defined?(install_modules_dependencies)
package/scripts/Config.js CHANGED
@@ -31,8 +31,12 @@ exports.defaultConfig = {
31
31
  instrument: (filename) => true,
32
32
  actionNamePrivacy: false,
33
33
  },
34
- custom: {
35
- reactnavigation: false,
34
+ navigation: {
35
+ enabled: true,
36
+ },
37
+ sourcemap: {
38
+ enabled: true,
39
+ androidSourcemapLocation: 'app/build/generated/sourcemaps/react/release/index.android.bundle.map',
36
40
  },
37
41
  },
38
42
  };
@@ -14,13 +14,10 @@ module.exports = (() => {
14
14
  }
15
15
  return acc;
16
16
  }, {});
17
- const isProd = parsedArgs.env === 'prod';
18
17
  const options = {
19
- isProd,
20
18
  projectRoot: parsedArgs.projectRoot || PathsConstants_1.default.getApplicationPath(),
21
19
  buildPath: parsedArgs.buildPath || PathsConstants_1.default.getBuildPath(),
22
- androidSourcemapPath: parsedArgs.androidSourcemapPath || '',
23
- iosSourcemapPath: parsedArgs.iosSourcemapPath || '',
20
+ sourcemapPath: parsedArgs.sourcemapPath,
24
21
  appBundleInfo: Object.assign(Object.assign({}, (0, GetValuesFromPackage_1.getHostAppBundleInfo)(PathsConstants_1.default.getPackageJsonFile())), { pluginVersion: (_b = (_a = (0, GetValuesFromPackage_1.getHostAppBundleInfo)(PathsConstants_1.default.getInternalPackageJsonFile(), true)) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : '0' }),
25
22
  };
26
23
  const analyzer = new LineOffsetAnalyzeCall_1.LineOffsetAnalyzer(options);
@@ -17,6 +17,10 @@ const Logger_1 = require("../Logger");
17
17
  const InstrumentUtil_1 = require("../util/InstrumentUtil");
18
18
  const FileOperationHelper_1 = require("../../scripts/FileOperationHelper");
19
19
  const ReactOptions_1 = require("../util/ReactOptions");
20
+ const config = require("../../scripts/Config");
21
+ const CustomArgumentUtil_1 = require("../../scripts/util/CustomArgumentUtil");
22
+ const PathsConstants_1 = require("../../scripts/PathsConstants");
23
+ const customArguments = (0, CustomArgumentUtil_1.readCustomArguments)();
20
24
  class LineOffsetAnalyzer {
21
25
  constructor(options) {
22
26
  this.rootDir = (0, path_1.resolve)(options.projectRoot);
@@ -24,11 +28,10 @@ class LineOffsetAnalyzer {
24
28
  this.outputFile = (0, path_1.resolve)(this.instrumentedDir, 'line-offsets.json');
25
29
  this.logFile = (0, path_1.resolve)(this.instrumentedDir, 'debug.log');
26
30
  this.appBundleInfo = options.appBundleInfo;
27
- this.isProd = options.isProd;
28
- this.androidSourcemapPath = options.androidSourcemapPath;
29
- this.iosSourcemapPath = options.iosSourcemapPath;
31
+ this.sourcemapPath = options.sourcemapPath;
30
32
  }
31
33
  run() {
34
+ var _a;
32
35
  return __awaiter(this, void 0, void 0, function* () {
33
36
  try {
34
37
  const buildExists = yield FileOperationHelper_1.default.checkIfFileExists(this.instrumentedDir);
@@ -76,23 +79,30 @@ class LineOffsetAnalyzer {
76
79
  };
77
80
  yield fs.writeFile(this.outputFile, JSON.stringify(finalOutput, null, 2));
78
81
  yield this.log(`✅ Line offsets written to ${this.outputFile}`, true);
79
- if (this.isProd) {
80
- yield this.log('🔧 Patching source map with all offset data...');
81
- const loadedMap = yield this.loadSourceMap();
82
- if (loadedMap) {
83
- const { map, path: originalMapPath } = loadedMap;
84
- map.x_dynatrace_offset = mappings;
85
- const backupPath = originalMapPath + '.bak';
86
- const serilalisedPath = originalMapPath + '.serialised';
87
- yield fs.copyFile(originalMapPath, backupPath);
88
- yield this.log(`💾 Backup created: ${backupPath}`);
89
- yield fs.writeFile(originalMapPath, JSON.stringify(map));
90
- yield fs.writeFile(serilalisedPath, JSON.stringify(map, null, 2));
91
- yield this.log(`📝 Patched source map written to: ${originalMapPath}`);
92
- }
93
- else {
94
- yield this.log('⚠️ No source map found skipping patching step');
95
- }
82
+ let reactOptions;
83
+ if (customArguments.isCustomConfigurationPathSet()) {
84
+ reactOptions = config.readConfig((0, path_1.join)(PathsConstants_1.default.getApplicationPath(), customArguments.getCustomConfigurationPath()));
85
+ }
86
+ else {
87
+ reactOptions = config.readConfig((0, path_1.join)(PathsConstants_1.default.getConfigFilePath()));
88
+ }
89
+ if (!this.sourcemapPath && !reactOptions.react.sourcemap.enabled) {
90
+ const message = 'ℹ️ Automatic sourcemap patching disabled. Skipping sourcemap patching.';
91
+ yield this.log(message);
92
+ console.info(message);
93
+ return;
94
+ }
95
+ const loadedMap = yield this.loadSourceMap((_a = this.sourcemapPath) !== null && _a !== void 0 ? _a : reactOptions.react.sourcemap.androidSourcemapLocation);
96
+ if (loadedMap) {
97
+ const { map, path: originalMapPath } = loadedMap;
98
+ map.x_dynatrace_offset = mappings;
99
+ const backupPath = originalMapPath + '.bak';
100
+ const serilalisedPath = originalMapPath + '.serialised';
101
+ yield fs.copyFile(originalMapPath, backupPath);
102
+ yield this.log(`💾 Backup created: ${backupPath}`);
103
+ yield fs.writeFile(originalMapPath, JSON.stringify(map));
104
+ yield fs.writeFile(serilalisedPath, JSON.stringify(map, null, 2));
105
+ yield this.log(`📝 Patched source map written to: ${originalMapPath}`);
96
106
  }
97
107
  }
98
108
  catch (err) {
@@ -100,35 +110,18 @@ class LineOffsetAnalyzer {
100
110
  }
101
111
  });
102
112
  }
103
- loadSourceMap() {
113
+ loadSourceMap(mapPath) {
104
114
  return __awaiter(this, void 0, void 0, function* () {
105
- const processValue = process.cwd();
106
- const possiblePaths = [
107
- (0, path_1.join)(processValue, 'app/build/generated/sourcemaps/react/release/index.android.bundle.map'),
108
- (0, path_1.join)(this.androidSourcemapPath),
109
- (0, path_1.join)(this.iosSourcemapPath),
110
- ];
111
- let foundAny = false;
112
- for (const mapPath of possiblePaths) {
113
- try {
114
- const exists = yield FileOperationHelper_1.default.checkIfFileExists(mapPath);
115
- if (!exists) {
116
- continue;
117
- }
118
- foundAny = true;
119
- const content = yield fs.readFile(mapPath, 'utf-8');
120
- const parsed = JSON.parse(content);
121
- yield this.log(`🗺️ Found and parsed source map at: ${mapPath}`, true);
122
- return { map: parsed, path: mapPath };
123
- }
124
- catch (err) {
125
- yield this.log(`⚠️ Failed to load or parse source map at ${mapPath}: ${err.message}`, true);
126
- }
115
+ try {
116
+ const content = yield fs.readFile(mapPath, 'utf-8');
117
+ const parsed = JSON.parse(content);
118
+ yield this.log(`🗺️ Found and parsed source map at: ${mapPath}`, true);
119
+ return { map: parsed, path: mapPath };
127
120
  }
128
- if (!foundAny) {
129
- yield this.log('❌ No valid source map found in any of the expected locations.', true);
121
+ catch (err) {
122
+ yield this.log(`⚠️ Failed to load or parse source map at ${mapPath}: ${err.message} - skipping patching step`, true);
123
+ return null;
130
124
  }
131
- return null;
132
125
  });
133
126
  }
134
127
  log(msg, logOnScreen = false) {