@microsoft/power-apps-native-common 0.2.2 → 0.3.2

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 (38) hide show
  1. package/lib/NOTICE.txt +26 -0
  2. package/lib/commonjs/index.js +29 -5
  3. package/lib/commonjs/telemetry/AnonymousTelemetry.js +25 -0
  4. package/lib/commonjs/telemetry/CustomEventsLogger.js +56 -0
  5. package/lib/commonjs/telemetry/OneDsTelemetryProvider.js +47 -5
  6. package/lib/commonjs/telemetry/TelemetrySanitizer.js +25 -4
  7. package/lib/commonjs/telemetry/resolveTelemetryLocation.js +29 -3
  8. package/lib/commonjs/telemetry/stringifyError.js +7 -15
  9. package/lib/commonjs/utils/DeviceIdUtils.js +9 -28
  10. package/lib/module/index.js +3 -3
  11. package/lib/module/telemetry/AnonymousTelemetry.js +21 -0
  12. package/lib/module/telemetry/CustomEventsLogger.js +51 -0
  13. package/lib/module/telemetry/OneDsTelemetryProvider.js +47 -5
  14. package/lib/module/telemetry/TelemetrySanitizer.js +25 -4
  15. package/lib/module/telemetry/resolveTelemetryLocation.js +26 -3
  16. package/lib/module/telemetry/stringifyError.js +7 -16
  17. package/lib/module/utils/DeviceIdUtils.js +8 -28
  18. package/lib/typescript/commonjs/index.d.ts +4 -4
  19. package/lib/typescript/commonjs/telemetry/AnonymousTelemetry.d.ts +4 -0
  20. package/lib/typescript/commonjs/telemetry/CustomEventsLogger.d.ts +21 -0
  21. package/lib/typescript/commonjs/telemetry/OneDsTelemetryProvider.d.ts +8 -1
  22. package/lib/typescript/commonjs/telemetry/TelemetryTypes.d.ts +8 -1
  23. package/lib/typescript/commonjs/telemetry/resolveTelemetryLocation.d.ts +8 -1
  24. package/lib/typescript/commonjs/telemetry/stringifyError.d.ts +3 -3
  25. package/lib/typescript/commonjs/utils/DeviceIdUtils.d.ts +5 -12
  26. package/lib/typescript/module/index.d.ts +4 -4
  27. package/lib/typescript/module/telemetry/AnonymousTelemetry.d.ts +4 -0
  28. package/lib/typescript/module/telemetry/CustomEventsLogger.d.ts +21 -0
  29. package/lib/typescript/module/telemetry/OneDsTelemetryProvider.d.ts +8 -1
  30. package/lib/typescript/module/telemetry/TelemetryTypes.d.ts +8 -1
  31. package/lib/typescript/module/telemetry/resolveTelemetryLocation.d.ts +8 -1
  32. package/lib/typescript/module/telemetry/stringifyError.d.ts +3 -3
  33. package/lib/typescript/module/utils/DeviceIdUtils.d.ts +5 -12
  34. package/package.json +3 -2
  35. package/lib/commonjs/telemetry/CustomerTelemetryLogger.js +0 -56
  36. package/lib/module/telemetry/CustomerTelemetryLogger.js +0 -51
  37. package/lib/typescript/commonjs/telemetry/CustomerTelemetryLogger.d.ts +0 -21
  38. package/lib/typescript/module/telemetry/CustomerTelemetryLogger.d.ts +0 -21
@@ -8,6 +8,7 @@ import { AppInsightsCore } from '@microsoft/applicationinsights-core-js';
8
8
  import { PostChannel } from '@microsoft/1ds-post-js';
9
9
  import { generateGuid } from "../utils/GuidUtils.js";
10
10
  import { resolvePlatformInfo } from "../utils/PlatformInfoUtils.js";
11
+ import { buildAnonymousTelemetryData } from "./AnonymousTelemetry.js";
11
12
  /** 1DS Aria project IDs shared by the webplayer and CLI. */
12
13
  const AriaProjectIds = {
13
14
  Production: '5c3a61f48d7c4522912765ae7465ab5c-fb3d6606-fe59-4d6b-9bb1-5e993d889672-7138',
@@ -93,11 +94,14 @@ export class OneDsTelemetryProvider {
93
94
  defaultProperties = {};
94
95
  constructor(config) {
95
96
  this._sessionId = generateGuid();
97
+ this.anonymous = config.anonymous ?? false;
98
+ this.telemetryLocation = config.telemetryLocation ?? 'global';
96
99
  this.appName = resolveAppName(config.clusterCategory);
97
100
  this.appVersion = config.appVersion ?? '';
98
101
  this.clientType = config.clientType;
99
102
  this.clusterCategory = config.clusterCategory;
100
103
  this.deviceId = config.deviceId ?? 'react-native';
104
+ this.includeUserIdentity = config.includeUserIdentity ?? false;
101
105
  this.minSeverity = config.minSeverity ?? 'info';
102
106
  const {
103
107
  osName,
@@ -124,15 +128,15 @@ export class OneDsTelemetryProvider {
124
128
  if (config.commonProperties) {
125
129
  Object.assign(this.defaultProperties, config.commonProperties);
126
130
  }
127
- const postChannel = new PostChannel();
131
+ this.postChannel = new PostChannel();
128
132
  const instrumentationKey = config.instrumentationKey ?? resolveInstrumentationKey(config.clusterCategory);
129
- const collectorUrl = resolveCollectorUrl(config.clusterCategory, config.telemetryLocation);
133
+ const collectorUrl = resolveCollectorUrl(config.clusterCategory, this.telemetryLocation);
130
134
  const coreConfig = {
131
135
  instrumentationKey,
132
- channels: [[postChannel]]
136
+ channels: [[this.postChannel]]
133
137
  };
134
138
  coreConfig.extensionConfig = {
135
- [postChannel.identifier]: {
139
+ [this.postChannel.identifier]: {
136
140
  // Override endpoint explicitly — PostChannel reads overrideEndpointUrl
137
141
  // from its own extensionConfig, not from coreConfig.endpointUrl.
138
142
  overrideEndpointUrl: collectorUrl,
@@ -164,6 +168,7 @@ export class OneDsTelemetryProvider {
164
168
  const ext = envelope.ext = envelope.ext ?? {};
165
169
  const utc = ext['utc'] = ext['utc'] ?? {};
166
170
  utc['eventFlags'] = (utc['eventFlags'] || 0) | 0x100000;
171
+ if (this.anonymous) return;
167
172
  const app = ext['app'] = ext['app'] ?? {};
168
173
  app['sesId'] = this._sessionId;
169
174
  if (this.appVersion) app['ver'] = this.appVersion; // → AppInfo_Version
@@ -189,6 +194,15 @@ export class OneDsTelemetryProvider {
189
194
  this.core.addTelemetryInitializer(initializer);
190
195
  }
191
196
  track(event) {
197
+ if (this.anonymous) {
198
+ this.core.track({
199
+ name: 'event',
200
+ time: event.timestamp,
201
+ baseType: 'custom',
202
+ data: buildAnonymousTelemetryData(event, this.appName, this.clusterCategory)
203
+ });
204
+ return;
205
+ }
192
206
  const allProperties = {
193
207
  ...this.defaultProperties,
194
208
  ...event.properties
@@ -214,7 +228,7 @@ export class OneDsTelemetryProvider {
214
228
  };
215
229
 
216
230
  // User identity promoted to top-level columns directly
217
- if (this.userIdentity) {
231
+ if (this.includeUserIdentity && this.userIdentity) {
218
232
  data.objectId = this.userIdentity.objectId;
219
233
  data.tenantId = this.userIdentity.tenantId;
220
234
  }
@@ -242,6 +256,34 @@ export class OneDsTelemetryProvider {
242
256
  };
243
257
  this.core.track(item);
244
258
  }
259
+ async resolveTelemetryLocation(telemetryLocation) {
260
+ if (!this.anonymous && telemetryLocation === this.telemetryLocation) return;
261
+ const previousResolution = this.locationResolution ?? Promise.resolve();
262
+ const currentResolution = previousResolution.catch(() => undefined).then(() => this.applyTelemetryLocation(telemetryLocation));
263
+ this.locationResolution = currentResolution;
264
+ try {
265
+ await currentResolution;
266
+ } finally {
267
+ if (this.locationResolution === currentResolution) {
268
+ this.locationResolution = undefined;
269
+ }
270
+ }
271
+ }
272
+ async applyTelemetryLocation(telemetryLocation) {
273
+ if (!this.anonymous && telemetryLocation === this.telemetryLocation) return;
274
+ if (telemetryLocation !== this.telemetryLocation) {
275
+ await this.flush();
276
+ this.core.updateCfg({
277
+ extensionConfig: {
278
+ [this.postChannel.identifier]: {
279
+ overrideEndpointUrl: resolveCollectorUrl(this.clusterCategory, telemetryLocation)
280
+ }
281
+ }
282
+ });
283
+ this.telemetryLocation = telemetryLocation;
284
+ }
285
+ this.anonymous = false;
286
+ }
245
287
  flush() {
246
288
  return new Promise(resolve => {
247
289
  this.core.flush(true, () => {
@@ -50,6 +50,13 @@ const SAS_KEY_SIG_RE = /(?:dsas_secret|sig)=[^#)\(<>\r\n\s'",\\_&]{8}[^#)\(<>\r\
50
50
  */
51
51
  const SYMM_KEY_256_RE = /[a-z0-9/+]{43}=/gi;
52
52
 
53
+ /** Bearer credentials and compact JWTs embedded in otherwise arbitrary text. */
54
+ const BEARER_CREDENTIAL_RE = /\bbearer\s+[a-z0-9._~+\/-]+=*/gi;
55
+ const JWT_RE = /\beyJ[a-z0-9_-]+\.[a-z0-9_-]+\.[a-z0-9_-]+\b/gi;
56
+
57
+ /** Query strings and fragments on absolute URLs commonly carry user context. */
58
+ const URL_QUERY_OR_FRAGMENT_RE = /(https?:\/\/[^\s?#'"<>]+)[?#][^\s'"<>]*/gi;
59
+
53
60
  /**
54
61
  * Property key patterns that must never appear as telemetry values.
55
62
  * Checked case-insensitively against the full key name.
@@ -61,7 +68,7 @@ const SENSITIVE_KEY_RE = /password|secret|token|credential|auth(?:orization)?|be
61
68
  * Safe to use on error messages, URL paths, and arbitrary text.
62
69
  */
63
70
  export function sanitizeErrorString(raw) {
64
- return raw.replace(EMAIL_RE, '<upn>').replace(PRIVATE_IPV4_RE, (_, port) => port ? `<private-ip>${port}` : '<private-ip>').replace(GOOGLE_API_KEY_RE, '<credential>').replace(SAS_KEY_SIG_RE, '<credential>').replace(SYMM_KEY_256_RE, '<credential>');
71
+ return raw.replace(URL_QUERY_OR_FRAGMENT_RE, '$1').replace(EMAIL_RE, '<upn>').replace(PRIVATE_IPV4_RE, (_, port) => port ? `<private-ip>${port}` : '<private-ip>').replace(GOOGLE_API_KEY_RE, '<credential>').replace(SAS_KEY_SIG_RE, '<credential>').replace(SYMM_KEY_256_RE, '<credential>').replace(BEARER_CREDENTIAL_RE, 'Bearer <credential>').replace(JWT_RE, '<credential>');
65
72
  }
66
73
 
67
74
  /**
@@ -80,15 +87,29 @@ export function sanitizeUrl(url) {
80
87
  * - Non-string primitives passed through unchanged
81
88
  */
82
89
  export function sanitizeProperties(props) {
90
+ return sanitizeRecord(props, new WeakSet(), 0);
91
+ }
92
+ const MAX_SANITIZE_DEPTH = 5;
93
+ function sanitizeRecord(props, seen, depth) {
94
+ if (seen.has(props) || depth > MAX_SANITIZE_DEPTH) return {};
95
+ seen.add(props);
83
96
  const result = {};
84
97
  for (const [key, value] of Object.entries(props)) {
85
98
  if (SENSITIVE_KEY_RE.test(key)) {
86
99
  result[key] = '<redacted>';
87
- } else if (typeof value === 'string') {
88
- result[key] = sanitizeErrorString(value);
89
100
  } else {
90
- result[key] = value;
101
+ result[key] = sanitizeValue(value, seen, depth + 1);
91
102
  }
92
103
  }
93
104
  return result;
105
+ }
106
+ function sanitizeValue(value, seen, depth) {
107
+ if (typeof value === 'string') return sanitizeErrorString(value);
108
+ if (value === null || typeof value !== 'object') return value;
109
+ if (depth > MAX_SANITIZE_DEPTH || seen.has(value)) return '<redacted>';
110
+ if (Array.isArray(value)) {
111
+ seen.add(value);
112
+ return value.map(item => sanitizeValue(item, seen, depth + 1));
113
+ }
114
+ return sanitizeRecord(value, seen, depth);
94
115
  }
@@ -11,13 +11,23 @@
11
11
  * Source: `metadata.properties.location` in the BAP Get Environments API response.
12
12
  */
13
13
  const EU_BAP_LOCATIONS = new Set(['europe', 'france', 'germany', 'italy', 'poland', 'norway', 'sweden', 'switzerland', 'unitedkingdom']);
14
+ const NON_EU_BAP_LOCATIONS = new Set(['asia', 'australia', 'brazil', 'canada', 'india', 'japan', 'korea', 'southafrica', 'southamerica', 'unitedarabemirates', 'unitedstates']);
15
+ const EU_DATAVERSE_REGIONS = new Set(['che', 'emea', 'eur', 'fra', 'gbr', 'ger', 'ita', 'nor', 'pol', 'swe']);
16
+ const NON_EU_DATAVERSE_REGIONS = new Set(['apac', 'aus', 'can', 'ind', 'jpn', 'kor', 'latam', 'nam', 'na', 'oce', 'sam', 'sgp', 'uae', 'usa']);
17
+ function resolveKnownLocation(input, euValues, nonEuValues) {
18
+ const value = input?.trim().toLowerCase();
19
+ if (value && euValues.has(value)) return 'eu';
20
+ if (value && nonEuValues.has(value)) return 'global';
21
+ return undefined;
22
+ }
14
23
 
15
24
  /**
16
25
  * Resolve the 1DS telemetry collector location from a Power Platform BAP
17
26
  * environment `location` string (`environment.properties.location`).
18
27
  * Returns `'eu'` when the location maps to the EU data boundary, routing
19
28
  * telemetry to `eu-mobile.events.data.microsoft.com` instead of the global
20
- * US collector.
29
+ * US collector. Missing or blank locations fail closed to the EU collector so
30
+ * telemetry emitted before the environment is known does not leave the EUDB.
21
31
  *
22
32
  * Mirrors the CLI's detection in `CliLogger.ts`:
23
33
  * ```
@@ -31,8 +41,21 @@ const EU_BAP_LOCATIONS = new Set(['europe', 'france', 'germany', 'italy', 'polan
31
41
  * resolveTelemetryLocation('unitedkingdom') // → 'eu'
32
42
  * resolveTelemetryLocation('italy') // → 'eu'
33
43
  * resolveTelemetryLocation('unitedstates') // → 'global'
44
+ * resolveTelemetryLocation() // → 'eu'
34
45
  */
35
46
  export function resolveTelemetryLocation(input) {
36
- if (!input) return 'global';
37
- return EU_BAP_LOCATIONS.has(input.trim().toLowerCase()) ? 'eu' : 'global';
47
+ return resolveKnownLocation(input, EU_BAP_LOCATIONS, NON_EU_BAP_LOCATIONS) ?? 'eu';
48
+ }
49
+
50
+ /** Resolve a Dataverse Global Discovery `Instance.Region` code. */
51
+ export function resolveTelemetryLocationFromDataverseRegion(input) {
52
+ return tryResolveTelemetryLocationFromDataverseRegion(input) ?? 'eu';
53
+ }
54
+ export function tryResolveTelemetryLocationFromDataverseRegion(input) {
55
+ return resolveKnownLocation(input, EU_DATAVERSE_REGIONS, NON_EU_DATAVERSE_REGIONS);
56
+ }
57
+
58
+ /** Resolve launch metadata, falling back from BAP location to cluster geography. */
59
+ export function tryResolveTelemetryLocationFromEnvironment(location, clusterGeoShortName) {
60
+ return resolveKnownLocation(location, EU_BAP_LOCATIONS, NON_EU_BAP_LOCATIONS) ?? tryResolveTelemetryLocationFromDataverseRegion(clusterGeoShortName);
38
61
  }
@@ -4,25 +4,16 @@
4
4
  * Copyright (C) Microsoft Corporation. All rights reserved.
5
5
  */
6
6
 
7
- import { sanitizeErrorString } from "./TelemetrySanitizer.js";
8
-
9
7
  /**
10
- * Converts an unknown thrown value to a string suitable for telemetry.
11
- * PII (email addresses, private IPv4 addresses) is redacted before the
12
- * string is returned.
8
+ * Classifies an unknown thrown value without exporting its message, stack, or
9
+ * serialized contents. Error prose is not a safe telemetry contract because
10
+ * upstream services may include customer data or credentials in it.
13
11
  */
14
12
  export function stringifyError(error) {
15
- let raw;
16
13
  if (error instanceof Error) {
17
- raw = `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`;
18
- } else if (typeof error === 'string') {
19
- raw = error;
20
- } else {
21
- try {
22
- raw = JSON.stringify(error);
23
- } catch {
24
- raw = String(error);
25
- }
14
+ return error.name || error.constructor.name || 'Error';
26
15
  }
27
- return sanitizeErrorString(raw);
16
+ if (typeof error === 'string') return 'StringError';
17
+ if (error && typeof error === 'object') return error.constructor?.name || 'ObjectError';
18
+ return `${typeof error}Error`;
28
19
  }
@@ -4,9 +4,7 @@
4
4
  * Copyright (C) Microsoft Corporation. All rights reserved.
5
5
  */
6
6
 
7
- import * as Application from 'expo-application';
8
7
  import * as SecureStore from 'expo-secure-store';
9
- import { Platform } from 'react-native';
10
8
  import { generateGuid } from "./GuidUtils.js";
11
9
 
12
10
  // Fallback key used when the platform native ID is unavailable.
@@ -14,18 +12,9 @@ import { generateGuid } from "./GuidUtils.js";
14
12
  const DEVICE_ID_FALLBACK_KEY = 'microsoft.power-apps-native-common.device_id';
15
13
 
16
14
  /**
17
- * Returns a stable device identifier, preferring platform-native IDs that
18
- * survive app reinstalls:
19
- *
20
- * - **iOS**: `getIosIdForVendorAsync()` (IDFV) — stable while ≥1 app from the
21
- * same vendor bundle prefix is installed. Resets only when ALL vendor apps
22
- * are removed.
23
- * - **Android**: `getAndroidId()` (SSAID) — scoped to the app signing key on
24
- * Android 8+; survives reinstalls as long as the signing key is unchanged.
25
- *
26
- * If the platform API returns null (rare edge cases: first boot, some emulators)
27
- * the function falls back to a UUID persisted in `expo-secure-store`, which on
28
- * iOS survives reinstalls via the Keychain and on Android is per-install only.
15
+ * Returns a random app-scoped telemetry identifier. It does not use IDFV,
16
+ * SSAID, or another platform device identifier, and can be rotated with
17
+ * `resetDeviceId()` for deletion and opt-out workflows.
29
18
  *
30
19
  * Pass the resolved value to `OneDsTelemetryProviderConfig.deviceId` at startup.
31
20
  *
@@ -38,20 +27,6 @@ const DEVICE_ID_FALLBACK_KEY = 'microsoft.power-apps-native-common.device_id';
38
27
  * ```
39
28
  */
40
29
  export async function resolveDeviceId() {
41
- if (Platform.OS === 'ios') {
42
- const idfv = await Application.getIosIdForVendorAsync();
43
- if (idfv) {
44
- return idfv;
45
- }
46
- } else if (Platform.OS === 'android') {
47
- const androidId = Application.getAndroidId();
48
- if (androidId) {
49
- return androidId;
50
- }
51
- }
52
-
53
- // Fallback: stable UUID in SecureStore (iOS: survives reinstall via Keychain;
54
- // Android: per-install only, but only reached when SSAID is unavailable).
55
30
  const existing = await SecureStore.getItemAsync(DEVICE_ID_FALLBACK_KEY);
56
31
  if (existing) {
57
32
  return existing;
@@ -59,4 +34,9 @@ export async function resolveDeviceId() {
59
34
  const id = generateGuid();
60
35
  await SecureStore.setItemAsync(DEVICE_ID_FALLBACK_KEY, id);
61
36
  return id;
37
+ }
38
+
39
+ /** Deletes the app-scoped telemetry identifier so the next resolution rotates it. */
40
+ export async function resetDeviceId() {
41
+ await SecureStore.deleteItemAsync(DEVICE_ID_FALLBACK_KEY);
62
42
  }
@@ -7,15 +7,15 @@ export type { ILogger, ScenarioTracker } from './telemetry/ILogger';
7
7
  export { Logger } from './telemetry/Logger';
8
8
  export { OneDsTelemetryProvider } from './telemetry/OneDsTelemetryProvider';
9
9
  export { ApplicationInsightsTelemetryProvider } from './telemetry/ApplicationInsightsTelemetryProvider';
10
- export { resolveTelemetryLocation } from './telemetry/resolveTelemetryLocation';
10
+ export { resolveTelemetryLocation, resolveTelemetryLocationFromDataverseRegion, tryResolveTelemetryLocationFromDataverseRegion, tryResolveTelemetryLocationFromEnvironment, } from './telemetry/resolveTelemetryLocation';
11
11
  export { stringifyError } from './telemetry/stringifyError';
12
12
  export { sanitizeErrorString, sanitizeUrl, sanitizeProperties } from './telemetry/TelemetrySanitizer';
13
13
  export { suppressKnownWarnings } from './telemetry/suppressKnownWarnings';
14
14
  export { HttpClient, getHttpCorrelationProperties } from './http/HttpClient';
15
- export { resolveDeviceId } from './utils/DeviceIdUtils';
15
+ export { resetDeviceId, resolveDeviceId } from './utils/DeviceIdUtils';
16
16
  export { configureAppLogger, getAppLogger } from './telemetry/AppLogger';
17
- export { configureCustomerTelemetryLogger, getCustomerTelemetryLogger, } from './telemetry/CustomerTelemetryLogger';
18
- export type { ICustomerTelemetryLogger } from './telemetry/CustomerTelemetryLogger';
17
+ export { configureCustomEventsLogger, getCustomEventsLogger, } from './telemetry/CustomEventsLogger';
18
+ export type { ICustomEventsLogger } from './telemetry/CustomEventsLogger';
19
19
  export type { ITelemetryProvider, LoggerConfig, OneDsTelemetryProviderConfig, ApplicationInsightsTelemetryProviderConfig, PropertyColumnMap, TelemetryEnvelope, TelemetryEvent, TelemetryLocation, TelemetrySeverity, UserIdentity, } from './telemetry/TelemetryTypes';
20
20
  export { ScenarioResults, TelemetryEventNames } from './telemetry/TelemetryTypes';
21
21
  export type { ClusterCategory, Region } from './types/ClusterCategory';
@@ -0,0 +1,4 @@
1
+ import type { ClusterCategory } from '../types/ClusterCategory';
2
+ import type { TelemetryEvent } from './TelemetryTypes';
3
+ export declare function buildAnonymousTelemetryData(event: TelemetryEvent, appName: string, clusterCategory: ClusterCategory): Record<string, unknown>;
4
+ //# sourceMappingURL=AnonymousTelemetry.d.ts.map
@@ -0,0 +1,21 @@
1
+ /*!
2
+ * Copyright (C) Microsoft Corporation. All rights reserved.
3
+ */
4
+ import type { ILogger, ScenarioTracker } from './ILogger';
5
+ export interface ICustomEventsLogger {
6
+ trackEvent(name: string, properties?: Record<string, unknown>): void;
7
+ trackError(name: string, error?: unknown, properties?: Record<string, unknown>): void;
8
+ trackScenario(name: string, properties?: Record<string, unknown>): ScenarioTracker;
9
+ flush(): Promise<void>;
10
+ }
11
+ /**
12
+ * Configures the custom-events singleton. Hosting infrastructure owns
13
+ * this function; application code should use getCustomEventsLogger().
14
+ */
15
+ export declare function configureCustomEventsLogger(logger: ILogger): void;
16
+ /**
17
+ * Returns the app's custom-events logger. It is a safe no-op until the
18
+ * host configures an Application Insights provider.
19
+ */
20
+ export declare function getCustomEventsLogger(): ICustomEventsLogger;
21
+ //# sourceMappingURL=CustomEventsLogger.d.ts.map
@@ -1,8 +1,9 @@
1
1
  /*!
2
2
  * Copyright (C) Microsoft Corporation. All rights reserved.
3
3
  */
4
- import type { ITelemetryProvider, OneDsTelemetryProviderConfig, TelemetryEnvelope, TelemetryEvent, TelemetrySeverity, UserIdentity } from './TelemetryTypes';
4
+ import type { ITelemetryProvider, OneDsTelemetryProviderConfig, TelemetryEnvelope, TelemetryEvent, TelemetryLocation, TelemetrySeverity, UserIdentity } from './TelemetryTypes';
5
5
  export declare class OneDsTelemetryProvider implements ITelemetryProvider {
6
+ private anonymous;
6
7
  private readonly appName;
7
8
  private readonly appVersion;
8
9
  private readonly clientType;
@@ -13,11 +14,15 @@ export declare class OneDsTelemetryProvider implements ITelemetryProvider {
13
14
  private readonly deviceMake;
14
15
  private readonly deviceModel;
15
16
  private readonly deviceType;
17
+ private readonly includeUserIdentity;
16
18
  private readonly osName;
17
19
  private readonly osVersion;
20
+ private readonly postChannel;
18
21
  private readonly userLocale;
19
22
  private readonly userTimeZone;
20
23
  private readonly propertyColumnMap;
24
+ private locationResolution?;
25
+ private telemetryLocation;
21
26
  readonly minSeverity: TelemetrySeverity;
22
27
  private _sessionId;
23
28
  private userIdentity?;
@@ -29,6 +34,8 @@ export declare class OneDsTelemetryProvider implements ITelemetryProvider {
29
34
  */
30
35
  addTelemetryInitializer(initializer: (envelope: TelemetryEnvelope) => void): void;
31
36
  track(event: TelemetryEvent): void;
37
+ resolveTelemetryLocation(telemetryLocation: TelemetryLocation): Promise<void>;
38
+ private applyTelemetryLocation;
32
39
  flush(): Promise<void>;
33
40
  teardown(): Promise<void>;
34
41
  get sessionId(): string;
@@ -72,6 +72,8 @@ export interface OneDsTelemetryProviderConfig {
72
72
  * and pass the result here. Falls back to `'react-native'` if omitted.
73
73
  */
74
74
  deviceId?: string;
75
+ /** Include signed-in object and tenant IDs. Disabled by default. */
76
+ includeUserIdentity?: boolean;
75
77
  /**
76
78
  * 1DS instrumentation key (Aria project ID).
77
79
  * When omitted, resolved automatically from `clusterCategory`.
@@ -81,12 +83,17 @@ export interface OneDsTelemetryProviderConfig {
81
83
  minSeverity?: TelemetrySeverity;
82
84
  /** Data residency location. Default: 'global'. Set to 'eu' for European environments. */
83
85
  telemetryLocation?: TelemetryLocation;
86
+ /**
87
+ * Emit only non-identifying operational fields. Stable IDs, user identity,
88
+ * platform fingerprint fields, defaults, and arbitrary event properties are omitted.
89
+ */
90
+ anonymous?: boolean;
84
91
  commonProperties?: Record<string, string>;
85
92
  propertyColumnMap?: PropertyColumnMap;
86
93
  channelConfig?: Record<string, unknown>;
87
94
  }
88
95
  export interface ApplicationInsightsTelemetryProviderConfig {
89
- /** Connection string for the C1-owned workspace-based Application Insights resource. */
96
+ /** Connection string for the customer-owned workspace-based Application Insights resource. */
90
97
  connectionString: string;
91
98
  /** Stable generated-app identifier added to every telemetry item. */
92
99
  appId: string;
@@ -7,7 +7,8 @@ import type { TelemetryLocation } from './TelemetryTypes';
7
7
  * environment `location` string (`environment.properties.location`).
8
8
  * Returns `'eu'` when the location maps to the EU data boundary, routing
9
9
  * telemetry to `eu-mobile.events.data.microsoft.com` instead of the global
10
- * US collector.
10
+ * US collector. Missing or blank locations fail closed to the EU collector so
11
+ * telemetry emitted before the environment is known does not leave the EUDB.
11
12
  *
12
13
  * Mirrors the CLI's detection in `CliLogger.ts`:
13
14
  * ```
@@ -21,6 +22,12 @@ import type { TelemetryLocation } from './TelemetryTypes';
21
22
  * resolveTelemetryLocation('unitedkingdom') // → 'eu'
22
23
  * resolveTelemetryLocation('italy') // → 'eu'
23
24
  * resolveTelemetryLocation('unitedstates') // → 'global'
25
+ * resolveTelemetryLocation() // → 'eu'
24
26
  */
25
27
  export declare function resolveTelemetryLocation(input?: string): TelemetryLocation;
28
+ /** Resolve a Dataverse Global Discovery `Instance.Region` code. */
29
+ export declare function resolveTelemetryLocationFromDataverseRegion(input?: string): TelemetryLocation;
30
+ export declare function tryResolveTelemetryLocationFromDataverseRegion(input?: string): TelemetryLocation | undefined;
31
+ /** Resolve launch metadata, falling back from BAP location to cluster geography. */
32
+ export declare function tryResolveTelemetryLocationFromEnvironment(location?: string, clusterGeoShortName?: string): TelemetryLocation | undefined;
26
33
  //# sourceMappingURL=resolveTelemetryLocation.d.ts.map
@@ -2,9 +2,9 @@
2
2
  * Copyright (C) Microsoft Corporation. All rights reserved.
3
3
  */
4
4
  /**
5
- * Converts an unknown thrown value to a string suitable for telemetry.
6
- * PII (email addresses, private IPv4 addresses) is redacted before the
7
- * string is returned.
5
+ * Classifies an unknown thrown value without exporting its message, stack, or
6
+ * serialized contents. Error prose is not a safe telemetry contract because
7
+ * upstream services may include customer data or credentials in it.
8
8
  */
9
9
  export declare function stringifyError(error: unknown): string;
10
10
  //# sourceMappingURL=stringifyError.d.ts.map
@@ -2,18 +2,9 @@
2
2
  * Copyright (C) Microsoft Corporation. All rights reserved.
3
3
  */
4
4
  /**
5
- * Returns a stable device identifier, preferring platform-native IDs that
6
- * survive app reinstalls:
7
- *
8
- * - **iOS**: `getIosIdForVendorAsync()` (IDFV) — stable while ≥1 app from the
9
- * same vendor bundle prefix is installed. Resets only when ALL vendor apps
10
- * are removed.
11
- * - **Android**: `getAndroidId()` (SSAID) — scoped to the app signing key on
12
- * Android 8+; survives reinstalls as long as the signing key is unchanged.
13
- *
14
- * If the platform API returns null (rare edge cases: first boot, some emulators)
15
- * the function falls back to a UUID persisted in `expo-secure-store`, which on
16
- * iOS survives reinstalls via the Keychain and on Android is per-install only.
5
+ * Returns a random app-scoped telemetry identifier. It does not use IDFV,
6
+ * SSAID, or another platform device identifier, and can be rotated with
7
+ * `resetDeviceId()` for deletion and opt-out workflows.
17
8
  *
18
9
  * Pass the resolved value to `OneDsTelemetryProviderConfig.deviceId` at startup.
19
10
  *
@@ -26,4 +17,6 @@
26
17
  * ```
27
18
  */
28
19
  export declare function resolveDeviceId(): Promise<string>;
20
+ /** Deletes the app-scoped telemetry identifier so the next resolution rotates it. */
21
+ export declare function resetDeviceId(): Promise<void>;
29
22
  //# sourceMappingURL=DeviceIdUtils.d.ts.map
@@ -7,15 +7,15 @@ export type { ILogger, ScenarioTracker } from './telemetry/ILogger.js';
7
7
  export { Logger } from './telemetry/Logger.js';
8
8
  export { OneDsTelemetryProvider } from './telemetry/OneDsTelemetryProvider.js';
9
9
  export { ApplicationInsightsTelemetryProvider } from './telemetry/ApplicationInsightsTelemetryProvider.js';
10
- export { resolveTelemetryLocation } from './telemetry/resolveTelemetryLocation.js';
10
+ export { resolveTelemetryLocation, resolveTelemetryLocationFromDataverseRegion, tryResolveTelemetryLocationFromDataverseRegion, tryResolveTelemetryLocationFromEnvironment, } from './telemetry/resolveTelemetryLocation.js';
11
11
  export { stringifyError } from './telemetry/stringifyError.js';
12
12
  export { sanitizeErrorString, sanitizeUrl, sanitizeProperties } from './telemetry/TelemetrySanitizer.js';
13
13
  export { suppressKnownWarnings } from './telemetry/suppressKnownWarnings.js';
14
14
  export { HttpClient, getHttpCorrelationProperties } from './http/HttpClient.js';
15
- export { resolveDeviceId } from './utils/DeviceIdUtils.js';
15
+ export { resetDeviceId, resolveDeviceId } from './utils/DeviceIdUtils.js';
16
16
  export { configureAppLogger, getAppLogger } from './telemetry/AppLogger.js';
17
- export { configureCustomerTelemetryLogger, getCustomerTelemetryLogger, } from './telemetry/CustomerTelemetryLogger.js';
18
- export type { ICustomerTelemetryLogger } from './telemetry/CustomerTelemetryLogger.js';
17
+ export { configureCustomEventsLogger, getCustomEventsLogger, } from './telemetry/CustomEventsLogger.js';
18
+ export type { ICustomEventsLogger } from './telemetry/CustomEventsLogger.js';
19
19
  export type { ITelemetryProvider, LoggerConfig, OneDsTelemetryProviderConfig, ApplicationInsightsTelemetryProviderConfig, PropertyColumnMap, TelemetryEnvelope, TelemetryEvent, TelemetryLocation, TelemetrySeverity, UserIdentity, } from './telemetry/TelemetryTypes.js';
20
20
  export { ScenarioResults, TelemetryEventNames } from './telemetry/TelemetryTypes.js';
21
21
  export type { ClusterCategory, Region } from './types/ClusterCategory.js';
@@ -0,0 +1,4 @@
1
+ import type { ClusterCategory } from '../types/ClusterCategory.js';
2
+ import type { TelemetryEvent } from './TelemetryTypes.js';
3
+ export declare function buildAnonymousTelemetryData(event: TelemetryEvent, appName: string, clusterCategory: ClusterCategory): Record<string, unknown>;
4
+ //# sourceMappingURL=AnonymousTelemetry.d.ts.map
@@ -0,0 +1,21 @@
1
+ /*!
2
+ * Copyright (C) Microsoft Corporation. All rights reserved.
3
+ */
4
+ import type { ILogger, ScenarioTracker } from './ILogger.js';
5
+ export interface ICustomEventsLogger {
6
+ trackEvent(name: string, properties?: Record<string, unknown>): void;
7
+ trackError(name: string, error?: unknown, properties?: Record<string, unknown>): void;
8
+ trackScenario(name: string, properties?: Record<string, unknown>): ScenarioTracker;
9
+ flush(): Promise<void>;
10
+ }
11
+ /**
12
+ * Configures the custom-events singleton. Hosting infrastructure owns
13
+ * this function; application code should use getCustomEventsLogger().
14
+ */
15
+ export declare function configureCustomEventsLogger(logger: ILogger): void;
16
+ /**
17
+ * Returns the app's custom-events logger. It is a safe no-op until the
18
+ * host configures an Application Insights provider.
19
+ */
20
+ export declare function getCustomEventsLogger(): ICustomEventsLogger;
21
+ //# sourceMappingURL=CustomEventsLogger.d.ts.map
@@ -1,8 +1,9 @@
1
1
  /*!
2
2
  * Copyright (C) Microsoft Corporation. All rights reserved.
3
3
  */
4
- import type { ITelemetryProvider, OneDsTelemetryProviderConfig, TelemetryEnvelope, TelemetryEvent, TelemetrySeverity, UserIdentity } from './TelemetryTypes.js';
4
+ import type { ITelemetryProvider, OneDsTelemetryProviderConfig, TelemetryEnvelope, TelemetryEvent, TelemetryLocation, TelemetrySeverity, UserIdentity } from './TelemetryTypes.js';
5
5
  export declare class OneDsTelemetryProvider implements ITelemetryProvider {
6
+ private anonymous;
6
7
  private readonly appName;
7
8
  private readonly appVersion;
8
9
  private readonly clientType;
@@ -13,11 +14,15 @@ export declare class OneDsTelemetryProvider implements ITelemetryProvider {
13
14
  private readonly deviceMake;
14
15
  private readonly deviceModel;
15
16
  private readonly deviceType;
17
+ private readonly includeUserIdentity;
16
18
  private readonly osName;
17
19
  private readonly osVersion;
20
+ private readonly postChannel;
18
21
  private readonly userLocale;
19
22
  private readonly userTimeZone;
20
23
  private readonly propertyColumnMap;
24
+ private locationResolution?;
25
+ private telemetryLocation;
21
26
  readonly minSeverity: TelemetrySeverity;
22
27
  private _sessionId;
23
28
  private userIdentity?;
@@ -29,6 +34,8 @@ export declare class OneDsTelemetryProvider implements ITelemetryProvider {
29
34
  */
30
35
  addTelemetryInitializer(initializer: (envelope: TelemetryEnvelope) => void): void;
31
36
  track(event: TelemetryEvent): void;
37
+ resolveTelemetryLocation(telemetryLocation: TelemetryLocation): Promise<void>;
38
+ private applyTelemetryLocation;
32
39
  flush(): Promise<void>;
33
40
  teardown(): Promise<void>;
34
41
  get sessionId(): string;
@@ -72,6 +72,8 @@ export interface OneDsTelemetryProviderConfig {
72
72
  * and pass the result here. Falls back to `'react-native'` if omitted.
73
73
  */
74
74
  deviceId?: string;
75
+ /** Include signed-in object and tenant IDs. Disabled by default. */
76
+ includeUserIdentity?: boolean;
75
77
  /**
76
78
  * 1DS instrumentation key (Aria project ID).
77
79
  * When omitted, resolved automatically from `clusterCategory`.
@@ -81,12 +83,17 @@ export interface OneDsTelemetryProviderConfig {
81
83
  minSeverity?: TelemetrySeverity;
82
84
  /** Data residency location. Default: 'global'. Set to 'eu' for European environments. */
83
85
  telemetryLocation?: TelemetryLocation;
86
+ /**
87
+ * Emit only non-identifying operational fields. Stable IDs, user identity,
88
+ * platform fingerprint fields, defaults, and arbitrary event properties are omitted.
89
+ */
90
+ anonymous?: boolean;
84
91
  commonProperties?: Record<string, string>;
85
92
  propertyColumnMap?: PropertyColumnMap;
86
93
  channelConfig?: Record<string, unknown>;
87
94
  }
88
95
  export interface ApplicationInsightsTelemetryProviderConfig {
89
- /** Connection string for the C1-owned workspace-based Application Insights resource. */
96
+ /** Connection string for the customer-owned workspace-based Application Insights resource. */
90
97
  connectionString: string;
91
98
  /** Stable generated-app identifier added to every telemetry item. */
92
99
  appId: string;
@@ -7,7 +7,8 @@ import type { TelemetryLocation } from './TelemetryTypes.js';
7
7
  * environment `location` string (`environment.properties.location`).
8
8
  * Returns `'eu'` when the location maps to the EU data boundary, routing
9
9
  * telemetry to `eu-mobile.events.data.microsoft.com` instead of the global
10
- * US collector.
10
+ * US collector. Missing or blank locations fail closed to the EU collector so
11
+ * telemetry emitted before the environment is known does not leave the EUDB.
11
12
  *
12
13
  * Mirrors the CLI's detection in `CliLogger.ts`:
13
14
  * ```
@@ -21,6 +22,12 @@ import type { TelemetryLocation } from './TelemetryTypes.js';
21
22
  * resolveTelemetryLocation('unitedkingdom') // → 'eu'
22
23
  * resolveTelemetryLocation('italy') // → 'eu'
23
24
  * resolveTelemetryLocation('unitedstates') // → 'global'
25
+ * resolveTelemetryLocation() // → 'eu'
24
26
  */
25
27
  export declare function resolveTelemetryLocation(input?: string): TelemetryLocation;
28
+ /** Resolve a Dataverse Global Discovery `Instance.Region` code. */
29
+ export declare function resolveTelemetryLocationFromDataverseRegion(input?: string): TelemetryLocation;
30
+ export declare function tryResolveTelemetryLocationFromDataverseRegion(input?: string): TelemetryLocation | undefined;
31
+ /** Resolve launch metadata, falling back from BAP location to cluster geography. */
32
+ export declare function tryResolveTelemetryLocationFromEnvironment(location?: string, clusterGeoShortName?: string): TelemetryLocation | undefined;
26
33
  //# sourceMappingURL=resolveTelemetryLocation.d.ts.map