@microsoft/applicationinsights-react-native 2.5.6 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +44 -2
  2. package/browser/applicationinsights-react-native.js +105 -47
  3. package/browser/applicationinsights-react-native.js.map +1 -1
  4. package/browser/applicationinsights-react-native.min.js +2 -2
  5. package/browser/applicationinsights-react-native.min.js.map +1 -1
  6. package/dist/applicationinsights-react-native.api.json +216 -6
  7. package/dist/applicationinsights-react-native.api.md +12 -5
  8. package/dist/applicationinsights-react-native.d.ts +70 -1
  9. package/dist/applicationinsights-react-native.js +105 -47
  10. package/dist/applicationinsights-react-native.js.map +1 -1
  11. package/dist/applicationinsights-react-native.min.js +2 -2
  12. package/dist/applicationinsights-react-native.min.js.map +1 -1
  13. package/dist/applicationinsights-react-native.rollup.d.ts +70 -1
  14. package/dist-esm/DeviceInfo/DeviceModule.js +38 -0
  15. package/dist-esm/DeviceInfo/DeviceModule.js.map +1 -0
  16. package/dist-esm/DeviceInfo/ReactNativeDeviceInfo.js +15 -0
  17. package/dist-esm/DeviceInfo/ReactNativeDeviceInfo.js.map +1 -0
  18. package/dist-esm/Interfaces/IDeviceInfoModule.js +8 -0
  19. package/dist-esm/Interfaces/IDeviceInfoModule.js.map +1 -0
  20. package/dist-esm/Interfaces/INativeDevice.js +3 -1
  21. package/dist-esm/Interfaces/INativeDevice.js.map +1 -1
  22. package/dist-esm/Interfaces/IReactNativePluginConfig.js +1 -1
  23. package/dist-esm/Interfaces/index.js +3 -1
  24. package/dist-esm/Interfaces/index.js.map +1 -1
  25. package/dist-esm/ReactNativePlugin.js +81 -41
  26. package/dist-esm/ReactNativePlugin.js.map +1 -1
  27. package/dist-esm/index.js +5 -1
  28. package/dist-esm/index.js.map +1 -1
  29. package/package.json +9 -8
  30. package/src/DeviceInfo/DeviceModule.ts +44 -0
  31. package/src/DeviceInfo/ReactNativeDeviceInfo.ts +13 -0
  32. package/src/Interfaces/IDeviceInfoModule.ts +31 -0
  33. package/src/Interfaces/INativeDevice.ts +3 -0
  34. package/src/Interfaces/IReactNativePluginConfig.ts +15 -0
  35. package/src/Interfaces/index.ts +3 -0
  36. package/src/ReactNativePlugin.ts +109 -41
  37. package/src/index.ts +8 -2
  38. package/types/DeviceInfo/DeviceModule.d.ts +10 -0
  39. package/types/DeviceInfo/ReactNativeDeviceInfo.d.ts +6 -0
  40. package/types/Interfaces/IDeviceInfoModule.d.ts +25 -0
  41. package/types/Interfaces/IReactNativePluginConfig.d.ts +11 -0
  42. package/types/ReactNativePlugin.d.ts +27 -11
  43. package/types/index.d.ts +4 -1
  44. package/types/tsdoc-metadata.json +1 -1
@@ -1,3 +1,6 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
1
4
  export interface INativeDevice {
2
5
  /**
3
6
  * Device type, e.g. Handset, Tablet, Tv
@@ -1,4 +1,19 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
1
3
  export interface IReactNativePluginConfig {
4
+ /**
5
+ * Disable automatic device collection
6
+ */
2
7
  disableDeviceCollection?: boolean;
8
+
9
+ /**
10
+ * Disable automatic exception collection
11
+ */
3
12
  disableExceptionCollection?: boolean;
13
+
14
+ /**
15
+ * Timeout value to unblock the processing of events if the DeviceInfoModule
16
+ * returns a Promise.
17
+ */
18
+ uniqueIdPromiseTimeout?: number;
4
19
  }
@@ -1,3 +1,6 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
1
4
  import { INativeDevice } from "./INativeDevice";
2
5
  import { IReactNativePluginConfig } from "./IReactNativePluginConfig";
3
6
 
@@ -1,39 +1,23 @@
1
- /**
2
- * ReactNativePlugin.ts
3
- * @copyright Microsoft 2019
4
- */
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
5
3
 
6
4
  import dynamicProto from "@microsoft/dynamicproto-js";
7
- import DeviceInfo from "react-native-device-info";
8
5
  import {
9
6
  AnalyticsPluginIdentifier, ConfigurationManager, IAppInsights, IDevice, IExceptionTelemetry, eSeverityLevel
10
7
  } from "@microsoft/applicationinsights-common";
11
8
  import {
12
9
  BaseTelemetryPlugin, IAppInsightsCore, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext, ITelemetryItem,
13
10
  ITelemetryPlugin, ITelemetryUnloadState, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, dumpObj, eLoggingSeverity,
14
- getExceptionName, hasOwnProperty, isObject, isUndefined
11
+ getExceptionName, isUndefined, objForEachKey
15
12
  } from "@microsoft/applicationinsights-core-js";
16
13
  import { getGlobal, strShimUndefined } from "@microsoft/applicationinsights-shims";
17
14
  import { INativeDevice, IReactNativePluginConfig } from "./Interfaces";
15
+ import { isPromiseLike, isString } from "@nevware21/ts-utils";
16
+ import { IDeviceInfoModule } from "./Interfaces/IDeviceInfoModule";
17
+ import { getReactNativeDeviceInfo } from "./DeviceInfo/ReactNativeDeviceInfo";
18
18
 
19
19
  declare var global: Window;
20
20
 
21
- /**
22
- * This is a helper function for the equivalent of arForEach(objKeys(target), callbackFn), this is a
23
- * performance optimization to avoid the creation of a new array for large objects
24
- * @param target The target object to find and process the keys
25
- * @param callbackfn The function to call with the details
26
- */
27
- export function objForEachKey(target: any, callbackfn: (name: string, value: any) => void) {
28
- if (target && isObject(target)) {
29
- for (let prop in target) {
30
- if (hasOwnProperty(target, prop)) {
31
- callbackfn.call(target, prop, target[prop]);
32
- }
33
- }
34
- }
35
- }
36
-
37
21
  export class ReactNativePlugin extends BaseTelemetryPlugin {
38
22
 
39
23
  identifier: string = "AppInsightsReactNativePlugin";
@@ -51,6 +35,10 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
51
35
  let _config: IReactNativePluginConfig;
52
36
  let _analyticsPlugin: IAppInsights;
53
37
  let _defaultHandler;
38
+ let _waitingForId: boolean;
39
+ let _waitingTimer: number;
40
+ let _waitingItems: { item: ITelemetryItem, itemCtx?: IProcessTelemetryContext }[] = null;
41
+ let _deviceInfoModule: IDeviceInfoModule;
54
42
 
55
43
  dynamicProto(ReactNativePlugin, this, (_self, _base) => {
56
44
  _initDefaults();
@@ -78,13 +66,8 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
78
66
  _self._collectDeviceInfo();
79
67
  }
80
68
 
81
- if (extensions) {
82
- arrForEach(extensions, ext => {
83
- const identifier = (ext as ITelemetryPlugin).identifier;
84
- if (identifier === AnalyticsPluginIdentifier) {
85
- _analyticsPlugin = (ext as any) as IAppInsights;
86
- }
87
- });
69
+ if (core && core.getPlugin) {
70
+ _analyticsPlugin = core.getPlugin<any>(AnalyticsPluginIdentifier)?.plugin as IAppInsights;
88
71
  }
89
72
 
90
73
  if (!_config.disableExceptionCollection) {
@@ -94,13 +77,25 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
94
77
  };
95
78
 
96
79
  _self.processTelemetry = (item: ITelemetryItem, itemCtx?: IProcessTelemetryContext) => {
97
- _applyDeviceContext(item);
98
- _self.processNext(item, itemCtx);
80
+ if (!_waitingForId) {
81
+ _applyDeviceContext(item);
82
+ _self.processNext(item, itemCtx);
83
+ } else {
84
+ // Make sure we have an array for the waiting items
85
+ _waitingItems = _waitingItems || [];
86
+ _waitingItems.push({
87
+ item,
88
+ itemCtx
89
+ });
90
+ }
99
91
  };
100
92
 
101
- _self.setDeviceId = (newId: string) => {
102
- _device.id = newId;
93
+ _self.setDeviceInfoModule = (deviceInfoModule: IDeviceInfoModule) => {
94
+ // Set the configured deviceInfoModule
95
+ _deviceInfoModule = deviceInfoModule;
103
96
  };
97
+
98
+ _self.setDeviceId =_setDeviceId;
104
99
 
105
100
  _self.setDeviceModel = (newModel: string) => {
106
101
  _device.model = newModel;
@@ -115,9 +110,30 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
115
110
  */
116
111
  _self._collectDeviceInfo = () => {
117
112
  try {
118
- _device.deviceClass = DeviceInfo.getDeviceType();
119
- _device.id = DeviceInfo.getUniqueId(); // Installation ID
120
- _device.model = DeviceInfo.getModel();
113
+ let deviceInfoModule = _deviceInfoModule || getReactNativeDeviceInfo();
114
+
115
+ _device.deviceClass = deviceInfoModule.getDeviceType();
116
+ _device.model = deviceInfoModule.getModel();
117
+ let uniqueId = deviceInfoModule.getUniqueId(); // Installation ID support different versions which return a promise vs string
118
+ if (isPromiseLike(uniqueId)) {
119
+ _waitingForId = true;
120
+ if (_waitingTimer) {
121
+ clearTimeout(_waitingTimer);
122
+ }
123
+ _waitingTimer = setTimeout(() => {
124
+ _waitingTimer = null;
125
+ _setDeviceId(_device.id);
126
+ });
127
+ uniqueId.then((value) => {
128
+ _setDeviceId(value);
129
+ }, (reason) => {
130
+ _warnToConsole(_self.diagLog(), "Failed to get device id: " + dumpObj(reason));
131
+ // Just reuse the existing id (if any)
132
+ _setDeviceId(_device.id);
133
+ });
134
+ } else if (isString(uniqueId)) {
135
+ _device.id = uniqueId;
136
+ }
121
137
  } catch (e) {
122
138
  _warnToConsole(_self.diagLog(), "Failed to get DeviceInfo: " + getExceptionName(e) + " - " + dumpObj(e));
123
139
  }
@@ -133,19 +149,41 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
133
149
  _config = config || _getDefaultConfig();
134
150
  _analyticsPlugin = null;
135
151
  _defaultHandler = null;
152
+ _waitingForId = false;
153
+ _deviceInfoModule = null;
154
+ }
155
+
156
+ function _setDeviceId(newId: string) {
157
+ _device.id = newId;
158
+ _waitingForId = false;
159
+ if (_waitingTimer) {
160
+ clearTimeout(_waitingTimer);
161
+ }
162
+
163
+ if (!_waitingForId && _waitingItems && _waitingItems.length > 0 && _self.isInitialized()) {
164
+ let items = _waitingItems;
165
+ _waitingItems = null;
166
+ arrForEach(items, (value) => {
167
+ try {
168
+ _self.processTelemetry(value.item, value.itemCtx);
169
+ } catch (e) {
170
+ // Just ignore
171
+ }
172
+ });
173
+ }
136
174
  }
137
175
 
138
176
  function _applyDeviceContext(item: ITelemetryItem) {
139
177
  if (_device) {
140
178
  item.ext = item.ext || {};
141
179
  item.ext.device = item.ext.device || ({} as IDevice);
142
- if (typeof _device.id === "string") {
180
+ if (isString(_device.id)) {
143
181
  item.ext.device.localId = _device.id;
144
182
  }
145
- if (typeof _device.model === "string") {
183
+ if (isString(_device.model)) {
146
184
  item.ext.device.model = _device.model;
147
185
  }
148
- if (typeof _device.deviceClass === "string") {
186
+ if (isString(_device.deviceClass)) {
149
187
  item.ext.device.deviceClass = _device.deviceClass;
150
188
  }
151
189
  }
@@ -195,7 +233,7 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
195
233
  // Test Hooks
196
234
  (_self as any)._config = _config;
197
235
  (_self as any)._getDbgPlgTargets = () => {
198
- return [_device];
236
+ return [_device, _deviceInfoModule];
199
237
  }
200
238
  });
201
239
 
@@ -203,7 +241,8 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
203
241
  return {
204
242
  // enable auto collection by default
205
243
  disableDeviceCollection: false,
206
- disableExceptionCollection: false
244
+ disableExceptionCollection: false,
245
+ uniqueIdPromiseTimeout: 5000
207
246
  };
208
247
  }
209
248
  }
@@ -220,14 +259,43 @@ export class ReactNativePlugin extends BaseTelemetryPlugin {
220
259
  // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
221
260
  }
222
261
 
262
+ /**
263
+ * Set the module that will be used during initialization when collecting device is enabled
264
+ * (the default), automatic collection can be disabled via the `disableDeviceCollection`
265
+ * config. The `react-native-device-info` module will be used by default if no
266
+ * `deviceInfoModule` is set and collection is enabled.
267
+ * @param deviceInfoModule
268
+ */
269
+ public setDeviceInfoModule(deviceInfoModule: IDeviceInfoModule) {
270
+ // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
271
+ }
272
+
273
+ /**
274
+ * Manually set the deviceId, if set before initialization and automatic device info collection
275
+ * is enabled this value may get overwritten. If you want to keep this value disable auto
276
+ * collection by setting the `disableDeviceCollection` config to true.
277
+ * @param newId - The value to use as the device Id.
278
+ */
223
279
  public setDeviceId(newId: string) {
224
280
  // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
225
281
  }
226
282
 
283
+ /**
284
+ * Manually set the device model, if set before initialization and automatic device info
285
+ * collection is enabled this value may get overwritten. If you want to keep this value
286
+ * disable auto collection by setting the `disableDeviceCollection` config to true.
287
+ * @param newModel - The value to use as the device model.
288
+ */
227
289
  public setDeviceModel(newModel: string) {
228
290
  // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
229
291
  }
230
292
 
293
+ /**
294
+ * Manually set the device type (class), if set before initialization and automatic device
295
+ * info collection is enabled this value may get overwritten. If you want to keep this value
296
+ * disable auto collection by setting the `disableDeviceCollection` config to true.
297
+ * @param newType - The value to use as the device type
298
+ */
231
299
  public setDeviceType(newType: string) {
232
300
  // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
233
301
  }
package/src/index.ts CHANGED
@@ -1,4 +1,10 @@
1
- import {ReactNativePlugin} from "./ReactNativePlugin";
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { ReactNativePlugin } from "./ReactNativePlugin";
2
5
  import { INativeDevice, IReactNativePluginConfig } from "./Interfaces";
6
+ import { IDeviceInfoModule } from "./Interfaces/IDeviceInfoModule";
7
+ import { getReactNativeDeviceInfo } from "./DeviceInfo/ReactNativeDeviceInfo";
3
8
 
4
- export { ReactNativePlugin, INativeDevice, IReactNativePluginConfig };
9
+ export { ReactNativePlugin, INativeDevice, IReactNativePluginConfig, IDeviceInfoModule };
10
+ export { getReactNativeDeviceInfo };
@@ -0,0 +1,10 @@
1
+ import { IDeviceInfoModule } from "../Interfaces/IDeviceInfoModule";
2
+ export declare const DEVICE_MODEL = "model";
3
+ export declare const DEVICE_TYPE = "type";
4
+ export declare const UNIQUE_ID = "id";
5
+ export declare class DeviceModule implements IDeviceInfoModule {
6
+ getModel: () => string;
7
+ getDeviceType: () => string;
8
+ getUniqueId: () => string | Promise<string>;
9
+ constructor();
10
+ }
@@ -0,0 +1,6 @@
1
+ import { IDeviceInfoModule } from "../Interfaces/IDeviceInfoModule";
2
+ /**
3
+ * Returns the "react-native-device-info" as the Device Info Module
4
+ * @returns
5
+ */
6
+ export declare function getReactNativeDeviceInfo(): IDeviceInfoModule;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Interface to abstract how the plugin can access the Device Info, this is a stripped
3
+ * down version of the "react-native-device-info" interface and is mostly supplied for
4
+ * testing.
5
+ */
6
+ export interface IDeviceInfoModule {
7
+ /**
8
+ * Returns the Device Model
9
+ */
10
+ getModel: () => string;
11
+ /**
12
+ * Returns the device type
13
+ */
14
+ getDeviceType: () => string;
15
+ /**
16
+ * Returns the unique Id for the device, to support both the current version and previous
17
+ * versions react-native-device-info, this may return either a `string` or `Promise<string>`,
18
+ * when a promise is returned the plugin will "wait" for the promise to `resolve` or `reject`
19
+ * before processing any events. This WILL cause telemetry to be BLOCKED until either of these
20
+ * states, so when returning a Promise it MUST `resolve` or `reject` it can't just never resolve.
21
+ * There is a default timeout configured via `uniqueIdPromiseTimeout` to automatically unblock
22
+ * event processing when this issue occurs.
23
+ */
24
+ getUniqueId: () => Promise<string> | string;
25
+ }
@@ -1,4 +1,15 @@
1
1
  export interface IReactNativePluginConfig {
2
+ /**
3
+ * Disable automatic device collection
4
+ */
2
5
  disableDeviceCollection?: boolean;
6
+ /**
7
+ * Disable automatic exception collection
8
+ */
3
9
  disableExceptionCollection?: boolean;
10
+ /**
11
+ * Timeout value to unblock the processing of events if the DeviceInfoModule
12
+ * returns a Promise.
13
+ */
14
+ uniqueIdPromiseTimeout?: number;
4
15
  }
@@ -1,16 +1,6 @@
1
- /**
2
- * ReactNativePlugin.ts
3
- * @copyright Microsoft 2019
4
- */
5
1
  import { BaseTelemetryPlugin, IAppInsightsCore, IPlugin, IProcessTelemetryContext, ITelemetryItem, ITelemetryPlugin } from "@microsoft/applicationinsights-core-js";
6
2
  import { IReactNativePluginConfig } from "./Interfaces";
7
- /**
8
- * This is a helper function for the equivalent of arForEach(objKeys(target), callbackFn), this is a
9
- * performance optimization to avoid the creation of a new array for large objects
10
- * @param target The target object to find and process the keys
11
- * @param callbackfn The function to call with the details
12
- */
13
- export declare function objForEachKey(target: any, callbackfn: (name: string, value: any) => void): void;
3
+ import { IDeviceInfoModule } from "./Interfaces/IDeviceInfoModule";
14
4
  export declare class ReactNativePlugin extends BaseTelemetryPlugin {
15
5
  identifier: string;
16
6
  priority: number;
@@ -21,7 +11,33 @@ export declare class ReactNativePlugin extends BaseTelemetryPlugin {
21
11
  initialize(config?: IReactNativePluginConfig | object, // need `| object` to coerce to interface
22
12
  core?: IAppInsightsCore, extensions?: IPlugin[]): void;
23
13
  processTelemetry(env: ITelemetryItem, itemCtx?: IProcessTelemetryContext): void;
14
+ /**
15
+ * Set the module that will be used during initialization when collecting device is enabled
16
+ * (the default), automatic collection can be disabled via the `disableDeviceCollection`
17
+ * config. The `react-native-device-info` module will be used by default if no
18
+ * `deviceInfoModule` is set and collection is enabled.
19
+ * @param deviceInfoModule
20
+ */
21
+ setDeviceInfoModule(deviceInfoModule: IDeviceInfoModule): void;
22
+ /**
23
+ * Manually set the deviceId, if set before initialization and automatic device info collection
24
+ * is enabled this value may get overwritten. If you want to keep this value disable auto
25
+ * collection by setting the `disableDeviceCollection` config to true.
26
+ * @param newId - The value to use as the device Id.
27
+ */
24
28
  setDeviceId(newId: string): void;
29
+ /**
30
+ * Manually set the device model, if set before initialization and automatic device info
31
+ * collection is enabled this value may get overwritten. If you want to keep this value
32
+ * disable auto collection by setting the `disableDeviceCollection` config to true.
33
+ * @param newModel - The value to use as the device model.
34
+ */
25
35
  setDeviceModel(newModel: string): void;
36
+ /**
37
+ * Manually set the device type (class), if set before initialization and automatic device
38
+ * info collection is enabled this value may get overwritten. If you want to keep this value
39
+ * disable auto collection by setting the `disableDeviceCollection` config to true.
40
+ * @param newType - The value to use as the device type
41
+ */
26
42
  setDeviceType(newType: string): void;
27
43
  }
package/types/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import { ReactNativePlugin } from "./ReactNativePlugin";
2
2
  import { INativeDevice, IReactNativePluginConfig } from "./Interfaces";
3
- export { ReactNativePlugin, INativeDevice, IReactNativePluginConfig };
3
+ import { IDeviceInfoModule } from "./Interfaces/IDeviceInfoModule";
4
+ import { getReactNativeDeviceInfo } from "./DeviceInfo/ReactNativeDeviceInfo";
5
+ export { ReactNativePlugin, INativeDevice, IReactNativePluginConfig, IDeviceInfoModule };
6
+ export { getReactNativeDeviceInfo };
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.28.6"
8
+ "packageVersion": "7.28.7"
9
9
  }
10
10
  ]
11
11
  }