@microsoft/power-apps-native-common 0.1.8

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 (72) hide show
  1. package/LICENSE +112 -0
  2. package/README.md +15 -0
  3. package/lib/NOTICE.txt +179 -0
  4. package/lib/commonjs/TelemetryTypes.js +29 -0
  5. package/lib/commonjs/index.js +112 -0
  6. package/lib/commonjs/package.json +1 -0
  7. package/lib/commonjs/telemetry/AppLogger.js +49 -0
  8. package/lib/commonjs/telemetry/ConsoleAdapter.js +64 -0
  9. package/lib/commonjs/telemetry/ILogger.js +5 -0
  10. package/lib/commonjs/telemetry/Logger.js +151 -0
  11. package/lib/commonjs/telemetry/OneDsTelemetryProvider.js +276 -0
  12. package/lib/commonjs/telemetry/TelemetrySanitizer.js +100 -0
  13. package/lib/commonjs/telemetry/TelemetryTypes.js +29 -0
  14. package/lib/commonjs/telemetry/resolveTelemetryLocation.js +42 -0
  15. package/lib/commonjs/telemetry/stringifyError.js +31 -0
  16. package/lib/commonjs/telemetry/suppressKnownWarnings.js +28 -0
  17. package/lib/commonjs/types/ClusterCategory.js +54 -0
  18. package/lib/commonjs/utils/DeviceIdUtils.js +66 -0
  19. package/lib/commonjs/utils/GuidUtils.js +23 -0
  20. package/lib/commonjs/utils/PlatformInfoUtils.js +60 -0
  21. package/lib/module/TelemetryTypes.js +25 -0
  22. package/lib/module/index.js +18 -0
  23. package/lib/module/package.json +1 -0
  24. package/lib/module/telemetry/AppLogger.js +44 -0
  25. package/lib/module/telemetry/ConsoleAdapter.js +59 -0
  26. package/lib/module/telemetry/ILogger.js +3 -0
  27. package/lib/module/telemetry/Logger.js +146 -0
  28. package/lib/module/telemetry/OneDsTelemetryProvider.js +271 -0
  29. package/lib/module/telemetry/TelemetrySanitizer.js +94 -0
  30. package/lib/module/telemetry/TelemetryTypes.js +25 -0
  31. package/lib/module/telemetry/resolveTelemetryLocation.js +38 -0
  32. package/lib/module/telemetry/stringifyError.js +28 -0
  33. package/lib/module/telemetry/suppressKnownWarnings.js +25 -0
  34. package/lib/module/types/ClusterCategory.js +49 -0
  35. package/lib/module/utils/DeviceIdUtils.js +62 -0
  36. package/lib/module/utils/GuidUtils.js +19 -0
  37. package/lib/module/utils/PlatformInfoUtils.js +55 -0
  38. package/lib/typescript/commonjs/TelemetryTypes.d.ts +88 -0
  39. package/lib/typescript/commonjs/index.d.ts +19 -0
  40. package/lib/typescript/commonjs/package.json +1 -0
  41. package/lib/typescript/commonjs/telemetry/AppLogger.d.ts +35 -0
  42. package/lib/typescript/commonjs/telemetry/ConsoleAdapter.d.ts +24 -0
  43. package/lib/typescript/commonjs/telemetry/ILogger.d.ts +45 -0
  44. package/lib/typescript/commonjs/telemetry/Logger.d.ts +28 -0
  45. package/lib/typescript/commonjs/telemetry/OneDsTelemetryProvider.d.ts +39 -0
  46. package/lib/typescript/commonjs/telemetry/TelemetrySanitizer.d.ts +21 -0
  47. package/lib/typescript/commonjs/telemetry/TelemetryTypes.d.ts +88 -0
  48. package/lib/typescript/commonjs/telemetry/resolveTelemetryLocation.d.ts +26 -0
  49. package/lib/typescript/commonjs/telemetry/stringifyError.d.ts +10 -0
  50. package/lib/typescript/commonjs/telemetry/suppressKnownWarnings.d.ts +19 -0
  51. package/lib/typescript/commonjs/types/ClusterCategory.d.ts +37 -0
  52. package/lib/typescript/commonjs/utils/DeviceIdUtils.d.ts +29 -0
  53. package/lib/typescript/commonjs/utils/GuidUtils.d.ts +11 -0
  54. package/lib/typescript/commonjs/utils/PlatformInfoUtils.d.ts +33 -0
  55. package/lib/typescript/module/TelemetryTypes.d.ts +88 -0
  56. package/lib/typescript/module/index.d.ts +19 -0
  57. package/lib/typescript/module/package.json +1 -0
  58. package/lib/typescript/module/telemetry/AppLogger.d.ts +35 -0
  59. package/lib/typescript/module/telemetry/ConsoleAdapter.d.ts +24 -0
  60. package/lib/typescript/module/telemetry/ILogger.d.ts +45 -0
  61. package/lib/typescript/module/telemetry/Logger.d.ts +28 -0
  62. package/lib/typescript/module/telemetry/OneDsTelemetryProvider.d.ts +39 -0
  63. package/lib/typescript/module/telemetry/TelemetrySanitizer.d.ts +21 -0
  64. package/lib/typescript/module/telemetry/TelemetryTypes.d.ts +88 -0
  65. package/lib/typescript/module/telemetry/resolveTelemetryLocation.d.ts +26 -0
  66. package/lib/typescript/module/telemetry/stringifyError.d.ts +10 -0
  67. package/lib/typescript/module/telemetry/suppressKnownWarnings.d.ts +19 -0
  68. package/lib/typescript/module/types/ClusterCategory.d.ts +37 -0
  69. package/lib/typescript/module/utils/DeviceIdUtils.d.ts +29 -0
  70. package/lib/typescript/module/utils/GuidUtils.d.ts +11 -0
  71. package/lib/typescript/module/utils/PlatformInfoUtils.d.ts +33 -0
  72. package/package.json +83 -0
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Logger = void 0;
7
+ var _GuidUtils = require("../utils/GuidUtils.js");
8
+ var _stringifyError = require("./stringifyError.js");
9
+ var _TelemetrySanitizer = require("./TelemetrySanitizer.js");
10
+ var _TelemetryTypes = require("./TelemetryTypes.js");
11
+ /*!
12
+ * Copyright (C) Microsoft Corporation. All rights reserved.
13
+ */
14
+
15
+ const severityOrder = {
16
+ verbose: 0,
17
+ info: 1,
18
+ warning: 2,
19
+ error: 3
20
+ };
21
+
22
+ /**
23
+ * Structured logger with canonical event names, severity filtering,
24
+ * sequence numbering, and scenario tracking.
25
+ * Supports multiple telemetry adapters; no-op safe when none are given.
26
+ */
27
+ class Logger {
28
+ sequence = 0;
29
+ constructor(config) {
30
+ this.providers = config?.providers ?? [];
31
+ // Use the least-restrictive minSeverity among all providers, falling back to 'verbose'.
32
+ if (this.providers.length === 0) {
33
+ this.minSeverity = 'verbose';
34
+ } else {
35
+ const order = severityOrder;
36
+ this.minSeverity = this.providers.reduce((min, p) => {
37
+ const pSev = p.minSeverity ?? 'verbose';
38
+ return order[pSev] < order[min] ? pSev : min;
39
+ }, 'error');
40
+ }
41
+ }
42
+ trackActivityEvent(name, properties, eventName) {
43
+ this.emit('info', eventName ?? _TelemetryTypes.TelemetryEventNames.Activity, name, properties);
44
+ }
45
+ trackVerboseEvent(name, properties, eventName) {
46
+ this.emit('verbose', eventName ?? _TelemetryTypes.TelemetryEventNames.Activity, name, properties);
47
+ }
48
+ trackErrorEvent(name, properties, eventName) {
49
+ this.emit('error', eventName ?? _TelemetryTypes.TelemetryEventNames.Error, name, properties);
50
+ }
51
+ trackScenario(name, properties) {
52
+ const startTime = typeof performance !== 'undefined' ? performance.now() : Date.now();
53
+ const scenarioGuid = (0, _GuidUtils.generateGuid)();
54
+ const scenarioProps = {
55
+ ...properties,
56
+ scenarioName: name,
57
+ scenarioGuid
58
+ };
59
+ this.emit('info', _TelemetryTypes.TelemetryEventNames.StartScenario, name, scenarioProps);
60
+ return {
61
+ complete: extraProps => {
62
+ const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
63
+ this.emit('info', _TelemetryTypes.TelemetryEventNames.EndScenario, name, {
64
+ ...scenarioProps,
65
+ ...extraProps,
66
+ scenarioResult: _TelemetryTypes.ScenarioResults.Success,
67
+ duration
68
+ });
69
+ },
70
+ completeWithError: extraProps => {
71
+ const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
72
+ this.emit('warning', _TelemetryTypes.TelemetryEventNames.EndScenario, name, {
73
+ ...scenarioProps,
74
+ ...extraProps,
75
+ scenarioResult: _TelemetryTypes.ScenarioResults.SuccessWithErrors,
76
+ duration
77
+ });
78
+ },
79
+ fail: (error, extraProps) => {
80
+ const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
81
+ this.emit('error', _TelemetryTypes.TelemetryEventNames.EndScenario, name, {
82
+ ...scenarioProps,
83
+ ...extraProps,
84
+ scenarioResult: _TelemetryTypes.ScenarioResults.Failed,
85
+ error: error !== undefined ? (0, _stringifyError.stringifyError)(error) : undefined,
86
+ duration
87
+ });
88
+ }
89
+ };
90
+ }
91
+ setDefaultProperty(name, value) {
92
+ for (const p of this.providers) p.setDefaultProperty(name, value);
93
+ }
94
+ identifyUser(identity) {
95
+ for (const p of this.providers) p.identifyUser(identity);
96
+ }
97
+ get sessionId() {
98
+ return this.providers[0]?.sessionId;
99
+ }
100
+ set sessionId(value) {
101
+ for (const p of this.providers) p.sessionId = value;
102
+ }
103
+ async flush() {
104
+ await Promise.all(this.providers.map(p => p.flush()));
105
+ }
106
+ shouldLog(severity) {
107
+ return severityOrder[severity] >= severityOrder[this.minSeverity];
108
+ }
109
+ emit(severity, eventName, operationName, properties) {
110
+ if (this.providers.length === 0) {
111
+ return;
112
+ }
113
+ if (!this.shouldLog(severity)) {
114
+ return;
115
+ }
116
+ const flatProps = flattenProperties(properties);
117
+ flatProps.operationName = operationName;
118
+ const event = {
119
+ eventName,
120
+ timestamp: new Date().toISOString(),
121
+ severity,
122
+ sequenceNumber: ++this.sequence,
123
+ duration: typeof flatProps.duration === 'number' ? flatProps.duration : undefined,
124
+ properties: flatProps
125
+ };
126
+ for (const p of this.providers) {
127
+ // Per-adapter severity filtering
128
+ const adapterMin = p.minSeverity ?? 'verbose';
129
+ if (severityOrder[severity] >= severityOrder[adapterMin]) {
130
+ p.track(event);
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ /** Convert Record<string, unknown> to Record<string, string | number | boolean> by JSON-stringifying non-primitives. Applies PII sanitization before flattening. */
137
+ exports.Logger = Logger;
138
+ function flattenProperties(properties) {
139
+ const sanitized = properties ? (0, _TelemetrySanitizer.sanitizeProperties)(properties) : undefined;
140
+ const result = {};
141
+ if (!sanitized) return result;
142
+ for (const [key, value] of Object.entries(sanitized)) {
143
+ if (value === undefined) continue;
144
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
145
+ result[key] = value;
146
+ } else {
147
+ result[key] = JSON.stringify(value);
148
+ }
149
+ }
150
+ return result;
151
+ }
@@ -0,0 +1,276 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.OneDsTelemetryProvider = void 0;
7
+ var _applicationinsightsCoreJs = require("@microsoft/applicationinsights-core-js");
8
+ var _dsPostJs = require("@microsoft/1ds-post-js");
9
+ var _GuidUtils = require("../utils/GuidUtils.js");
10
+ var _PlatformInfoUtils = require("../utils/PlatformInfoUtils.js");
11
+ /*!
12
+ * Copyright (C) Microsoft Corporation. All rights reserved.
13
+ */
14
+
15
+ /** 1DS Aria project IDs shared by the webplayer and CLI. */
16
+ const AriaProjectIds = {
17
+ Production: '5c3a61f48d7c4522912765ae7465ab5c-fb3d6606-fe59-4d6b-9bb1-5e993d889672-7138',
18
+ NonProduction: '3fb21f3df5c44380bf452fd710f4d50c-0e3f82aa-6d27-41d8-b727-c96b28f99992-7504',
19
+ Mooncake: '1c1d139788f74386bd95e752dd781371-04b4424b-e5c1-46ae-8312-28e9fa5832c0-6923',
20
+ GccModerate: '0d7685a948a140789ac92933d3dc2d87-2dd0c1ce-8f10-41f0-a70a-2f9e51a851c8-6823',
21
+ GccHigh: 'd31229fb23b0406790b9332e5f465dfc-a6b19a0e-170d-4570-bda5-f35e3668e162-7067',
22
+ DoD: '41cc10dad35043adbcdace2896484ab4-5ebbc1d6-04c9-486d-a6b6-e5963cd778da-7542'
23
+ };
24
+
25
+ /**
26
+ * Default property-to-column promotion map matching the webplayer convention.
27
+ * Properties matching these keys are promoted to top-level data columns;
28
+ * the rest go into the customDimensions JSON blob.
29
+ */
30
+ const DefaultPropertyToColumn = {
31
+ apiId: 'apiId',
32
+ appSequenceNumber: 'appSequenceNumber',
33
+ duration: 'duration',
34
+ environmentId: 'environmentId',
35
+ httpMethod: 'httpMethod',
36
+ httpStatus: 'httpStatus',
37
+ operationName: 'operation_Name',
38
+ playerAppId: 'playerAppId',
39
+ scenarioGuid: 'scenarioGuid',
40
+ scenarioName: 'scenarioName',
41
+ scenarioResult: 'scenarioResult',
42
+ serverLocation: 'serverLocation',
43
+ url: 'url',
44
+ webPlayerUrl: 'webPlayerUrl'
45
+ };
46
+ function resolveInstrumentationKey(clusterCategory) {
47
+ switch (clusterCategory) {
48
+ case 'prod':
49
+ case 'firstrelease':
50
+ case 'ex':
51
+ case 'rx':
52
+ return AriaProjectIds.Production;
53
+ case 'mooncake':
54
+ return AriaProjectIds.Mooncake;
55
+ case 'gov':
56
+ return AriaProjectIds.GccModerate;
57
+ case 'high':
58
+ return AriaProjectIds.GccHigh;
59
+ case 'dod':
60
+ return AriaProjectIds.DoD;
61
+ default:
62
+ return AriaProjectIds.NonProduction;
63
+ }
64
+ }
65
+ function resolveCollectorUrl(clusterCategory, telemetryLocation = 'global') {
66
+ switch (clusterCategory) {
67
+ case 'mooncake':
68
+ return 'https://collector.azure.cn/OneCollector/1.0/';
69
+ case 'gov':
70
+ case 'high':
71
+ return 'https://tb.events.data.microsoft.com/OneCollector/1.0/';
72
+ case 'dod':
73
+ return 'https://pf.events.data.microsoft.com/OneCollector/1.0/';
74
+ case 'ex':
75
+ return 'https://collector.azure.eaglex.ic.gov/OneCollector/1.0/';
76
+ case 'rx':
77
+ return 'https://collector.azure.microsoft.scloud/OneCollector/1.0/';
78
+ default:
79
+ if (telemetryLocation === 'eu') {
80
+ return 'https://eu-mobile.events.data.microsoft.com/OneCollector/1.0/';
81
+ }
82
+ return 'https://us-mobile.events.data.microsoft.com/OneCollector/1.0/';
83
+ }
84
+ }
85
+ function resolveAppName(clusterCategory) {
86
+ switch (clusterCategory) {
87
+ case 'local':
88
+ case 'dev':
89
+ case 'test':
90
+ case 'preprod':
91
+ return 'powerappsclientnonprod';
92
+ default:
93
+ return 'powerappsclient';
94
+ }
95
+ }
96
+ class OneDsTelemetryProvider {
97
+ defaultProperties = {};
98
+ constructor(config) {
99
+ this._sessionId = (0, _GuidUtils.generateGuid)();
100
+ this.appName = resolveAppName(config.clusterCategory);
101
+ this.appVersion = config.appVersion ?? '';
102
+ this.clientType = config.clientType;
103
+ this.clusterCategory = config.clusterCategory;
104
+ this.deviceId = config.deviceId ?? 'react-native';
105
+ this.minSeverity = config.minSeverity ?? 'info';
106
+ const {
107
+ osName,
108
+ osVersion,
109
+ deviceMake,
110
+ deviceModel,
111
+ deviceType,
112
+ userLocale,
113
+ userTimeZone
114
+ } = (0, _PlatformInfoUtils.resolvePlatformInfo)();
115
+ this.osName = osName;
116
+ this.osVersion = osVersion;
117
+ this.deviceMake = deviceMake;
118
+ this.deviceModel = deviceModel;
119
+ this.deviceType = deviceType;
120
+ this.userLocale = userLocale;
121
+ this.userTimeZone = userTimeZone;
122
+
123
+ // Merge default promotion map with consumer overrides (overrides win)
124
+ this.propertyColumnMap = {
125
+ ...DefaultPropertyToColumn,
126
+ ...config.propertyColumnMap
127
+ };
128
+ if (config.commonProperties) {
129
+ Object.assign(this.defaultProperties, config.commonProperties);
130
+ }
131
+ const postChannel = new _dsPostJs.PostChannel();
132
+ const instrumentationKey = config.instrumentationKey ?? resolveInstrumentationKey(config.clusterCategory);
133
+ const collectorUrl = resolveCollectorUrl(config.clusterCategory, config.telemetryLocation);
134
+ const coreConfig = {
135
+ instrumentationKey,
136
+ channels: [[postChannel]]
137
+ };
138
+ coreConfig.extensionConfig = {
139
+ [postChannel.identifier]: {
140
+ // Override endpoint explicitly — PostChannel reads overrideEndpointUrl
141
+ // from its own extensionConfig, not from coreConfig.endpointUrl.
142
+ overrideEndpointUrl: collectorUrl,
143
+ // Use React Native's fetch instead of PostChannel's XHR path, which
144
+ // uses browser-specific CORS and Beacon APIs not available in RN.
145
+ httpXHROverride: {
146
+ sendPOST: (payload, oncomplete) => {
147
+ const headers = {
148
+ ...(payload.headers ?? {})
149
+ };
150
+ fetch(payload.urlString, {
151
+ method: 'POST',
152
+ headers,
153
+ body: typeof payload.data === 'string' ? payload.data : payload.data
154
+ }).then(async r => {
155
+ oncomplete(r.status, {});
156
+ }).catch(err => {
157
+ console.warn('[OneDsTelemetryProvider] sendPOST FAILED', err);
158
+ oncomplete(0, {});
159
+ });
160
+ }
161
+ },
162
+ ...config.channelConfig
163
+ }
164
+ };
165
+ this.core = new _applicationinsightsCoreJs.AppInsightsCore();
166
+ this.core.initialize(coreConfig, []);
167
+ this.core.addTelemetryInitializer(envelope => {
168
+ const ext = envelope.ext = envelope.ext ?? {};
169
+ const utc = ext['utc'] = ext['utc'] ?? {};
170
+ utc['eventFlags'] = (utc['eventFlags'] || 0) | 0x100000;
171
+ const app = ext['app'] = ext['app'] ?? {};
172
+ app['sesId'] = this._sessionId;
173
+ if (this.appVersion) app['ver'] = this.appVersion; // → AppInfo_Version
174
+ const os = ext['os'] = ext['os'] ?? {};
175
+ os['name'] = this.osName; // → DeviceInfo_OsName
176
+ os['ver'] = this.osVersion; // → DeviceInfo_OsVersion
177
+ // ext.device.make/model → DeviceInfo_Make / DeviceInfo_Model
178
+ // Note: localId is intentionally omitted — it requires a strict UUID format
179
+ // and our device_Id column in data carries the same info once resolved.
180
+ const device = ext['device'] = ext['device'] ?? {};
181
+ if (this.deviceMake) device['make'] = this.deviceMake;
182
+ if (this.deviceModel) device['model'] = this.deviceModel;
183
+ if (this.deviceType) device['deviceClass'] = this.deviceType;
184
+ });
185
+ }
186
+
187
+ /**
188
+ * Register a telemetry initializer that runs on every envelope before send.
189
+ * Use this to add Part A Common Schema extensions (ext.app, ext.web, ext.os, etc.)
190
+ * that require platform-specific APIs (e.g. browser info, OS info).
191
+ */
192
+ addTelemetryInitializer(initializer) {
193
+ this.core.addTelemetryInitializer(initializer);
194
+ }
195
+ track(event) {
196
+ const allProperties = {
197
+ ...this.defaultProperties,
198
+ ...event.properties
199
+ };
200
+
201
+ // Build data object with fixed columns matching webplayer convention
202
+ const data = {
203
+ app_Name: this.appName,
204
+ clientType: this.clientType,
205
+ clusterCategory: this.clusterCategory,
206
+ device_Id: this.deviceId,
207
+ DeviceInfo_Make: this.deviceMake,
208
+ ...(this.deviceModel ? {
209
+ DeviceInfo_Model: this.deviceModel
210
+ } : {}),
211
+ userLocale: this.userLocale || undefined,
212
+ userTimeZone: this.userTimeZone || undefined,
213
+ event_Name: event.eventName,
214
+ sequenceNumber: event.sequenceNumber,
215
+ session_Id: this._sessionId,
216
+ severity: event.severity,
217
+ timestamp: event.timestamp
218
+ };
219
+
220
+ // User identity promoted to top-level columns directly
221
+ if (this.userIdentity) {
222
+ data.objectId = this.userIdentity.objectId;
223
+ data.tenantId = this.userIdentity.tenantId;
224
+ }
225
+ if (event.duration !== undefined) {
226
+ data.duration = event.duration;
227
+ }
228
+
229
+ // Promote properties matching the column map to top-level data fields
230
+ // Properties are kept in allProperties so they also appear in customDimensions
231
+ for (const [propKey, columnName] of Object.entries(this.propertyColumnMap)) {
232
+ if (propKey in allProperties) {
233
+ data[columnName] = allProperties[propKey];
234
+ }
235
+ }
236
+
237
+ // Serialize remaining properties as customDimensions
238
+ data.customDimensions = JSON.stringify(allProperties);
239
+ const item = {
240
+ // 'event' routes all events to the Kusto `event` table.
241
+ // The actual event name is stored in data.event_Name.
242
+ name: 'event',
243
+ time: event.timestamp,
244
+ baseType: 'custom',
245
+ data
246
+ };
247
+ this.core.track(item);
248
+ }
249
+ flush() {
250
+ return new Promise(resolve => {
251
+ this.core.flush(true, () => {
252
+ resolve();
253
+ });
254
+ });
255
+ }
256
+ teardown() {
257
+ return new Promise(resolve => {
258
+ this.core.unload(true, () => {
259
+ resolve();
260
+ });
261
+ });
262
+ }
263
+ get sessionId() {
264
+ return this._sessionId;
265
+ }
266
+ set sessionId(value) {
267
+ this._sessionId = value;
268
+ }
269
+ identifyUser(identity) {
270
+ this.userIdentity = identity;
271
+ }
272
+ setDefaultProperty(name, value) {
273
+ this.defaultProperties[name] = value;
274
+ }
275
+ }
276
+ exports.OneDsTelemetryProvider = OneDsTelemetryProvider;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sanitizeErrorString = sanitizeErrorString;
7
+ exports.sanitizeProperties = sanitizeProperties;
8
+ exports.sanitizeUrl = sanitizeUrl;
9
+ /*!
10
+ * Copyright (C) Microsoft Corporation. All rights reserved.
11
+ */
12
+
13
+ /**
14
+ * Utilities for stripping PII and credentials from strings and property bags
15
+ * before they enter telemetry. All functions are pure and synchronous — safe
16
+ * to call on the hot path.
17
+ *
18
+ * Patterns detected (aligned with the CLI's ScrubUtils / CredScan KB):
19
+ * - Email / UPN addresses → '<upn>'
20
+ * - Private IPv4 addresses → '<private-ip>'
21
+ * - URL query strings / fragments → stripped (may carry tokens/user context)
22
+ * - Google API keys (AIza…) → '<credential>'
23
+ * - SAS key sig= parameter → '<credential>'
24
+ * - 256-bit symmetric keys (b64) → '<credential>'
25
+ *
26
+ * Property-bag rules:
27
+ * - Keys matching a PII/credential denylist → value replaced with '<redacted>'
28
+ * - String values run through sanitizeErrorString
29
+ */
30
+
31
+ /** Matches email addresses / UPNs (simplified RFC 5322). */
32
+ const EMAIL_RE = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g;
33
+
34
+ /**
35
+ * Matches private / loopback IPv4 addresses (RFC 1918 + 127.0.0.0/8 +
36
+ * link-local 169.254.0.0/16).
37
+ */
38
+ const PRIVATE_IPV4_RE = /\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3})(:\d+)?\b/g;
39
+
40
+ /**
41
+ * Google API key pattern. Aligned with CredScan KB:
42
+ * https://msazure.visualstudio.com/One/_git/SecEng-CredScan-Core
43
+ */
44
+ const GOOGLE_API_KEY_RE = /AIza[a-z0-9_\-]{35}/gi;
45
+
46
+ /**
47
+ * SAS key sig= parameter. Aligned with CredScan KB (modified for JS):
48
+ * matches `sig=` or `dsas_secret=` followed by ≥8 non-whitespace chars
49
+ * (excluding delimiters that would indicate a false positive).
50
+ */
51
+ const SAS_KEY_SIG_RE = /(?:dsas_secret|sig)=[^#)\(<>\r\n\s'",\\_&]{8}[^#)\(<>\r\n\s'",\\_&]*/gi;
52
+
53
+ /**
54
+ * 256-bit symmetric key in base64 (43 base64url chars + `=` pad).
55
+ * Aligned with CredScan KB SymmKey256 pattern.
56
+ */
57
+ const SYMM_KEY_256_RE = /[a-z0-9/+]{43}=/gi;
58
+
59
+ /**
60
+ * Property key patterns that must never appear as telemetry values.
61
+ * Checked case-insensitively against the full key name.
62
+ */
63
+ const SENSITIVE_KEY_RE = /password|secret|token|credential|auth(?:orization)?|bearer|apikey|api[_-]key|upn|email|username|accesstoken|refreshtoken|idtoken/i;
64
+
65
+ /**
66
+ * Redacts PII and credentials from a string.
67
+ * Safe to use on error messages, URL paths, and arbitrary text.
68
+ */
69
+ function sanitizeErrorString(raw) {
70
+ 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
+ }
72
+
73
+ /**
74
+ * Strips the query string and URL fragment from a URL string, then redacts any
75
+ * PII/credentials in the remaining path.
76
+ */
77
+ function sanitizeUrl(url) {
78
+ const withoutQuery = url.replace(/[?#].*/, '');
79
+ return sanitizeErrorString(withoutQuery);
80
+ }
81
+
82
+ /**
83
+ * Returns a copy of `props` with PII and credentials scrubbed:
84
+ * - Keys matching SENSITIVE_KEY_RE → value replaced with '<redacted>'
85
+ * - String values run through sanitizeErrorString
86
+ * - Non-string primitives passed through unchanged
87
+ */
88
+ function sanitizeProperties(props) {
89
+ const result = {};
90
+ for (const [key, value] of Object.entries(props)) {
91
+ if (SENSITIVE_KEY_RE.test(key)) {
92
+ result[key] = '<redacted>';
93
+ } else if (typeof value === 'string') {
94
+ result[key] = sanitizeErrorString(value);
95
+ } else {
96
+ result[key] = value;
97
+ }
98
+ }
99
+ return result;
100
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TelemetryEventNames = exports.ScenarioResults = void 0;
7
+ /*!
8
+ * Copyright (C) Microsoft Corporation. All rights reserved.
9
+ */
10
+
11
+ /** Canonical 1DS event names matching webplayer conventions. */
12
+ const TelemetryEventNames = exports.TelemetryEventNames = {
13
+ Activity: 'PowerAppsClient.Activity',
14
+ Error: 'PowerAppsClient.Error',
15
+ StartScenario: 'PowerAppsClient.StartScenario',
16
+ EndScenario: 'PowerAppsClient.EndScenario'
17
+ };
18
+ const ScenarioResults = exports.ScenarioResults = {
19
+ Success: 'Success',
20
+ Failed: 'Failed',
21
+ SuccessWithErrors: 'SuccessWithErrors'
22
+ };
23
+
24
+ /** Telemetry data residency location. EU routes to eu-mobile collector. */
25
+
26
+ /**
27
+ * Structural type for the 1DS telemetry envelope passed to telemetry initializers.
28
+ * Decouples consumers from the internal `ITelemetryItem` type.
29
+ */
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resolveTelemetryLocation = resolveTelemetryLocation;
7
+ /*!
8
+ * Copyright (C) Microsoft Corporation. All rights reserved.
9
+ */
10
+
11
+ /**
12
+ * Power Platform BAP environment `location` field values that fall under the
13
+ * EU data boundary. Mirrors `EUGeoRegions` from the CLI's `Logger/Constants.ts`.
14
+ *
15
+ * Source: `metadata.properties.location` in the BAP Get Environments API response.
16
+ */
17
+ const EU_BAP_LOCATIONS = new Set(['europe', 'france', 'germany', 'italy', 'poland', 'norway', 'sweden', 'switzerland', 'unitedkingdom']);
18
+
19
+ /**
20
+ * Resolve the 1DS telemetry collector location from a Power Platform BAP
21
+ * environment `location` string (`environment.properties.location`).
22
+ * Returns `'eu'` when the location maps to the EU data boundary, routing
23
+ * telemetry to `eu-mobile.events.data.microsoft.com` instead of the global
24
+ * US collector.
25
+ *
26
+ * Mirrors the CLI's detection in `CliLogger.ts`:
27
+ * ```
28
+ * if (metadata?.properties?.location && EUGeoRegions.has(metadata.properties.location)) {
29
+ * telemetryLocation = 'eu';
30
+ * }
31
+ * ```
32
+ *
33
+ * @example
34
+ * resolveTelemetryLocation('europe') // → 'eu'
35
+ * resolveTelemetryLocation('unitedkingdom') // → 'eu'
36
+ * resolveTelemetryLocation('italy') // → 'eu'
37
+ * resolveTelemetryLocation('unitedstates') // → 'global'
38
+ */
39
+ function resolveTelemetryLocation(input) {
40
+ if (!input) return 'global';
41
+ return EU_BAP_LOCATIONS.has(input.trim().toLowerCase()) ? 'eu' : 'global';
42
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.stringifyError = stringifyError;
7
+ var _TelemetrySanitizer = require("./TelemetrySanitizer.js");
8
+ /*!
9
+ * Copyright (C) Microsoft Corporation. All rights reserved.
10
+ */
11
+
12
+ /**
13
+ * Converts an unknown thrown value to a string suitable for telemetry.
14
+ * PII (email addresses, private IPv4 addresses) is redacted before the
15
+ * string is returned.
16
+ */
17
+ function stringifyError(error) {
18
+ let raw;
19
+ if (error instanceof Error) {
20
+ raw = `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`;
21
+ } else if (typeof error === 'string') {
22
+ raw = error;
23
+ } else {
24
+ try {
25
+ raw = JSON.stringify(error);
26
+ } catch {
27
+ raw = String(error);
28
+ }
29
+ }
30
+ return (0, _TelemetrySanitizer.sanitizeErrorString)(raw);
31
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.suppressKnownWarnings = suppressKnownWarnings;
7
+ var _reactNative = require("react-native");
8
+ /*!
9
+ * Copyright (C) Microsoft Corporation. All rights reserved.
10
+ */
11
+
12
+ /**
13
+ * Suppresses known noisy LogBox warnings that originate from third-party
14
+ * packages and are not actionable in a React Native context.
15
+ *
16
+ * Call once at app startup (e.g. in the root `_layout.tsx` or `App.tsx`)
17
+ * before rendering any UI.
18
+ *
19
+ * **Why these warnings appear:**
20
+ * - `"Deprecated API for given entry type."` — emitted by React Native's
21
+ * Performance API when a caller requests an entry type (e.g. `"navigation"`,
22
+ * `"resource"`) that only exists in the browser W3C spec. The
23
+ * `@microsoft/power-apps` package calls `getEntriesByType('navigation')` for
24
+ * app-load telemetry; on React Native the call returns `[]` harmlessly.
25
+ */
26
+ function suppressKnownWarnings() {
27
+ _reactNative.LogBox.ignoreLogs(['Deprecated API for given entry type.']);
28
+ }