@microsoft/power-apps-native-host 0.2.25 → 0.3.3

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 (154) hide show
  1. package/README.md +21 -10
  2. package/compatibility/current.json +31 -4
  3. package/lib/NOTICE.txt +1325 -24
  4. package/lib/commonjs/auth/AuthContext.js +110 -33
  5. package/lib/commonjs/bridge/NativePowerAppsBridge.js +11 -18
  6. package/lib/commonjs/bridge/PowerPagesBridge.js +27 -8
  7. package/lib/commonjs/bridge/bridgeState.js +40 -0
  8. package/lib/commonjs/config/babelConfig.js +13 -0
  9. package/lib/commonjs/config/expoConfig.js +71 -0
  10. package/lib/commonjs/config/metroConfig.js +70 -0
  11. package/lib/commonjs/config/metroLogger.js +182 -0
  12. package/lib/commonjs/config/tamaguiConfig.js +98 -0
  13. package/lib/commonjs/connections/ConnectionSetupScreen.js +459 -80
  14. package/lib/commonjs/connections/PowerPlatformConnectionApi.js +946 -0
  15. package/lib/commonjs/connections/connectionMetadata.js +127 -0
  16. package/lib/commonjs/connections/connectionState.js +96 -0
  17. package/lib/commonjs/connections/disambiguate.js +19 -11
  18. package/lib/commonjs/connections/resolveConnections.js +348 -0
  19. package/lib/commonjs/connections/types.js +106 -0
  20. package/lib/commonjs/{platform → connections}/useConnectionRefs.js +130 -65
  21. package/lib/commonjs/connections/useConnectionSetup.js +111 -52
  22. package/lib/commonjs/controls/FilePicker.js +6 -0
  23. package/lib/commonjs/controls/ImagePicker.js +8 -0
  24. package/lib/commonjs/index.js +167 -4
  25. package/lib/commonjs/logger.js +9 -6
  26. package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
  27. package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +48 -0
  28. package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
  29. package/lib/commonjs/platform/DataverseDataSources.js +18 -0
  30. package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +94 -0
  31. package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
  32. package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
  33. package/lib/commonjs/provider/PowerAppsHostProvider.js +157 -25
  34. package/lib/commonjs/provider/PowerAppsProvider.js +178 -134
  35. package/lib/commonjs/provider/SessionDetailsGesture.js +208 -0
  36. package/lib/commonjs/telemetry/OfflineSdkTelemetry.js +95 -0
  37. package/lib/commonjs/telemetry/OfflineSdkTelemetry.web.js +9 -0
  38. package/lib/commonjs/telemetry/index.js +22 -3
  39. package/lib/module/auth/AuthContext.js +110 -33
  40. package/lib/module/bridge/NativePowerAppsBridge.js +12 -19
  41. package/lib/module/bridge/PowerPagesBridge.js +27 -8
  42. package/lib/module/bridge/bridgeState.js +34 -0
  43. package/lib/module/config/babelConfig.js +9 -0
  44. package/lib/module/config/expoConfig.js +67 -0
  45. package/lib/module/config/metroConfig.js +65 -0
  46. package/lib/module/config/metroLogger.js +175 -0
  47. package/lib/module/config/tamaguiConfig.js +93 -0
  48. package/lib/module/connections/ConnectionSetupScreen.js +460 -81
  49. package/lib/module/connections/PowerPlatformConnectionApi.js +932 -0
  50. package/lib/module/connections/connectionMetadata.js +112 -0
  51. package/lib/module/connections/connectionState.js +82 -0
  52. package/lib/module/connections/disambiguate.js +19 -12
  53. package/lib/module/connections/resolveConnections.js +343 -0
  54. package/lib/module/connections/types.js +91 -0
  55. package/lib/module/{platform → connections}/useConnectionRefs.js +131 -66
  56. package/lib/module/connections/useConnectionSetup.js +113 -54
  57. package/lib/module/controls/FilePicker.js +6 -0
  58. package/lib/module/controls/ImagePicker.js +8 -0
  59. package/lib/module/index.js +14 -4
  60. package/lib/module/logger.js +8 -6
  61. package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
  62. package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +44 -0
  63. package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
  64. package/lib/module/platform/DataverseDataSources.js +13 -0
  65. package/lib/module/platform/DataverseGlobalDiscoveryApi.js +89 -0
  66. package/lib/module/platform/GlobalDiscovery.js +45 -0
  67. package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
  68. package/lib/module/provider/PowerAppsHostProvider.js +160 -28
  69. package/lib/module/provider/PowerAppsProvider.js +182 -138
  70. package/lib/module/provider/SessionDetailsGesture.js +203 -0
  71. package/lib/module/telemetry/OfflineSdkTelemetry.js +91 -0
  72. package/lib/module/telemetry/OfflineSdkTelemetry.web.js +5 -0
  73. package/lib/module/telemetry/index.js +15 -4
  74. package/lib/typescript/commonjs/auth/AuthContext.d.ts +3 -1
  75. package/lib/typescript/commonjs/auth/AuthContext.web.d.ts +1 -0
  76. package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -0
  77. package/lib/typescript/commonjs/config/babelConfig.d.ts +12 -0
  78. package/lib/typescript/commonjs/config/expoConfig.d.ts +21 -0
  79. package/lib/typescript/commonjs/config/metroConfig.d.ts +6 -0
  80. package/lib/typescript/commonjs/config/metroLogger.d.ts +21 -0
  81. package/lib/typescript/commonjs/config/tamaguiConfig.d.ts +1792 -0
  82. package/lib/typescript/commonjs/connections/ConnectionSetupScreen.d.ts +28 -7
  83. package/lib/typescript/commonjs/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
  84. package/lib/typescript/commonjs/connections/connectionMetadata.d.ts +66 -0
  85. package/lib/typescript/commonjs/connections/connectionState.d.ts +16 -0
  86. package/lib/typescript/commonjs/connections/disambiguate.d.ts +4 -2
  87. package/lib/typescript/commonjs/{platform → connections}/resolveConnections.d.ts +22 -20
  88. package/lib/typescript/commonjs/connections/types.d.ts +129 -1
  89. package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +36 -25
  90. package/lib/typescript/commonjs/connections/useConnectionSetup.d.ts +12 -8
  91. package/lib/typescript/commonjs/controls/FilePicker.d.ts +7 -1
  92. package/lib/typescript/commonjs/controls/ImagePicker.d.ts +9 -1
  93. package/lib/typescript/commonjs/index.d.ts +18 -10
  94. package/lib/typescript/commonjs/logger.d.ts +4 -4
  95. package/lib/typescript/commonjs/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
  96. package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
  97. package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
  98. package/lib/typescript/commonjs/platform/DataverseDataSources.d.ts +28 -0
  99. package/lib/typescript/commonjs/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
  100. package/lib/typescript/commonjs/platform/GlobalDiscovery.d.ts +4 -0
  101. package/lib/typescript/commonjs/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
  102. package/lib/typescript/commonjs/provider/PowerAppsHostProvider.d.ts +29 -18
  103. package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +54 -9
  104. package/lib/typescript/commonjs/provider/SessionDetailsGesture.d.ts +13 -0
  105. package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.d.ts +15 -0
  106. package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
  107. package/lib/typescript/commonjs/telemetry/index.d.ts +13 -1
  108. package/lib/typescript/module/auth/AuthContext.d.ts +3 -1
  109. package/lib/typescript/module/auth/AuthContext.web.d.ts +1 -0
  110. package/lib/typescript/module/bridge/bridgeState.d.ts +5 -0
  111. package/lib/typescript/module/config/babelConfig.d.ts +12 -0
  112. package/lib/typescript/module/config/expoConfig.d.ts +21 -0
  113. package/lib/typescript/module/config/metroConfig.d.ts +6 -0
  114. package/lib/typescript/module/config/metroLogger.d.ts +21 -0
  115. package/lib/typescript/module/config/tamaguiConfig.d.ts +1792 -0
  116. package/lib/typescript/module/connections/ConnectionSetupScreen.d.ts +28 -7
  117. package/lib/typescript/module/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
  118. package/lib/typescript/module/connections/connectionMetadata.d.ts +66 -0
  119. package/lib/typescript/module/connections/connectionState.d.ts +16 -0
  120. package/lib/typescript/module/connections/disambiguate.d.ts +4 -2
  121. package/lib/typescript/module/{platform → connections}/resolveConnections.d.ts +22 -20
  122. package/lib/typescript/module/connections/types.d.ts +129 -1
  123. package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +36 -25
  124. package/lib/typescript/module/connections/useConnectionSetup.d.ts +12 -8
  125. package/lib/typescript/module/controls/FilePicker.d.ts +7 -1
  126. package/lib/typescript/module/controls/ImagePicker.d.ts +9 -1
  127. package/lib/typescript/module/index.d.ts +18 -10
  128. package/lib/typescript/module/logger.d.ts +4 -4
  129. package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
  130. package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
  131. package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
  132. package/lib/typescript/module/platform/DataverseDataSources.d.ts +28 -0
  133. package/lib/typescript/module/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
  134. package/lib/typescript/module/platform/GlobalDiscovery.d.ts +4 -0
  135. package/lib/typescript/module/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
  136. package/lib/typescript/module/provider/PowerAppsHostProvider.d.ts +29 -18
  137. package/lib/typescript/module/provider/PowerAppsProvider.d.ts +54 -9
  138. package/lib/typescript/module/provider/SessionDetailsGesture.d.ts +13 -0
  139. package/lib/typescript/module/telemetry/OfflineSdkTelemetry.d.ts +15 -0
  140. package/lib/typescript/module/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
  141. package/lib/typescript/module/telemetry/index.d.ts +13 -1
  142. package/package.json +52 -13
  143. package/scripts/build-codegen-package.js +283 -0
  144. package/scripts/start-web.mjs +9 -5
  145. package/scripts/upgrade/runtime.js +139 -24
  146. package/scripts/upgrade-authoring.js +274 -180
  147. package/scripts/upgrade.js +10 -16
  148. package/src/config/generated-config.d.ts +4 -0
  149. package/src/config/index.d.ts +3 -0
  150. package/src/config/tsconfig.json +26 -0
  151. package/lib/commonjs/platform/PowerPlatformConnectionApi.js +0 -606
  152. package/lib/commonjs/platform/resolveConnections.js +0 -264
  153. package/lib/module/platform/PowerPlatformConnectionApi.js +0 -595
  154. package/lib/module/platform/resolveConnections.js +0 -259
@@ -19,9 +19,13 @@ var _PowerPlatformEnvironmentApi = require("../platform/PowerPlatformEnvironment
19
19
  var _ThemeProvider = require("../theme/ThemeProvider.js");
20
20
  var _ErrorBoundary = require("../ErrorBoundary.js");
21
21
  var _isDevPlayer = require("../utils/isDevPlayer.js");
22
+ var Application = _interopRequireWildcard(require("expo-application"));
22
23
  var _expoConstants = _interopRequireDefault(require("expo-constants"));
23
24
  var _powerAppsNativeCommon = require("@microsoft/power-apps-native-common");
24
- var _useOfflineIntegration = require("../offline/useOfflineIntegration");
25
+ var _createOfflineHostActivationCallbacks = require("../offline/createOfflineHostActivationCallbacks.js");
26
+ var _useOfflineIntegrationWithStartupGate = require("../offline/useOfflineIntegrationWithStartupGate");
27
+ var _SessionDetailsGesture = require("./SessionDetailsGesture.js");
28
+ var _OfflineSdkTelemetry = require("../telemetry/OfflineSdkTelemetry");
25
29
  var _jsxRuntime = require("react/jsx-runtime");
26
30
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
27
31
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -62,7 +66,6 @@ _reactQuery.onlineManager.setEventListener(setOnline => {
62
66
  if (_reactNative.Platform.OS === 'web' && typeof window !== 'undefined') {
63
67
  const updateOnlineState = () => setOnline(window.navigator.onLine);
64
68
  window.addEventListener('online', updateOnlineState);
65
- window.addEventListener('offline', updateOnlineState);
66
69
  updateOnlineState();
67
70
  return () => {
68
71
  window.removeEventListener('online', updateOnlineState);
@@ -87,86 +90,14 @@ _reactQuery.focusManager.setEventListener(handleFocus => {
87
90
  // The bare @tamagui/config/v5 preset is only a last-resort fallback for tests
88
91
  // and storybook — it will not resolve custom $surface* tokens.
89
92
  const defaultTamaguiConfig = (0, _core.createTamagui)(_v.defaultConfig);
90
-
91
- // Whether the offline SDK will actually orchestrate for this app. Mirrors the
92
- // resolution that @microsoft/power-apps-native-offline's useOfflineIntegration
93
- // performs (offlineProfile prop → expo manifest `extra.__offlineProfile`;
94
- // enabled defaults true unless the profile's `appConfig.enabled` is explicitly
95
- // false), but computed synchronously here because the QueryClient's networkMode
96
- // must be fixed BEFORE the first query runs. The SDK's own `isEnabled` is only
97
- // known deep inside the tree (below QueryClientProvider), which is too late to
98
- // configure the client without a race. Kept deliberately narrow: it only
99
- // decides networkMode below.
100
- function isOfflineEnabled(offlineProfile) {
101
- if (_reactNative.Platform.OS === 'web') return false;
102
- // Only honour the prop when it carries a profileId — this mirrors the SDK's
103
- // useOfflineIntegration, which ignores a profileId-less prop and falls through
104
- // to the manifest. Without this guard a truthy-but-invalid prop (no profileId)
105
- // short-circuits to `false` here while the SDK still resolves enabled from the
106
- // manifest, leaving networkMode on 'online' (blank offline lists).
107
- const propProfile = offlineProfile;
108
- let profile = propProfile && propProfile.profileId ? propProfile : undefined;
109
- if (!profile) {
110
- const fromManifest = _expoConstants.default.expoConfig?.extra?.__offlineProfile;
111
- if (fromManifest && typeof fromManifest === 'object' && fromManifest.profileId) {
112
- profile = fromManifest;
113
- }
114
- }
115
- if (profile) {
116
- // Honour an explicit `appConfig.enabled: false`. This mirrors the SDK's
117
- // useOfflineIntegration, whose validateConfig classifies `enabled === false`
118
- // as "explicitly-disabled" and stays inert. A host shell's placeholder
119
- // profile (e.g. Power Apps Dev Player's offline-profile.json, enabled:false)
120
- // must NOT flip networkMode to 'always' for the loaded app — otherwise every
121
- // scanned app gets paused queries / blank lists. Any other resolved profile
122
- // (enabled true, or omitted → SDK defaults to true) enables offline.
123
- const appConfig = profile.appConfig;
124
- if (appConfig && appConfig.enabled === false) {
125
- return false;
126
- }
127
- return true;
128
- }
129
- return false;
130
- }
131
-
132
- // Builds the app's QueryClient. networkMode is gated on whether offline is
133
- // actually enabled:
134
- // • Offline enabled → 'always': the host is offline-first, so reads/writes are
135
- // served by the offline SDK from local SQLite regardless of connectivity.
136
- // onlineManager is wired to NetInfo (above) for refetchOnReconnect, but that
137
- // same wiring makes the default 'online' mode PAUSE every query/mutation while
138
- // offline (queryFn never runs → blank lists with WiFi off). 'always' makes
139
- // React Query ignore connectivity for both the initial attempt AND retries, so
140
- // local-SQLite reads/writes never get paused. ('offlineFirst' would still pause
141
- // *retries* offline — wrong for a purely-local SDK where a transient first
142
- // attempt error, e.g. SDK-not-ready at cold boot, would leave the query stuck
143
- // 'paused' until reconnect.)
144
- // • Offline disabled → undefined: React Query keeps its default 'online' mode,
145
- // i.e. the exact pre-offline behaviour for online-only apps.
146
- function createQueryClient(offlineEnabled) {
147
- const networkMode = offlineEnabled ? 'always' : undefined;
148
- return new _reactQuery.QueryClient({
149
- defaultOptions: {
150
- queries: {
151
- staleTime: 60_000,
152
- retry: 2,
153
- networkMode
154
- },
155
- mutations: {
156
- retry: 0,
157
- networkMode
158
- }
159
- }
160
- });
161
- }
162
93
  function hasConfiguredValue(value) {
163
94
  return typeof value === 'string' && value.trim().length > 0;
164
95
  }
165
96
  function hasEntries(value) {
166
97
  return Boolean(value && typeof value === 'object' && Object.keys(value).length > 0);
167
98
  }
168
- function requiresPowerPlatformAuth(powerConfig, offlineEnabled) {
169
- return Boolean(hasConfiguredValue(powerConfig.appId) || hasConfiguredValue(powerConfig.environmentId) || hasEntries(powerConfig.connectionReferences) || hasEntries(powerConfig.databaseReferences) || offlineEnabled);
99
+ function requiresPowerPlatformAuth(powerConfig) {
100
+ return Boolean(hasConfiguredValue(powerConfig.appId) || hasConfiguredValue(powerConfig.environmentId) || hasEntries(powerConfig.connectionReferences) || hasEntries(powerConfig.databaseReferences));
170
101
  }
171
102
  function MissingClientIdErrorScreen() {
172
103
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
@@ -183,11 +114,58 @@ function MissingClientIdErrorScreen() {
183
114
  })]
184
115
  });
185
116
  }
117
+ function MissingAppIdErrorScreen() {
118
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
119
+ contentContainerStyle: styles.errorContainer,
120
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
121
+ style: styles.errorTitle,
122
+ children: "App ID is missing"
123
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
124
+ style: styles.errorBody,
125
+ children: "This mobile app does not include an app ID. Push the mobile app to the Power Platform environment, rebuild it, and try again."
126
+ })]
127
+ });
128
+ }
129
+ function MissingEnvironmentIdErrorScreen() {
130
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
131
+ contentContainerStyle: styles.errorContainer,
132
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
133
+ style: styles.errorTitle,
134
+ children: "Environment ID is missing"
135
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
136
+ style: styles.errorBody,
137
+ children: "This mobile app does not include an environment ID. Push the mobile app to the Power Platform environment, rebuild it, and try again."
138
+ })]
139
+ });
140
+ }
186
141
 
187
142
  // ---- Types ----
188
143
 
189
144
  /** Shape of power.config.json consumed by the provider. */
190
145
 
146
+ function readAppInsightsConfig(value) {
147
+ if (!value || typeof value !== 'object') return undefined;
148
+ const config = value;
149
+ const minSeverity = config.minSeverity;
150
+ return {
151
+ enabled: config.enabled === true,
152
+ connectionString: typeof config.connectionString === 'string' ? config.connectionString : '',
153
+ appId: typeof config.appId === 'string' ? config.appId : '',
154
+ ...(typeof config.appVersion === 'string' ? {
155
+ appVersion: config.appVersion
156
+ } : {}),
157
+ ...(typeof config.environment === 'string' ? {
158
+ environment: config.environment
159
+ } : {}),
160
+ ...(minSeverity === 'verbose' || minSeverity === 'info' || minSeverity === 'warning' || minSeverity === 'error' ? {
161
+ minSeverity
162
+ } : {}),
163
+ ...(typeof config.includeUserId === 'boolean' ? {
164
+ includeUserId: config.includeUserId
165
+ } : {})
166
+ };
167
+ }
168
+
191
169
  // ---- Inner component ----
192
170
  // Separate from PowerAppsProvider only because useAuth() must be called inside
193
171
  // AuthProvider. All auth-dependent wiring lives here.
@@ -198,53 +176,49 @@ function InnerProviders({
198
176
  schemaMap,
199
177
  renderOAuthWebView,
200
178
  onDisambiguationNeeded,
179
+ onConnectionConsent,
180
+ onResourceConsent,
181
+ onConnectionConsentDeclined,
201
182
  offlineProfile,
183
+ onOfflineEnabledChange,
202
184
  children
203
185
  }) {
204
186
  const {
205
187
  acquireToken,
206
188
  isSignedIn,
207
- hasRealAccount
189
+ hasRealAccount,
190
+ isAuthReady,
191
+ signOut
208
192
  } = (0, _AuthContext.useAuth)();
209
- const connectionReferences = (0, _react.useMemo)(() => powerConfig.connectionReferences ?? {}, [powerConfig.connectionReferences]);
210
-
211
- // ---- Offline (all logic lives in the SDK) ----
212
- // Adapter over the host's fetchInstanceUrl: the offline SDK's contract passes a
213
- // 4th `signal?: AbortSignal` arg (which fetchInstanceUrl treats as bearerToken)
214
- // and expects a `string | null` return, so drop the extra arg and normalise
215
- // `undefined` -> `null`.
216
- const resolveInstanceUrlForOffline = (0, _react.useCallback)(async (environmentId, region, acqToken, _signal) => {
217
- const url = await (0, _PowerPlatformEnvironmentApi.fetchInstanceUrl)(environmentId, region, acqToken);
218
- return url ?? null;
219
- }, []);
220
-
221
- // Gate offline engagement on a REAL account (`hasRealAccount`), not the
222
- // `isSignedIn` flag — `isSignedIn` is inflated by noAuthMode (login-bypassed /
223
- // demo sessions report signed-in but have no account, so `acquireToken` always
224
- // returns null). Passing the inflated flag makes the SDK orchestrator engage
225
- // and then spin in a perpetual "waiting-for-auth" 3s retry loop (each retry
226
- // re-renders the provider subtree). With no obtainable token offline cannot
227
- // sync anyway, so we only engage once a usable token exists.
228
- const offline = (0, _useOfflineIntegration.useOfflineIntegration)({
193
+ const connectionReferences = (0, _react.useMemo)(() => _isDevPlayer.isDevPlayer ? powerConfig.connectionReferences ?? {} : {}, [powerConfig.connectionReferences, _isDevPlayer.isDevPlayer]);
194
+ const runtimeSchemaMap = (0, _react.useMemo)(() => _isDevPlayer.isDevPlayer ? schemaMap : {}, [schemaMap, _isDevPlayer.isDevPlayer]);
195
+ const offline = (0, _useOfflineIntegrationWithStartupGate.useOfflineIntegrationWithStartupGate)({
229
196
  powerConfig,
230
197
  offlineProfile,
231
198
  acquireToken,
232
- isSignedIn: hasRealAccount,
233
- fetchInstanceUrl: resolveInstanceUrlForOffline
199
+ hasRealAccount,
200
+ isAuthReady
234
201
  });
202
+ (0, _react.useEffect)(() => {
203
+ onOfflineEnabledChange(offline.isEnabled);
204
+ }, [offline.isEnabled, onOfflineEnabledChange]);
235
205
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_PowerAppsHostProvider.PowerAppsHostProvider, {
236
206
  acquireToken: acquireToken,
237
207
  isSignedIn: isSignedIn,
208
+ onSignOut: signOut,
238
209
  appId: powerConfig.appId ?? undefined,
239
210
  environmentId: powerConfig.environmentId ?? '',
240
211
  region: powerConfig.region ?? 'prod',
241
212
  connectionReferences: connectionReferences,
242
- schemaMap: schemaMap,
243
- databaseReferences: powerConfig.databaseReferences,
213
+ schemaMap: runtimeSchemaMap,
214
+ databaseReferences: _isDevPlayer.isDevPlayer ? powerConfig.databaseReferences : undefined,
244
215
  isvClientId: msalConfig.clientId,
245
216
  renderOAuthWebView: renderOAuthWebView,
246
217
  onDisambiguationNeeded: onDisambiguationNeeded,
247
- children: [children, offline.StatusOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(offline.StatusOverlay, {})]
218
+ onConnectionConsent: onConnectionConsent,
219
+ onResourceConsent: onResourceConsent,
220
+ onConnectionConsentDeclined: onConnectionConsentDeclined,
221
+ children: [offline.shouldMountChildren && children, offline.StatusOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(offline.StatusOverlay, {})]
248
222
  });
249
223
  }
250
224
 
@@ -259,6 +233,7 @@ function InnerProviders({
259
233
  * root layout.
260
234
  */
261
235
  function PowerAppsProvider({
236
+ appConfig,
262
237
  msalConfig,
263
238
  intuneConfig,
264
239
  powerConfig,
@@ -271,8 +246,14 @@ function PowerAppsProvider({
271
246
  followSystemTheme = true,
272
247
  renderOAuthWebView,
273
248
  onDisambiguationNeeded,
249
+ onConnectionConsent,
250
+ onResourceConsent,
251
+ onConnectionConsentDeclined,
274
252
  appName,
275
253
  logger: loggerProp,
254
+ showSessionDetailsOnLongPress,
255
+ showSessionDetailsOnSwipe,
256
+ appInsightsConfig,
276
257
  offlineProfile,
277
258
  children
278
259
  }) {
@@ -280,14 +261,19 @@ function PowerAppsProvider({
280
261
  // is stable (loggerProp is an object reference; re-running on every render
281
262
  // would reconfigure and leak the previous provider).
282
263
  const loggerPropRef = (0, _react.useRef)(loggerProp);
283
-
284
- // Gate the offline-first networkMode on whether offline is actually enabled
285
- // for this app. Keyed on the resolved boolean (not the prop object refs) so the
286
- // QueryClient identity stays stable across renders even if the caller passes
287
- // fresh offlineProfile literals.
288
- const offlineEnabled = (0, _react.useMemo)(() => isOfflineEnabled(offlineProfile), [offlineProfile]);
289
- const missingClientIdInDevPlayer = _reactNative.Platform.OS !== 'web' && _isDevPlayer.isDevPlayer && !hasConfiguredValue(msalConfig.clientId) && requiresPowerPlatformAuth(powerConfig, offlineEnabled);
290
- const queryClient = (0, _react.useMemo)(() => createQueryClient(offlineEnabled), [offlineEnabled]);
264
+ const appInsightsConfigRef = (0, _react.useRef)(appInsightsConfig ?? readAppInsightsConfig(appConfig?.expo?.extra?.appInsightsConfig ?? _expoConstants.default.expoConfig?.extra?.appInsightsConfig));
265
+ const [offlineTelemetryEnabled, setOfflineTelemetryEnabled] = (0, _react.useState)();
266
+ const missingClientIdInDevPlayer = _reactNative.Platform.OS !== 'web' && _isDevPlayer.isDevPlayer && !hasConfiguredValue(msalConfig.clientId) && requiresPowerPlatformAuth(powerConfig);
267
+ const missingAppId = _reactNative.Platform.OS !== 'web' && !_isDevPlayer.isDevPlayer && !hasConfiguredValue(powerConfig.appId);
268
+ const missingEnvironmentId = !_isDevPlayer.isDevPlayer && !hasConfiguredValue(powerConfig.environmentId);
269
+ const appId = typeof powerConfig.appId === 'string' ? powerConfig.appId.trim() : '';
270
+ const configuredBundleId = _reactNative.Platform.OS === 'ios' ? _expoConstants.default.expoConfig?.ios?.bundleIdentifier : _reactNative.Platform.OS === 'android' ? _expoConstants.default.expoConfig?.android?.package : undefined;
271
+ const bundleId = _reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'android' ? Application.applicationId ?? configuredBundleId : undefined;
272
+ const appInstanceId = _expoConstants.default.expoConfig?.extra?.telemetry?.appInstanceId;
273
+ const skillCorrelationId = typeof appInstanceId === 'string' ? appInstanceId.trim() : '';
274
+ const sessionDetailsGestureEnabled = showSessionDetailsOnLongPress ?? showSessionDetailsOnSwipe ?? true;
275
+ const requiredAuthScopes = (0, _react.useMemo)(() => [(0, _PowerPlatformEnvironmentApi.powerPlatformScope)(powerConfig.region ?? 'prod')], [powerConfig.region]);
276
+ const queryClient = (0, _react.useMemo)(() => (0, _createOfflineHostActivationCallbacks.createHostQueryClient)(), []);
291
277
 
292
278
  // Configure the app logger exactly once per mount inside useEffect so that
293
279
  // side effects (provider construction, async resolveDeviceId) never run
@@ -295,6 +281,9 @@ function PowerAppsProvider({
295
281
  // silent no-op Logger, so any telemetry emitted before the first commit is
296
282
  // silently dropped rather than crashing.
297
283
  (0, _react.useEffect)(() => {
284
+ // Customer telemetry is a no-op until a valid Application Insights
285
+ // provider is configured below.
286
+ (0, _powerAppsNativeCommon.configureCustomerTelemetryLogger)(new _powerAppsNativeCommon.Logger());
298
287
  const lp = loggerPropRef.current;
299
288
  if (lp === null) {
300
289
  // Explicit opt-out — replace with a silent no-op Logger.
@@ -310,26 +299,63 @@ function PowerAppsProvider({
310
299
  clientType: appName ?? 'PowerAppsNative',
311
300
  appVersion: _expoConstants.default.expoConfig?.version,
312
301
  minSeverity: __DEV__ ? 'verbose' : 'info',
313
- telemetryLocation: (0, _powerAppsNativeCommon.resolveTelemetryLocation)(powerConfig.geoRegion)
302
+ telemetryLocation: (0, _powerAppsNativeCommon.resolveTelemetryLocation)(powerConfig.geoRegion),
303
+ commonProperties: {
304
+ ...(appId ? {
305
+ appId
306
+ } : {}),
307
+ ...(bundleId ? {
308
+ bundleId
309
+ } : {}),
310
+ ...(skillCorrelationId ? {
311
+ skillCorrelationId
312
+ } : {})
313
+ }
314
+ };
315
+ const configureDefaultLogger = (deviceId = 'react-native') => {
316
+ const oneDsProvider = new _powerAppsNativeCommon.OneDsTelemetryProvider({
317
+ ...providerConfig,
318
+ deviceId
319
+ });
320
+ const providers = [oneDsProvider];
321
+ let appInsightsEnabled = false;
322
+ const configuredAppInsights = appInsightsConfigRef.current;
323
+ if (configuredAppInsights?.enabled) {
324
+ try {
325
+ const customerProvider = new _powerAppsNativeCommon.ApplicationInsightsTelemetryProvider({
326
+ ...configuredAppInsights,
327
+ appVersion: configuredAppInsights.appVersion ?? _expoConstants.default.expoConfig?.version,
328
+ deviceId,
329
+ sessionId: oneDsProvider.sessionId
330
+ });
331
+ providers.push(customerProvider);
332
+ (0, _powerAppsNativeCommon.configureCustomerTelemetryLogger)(new _powerAppsNativeCommon.Logger({
333
+ providers: [customerProvider]
334
+ }));
335
+ appInsightsEnabled = true;
336
+ } catch (error) {
337
+ console.error('[PowerAppsProvider] Application Insights configuration is invalid.', error);
338
+ }
339
+ }
340
+ const logger = new _powerAppsNativeCommon.Logger({
341
+ providers
342
+ });
343
+ (0, _powerAppsNativeCommon.configureAppLogger)(logger);
344
+ if (appInsightsEnabled) {
345
+ logger.trackActivityEvent('PowerAppsNative.ApplicationStarted', {
346
+ app_id: configuredAppInsights?.appId
347
+ });
348
+ }
314
349
  };
315
350
  // Resolve the stable device ID first so every event — including the
316
351
  // very first — carries the real GUID rather than the 'react-native'
317
352
  // fallback. Events emitted while this resolves are silently dropped
318
353
  // by the no-op Logger that is active until configureAppLogger is called.
319
354
  (0, _powerAppsNativeCommon.resolveDeviceId)().then(deviceId => {
320
- const provider = new _powerAppsNativeCommon.OneDsTelemetryProvider({
321
- ...providerConfig,
322
- deviceId
323
- });
324
- (0, _powerAppsNativeCommon.configureAppLogger)(new _powerAppsNativeCommon.Logger({
325
- providers: [provider]
326
- }));
355
+ configureDefaultLogger(deviceId);
327
356
  }).catch(_err => {
328
357
  // SecureStore unavailable — fall back to a provider without a stable ID.
329
- const provider = new _powerAppsNativeCommon.OneDsTelemetryProvider(providerConfig);
330
- (0, _powerAppsNativeCommon.configureAppLogger)(new _powerAppsNativeCommon.Logger({
331
- providers: [provider]
332
- }));
358
+ configureDefaultLogger();
333
359
  });
334
360
  }
335
361
 
@@ -342,6 +368,11 @@ function PowerAppsProvider({
342
368
  };
343
369
  // eslint-disable-next-line react-hooks/exhaustive-deps
344
370
  }, []); // intentionally empty — logger is configured once per mount
371
+
372
+ (0, _react.useEffect)(() => {
373
+ if (offlineTelemetryEnabled === undefined) return undefined;
374
+ return (0, _OfflineSdkTelemetry.configureOfflineSdkTelemetry)(offlineTelemetryEnabled);
375
+ }, [offlineTelemetryEnabled]);
345
376
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorBoundary.ErrorBoundary, {
346
377
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView, {
347
378
  style: {
@@ -359,19 +390,32 @@ function PowerAppsProvider({
359
390
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_toast.ToastProvider, {
360
391
  swipeDirection: "horizontal",
361
392
  duration: 3000,
362
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactQuery.QueryClientProvider, {
363
- client: queryClient,
364
- children: missingClientIdInDevPlayer ? /*#__PURE__*/(0, _jsxRuntime.jsx)(MissingClientIdErrorScreen, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_AuthContext.AuthProvider, {
365
- msalConfig: msalConfig,
366
- intuneConfig: intuneConfig,
367
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(InnerProviders, {
393
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_SessionDetailsGesture.SessionDetailsGesture, {
394
+ enabled: sessionDetailsGestureEnabled,
395
+ appName: appName ?? _expoConstants.default.expoConfig?.name ?? 'Power Apps',
396
+ appId: appId || undefined,
397
+ environmentId: powerConfig.environmentId,
398
+ region: powerConfig.region ?? 'prod',
399
+ appVersion: _expoConstants.default.expoConfig?.version,
400
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactQuery.QueryClientProvider, {
401
+ client: queryClient,
402
+ children: missingAppId ? /*#__PURE__*/(0, _jsxRuntime.jsx)(MissingAppIdErrorScreen, {}) : missingEnvironmentId ? /*#__PURE__*/(0, _jsxRuntime.jsx)(MissingEnvironmentIdErrorScreen, {}) : missingClientIdInDevPlayer ? /*#__PURE__*/(0, _jsxRuntime.jsx)(MissingClientIdErrorScreen, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_AuthContext.AuthProvider, {
368
403
  msalConfig: msalConfig,
369
- powerConfig: powerConfig,
370
- schemaMap: schemaMap,
371
- renderOAuthWebView: renderOAuthWebView,
372
- onDisambiguationNeeded: onDisambiguationNeeded,
373
- offlineProfile: offlineProfile,
374
- children: children
404
+ intuneConfig: intuneConfig,
405
+ requiredScopes: requiredAuthScopes,
406
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(InnerProviders, {
407
+ msalConfig: msalConfig,
408
+ powerConfig: powerConfig,
409
+ schemaMap: schemaMap,
410
+ renderOAuthWebView: renderOAuthWebView,
411
+ onDisambiguationNeeded: onDisambiguationNeeded,
412
+ onConnectionConsent: onConnectionConsent,
413
+ onResourceConsent: onResourceConsent,
414
+ onConnectionConsentDeclined: onConnectionConsentDeclined,
415
+ offlineProfile: offlineProfile,
416
+ onOfflineEnabledChange: setOfflineTelemetryEnabled,
417
+ children: children
418
+ })
375
419
  })
376
420
  })
377
421
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_toast.ToastViewport, {
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SessionDetailsGesture = SessionDetailsGesture;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var Clipboard = _interopRequireWildcard(require("expo-clipboard"));
10
+ var _reactNativeGestureHandler = require("react-native-gesture-handler");
11
+ var _index = require("../telemetry/index.js");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
+ function SessionDetailsGesture({
15
+ enabled,
16
+ appName,
17
+ appId,
18
+ environmentId,
19
+ region,
20
+ appVersion,
21
+ children
22
+ }) {
23
+ const [visible, setVisible] = (0, _react.useState)(false);
24
+ const [sessionId, setSessionId] = (0, _react.useState)();
25
+ const [copied, setCopied] = (0, _react.useState)(false);
26
+ const showSessionDetails = (0, _react.useCallback)(() => {
27
+ setSessionId((0, _index.getAppLogger)().sessionId);
28
+ setCopied(false);
29
+ setVisible(true);
30
+ }, []);
31
+ const gesture = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.LongPress().enabled(enabled && _reactNative.Platform.OS !== 'web').numberOfPointers(3).runOnJS(true).onStart(showSessionDetails), [enabled, showSessionDetails]);
32
+ const close = (0, _react.useCallback)(() => setVisible(false), []);
33
+ const copySessionId = (0, _react.useCallback)(async () => {
34
+ if (!sessionId) return;
35
+ await Clipboard.setStringAsync(sessionId);
36
+ setCopied(true);
37
+ }, [sessionId]);
38
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
39
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
40
+ gesture: gesture,
41
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
42
+ style: styles.content,
43
+ children: children
44
+ })
45
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
46
+ animationType: "fade",
47
+ onRequestClose: close,
48
+ transparent: true,
49
+ visible: visible,
50
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
51
+ accessibilityRole: "button",
52
+ accessibilityLabel: "Close session details",
53
+ onPress: close,
54
+ style: styles.backdrop,
55
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
56
+ accessible: false,
57
+ onPress: event => event.stopPropagation(),
58
+ style: styles.panel,
59
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
60
+ style: styles.title,
61
+ children: "Session details"
62
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
63
+ label: "Telemetry session ID",
64
+ value: sessionId ?? 'Not available',
65
+ selectable: true,
66
+ singleLine: true
67
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
68
+ accessibilityRole: "button",
69
+ disabled: !sessionId,
70
+ onPress: () => {
71
+ void copySessionId();
72
+ },
73
+ style: ({
74
+ pressed
75
+ }) => [styles.copyButton, !sessionId && styles.disabledButton, pressed && styles.pressedButton],
76
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
77
+ style: styles.copyButtonText,
78
+ children: copied ? 'Copied' : 'Copy session ID'
79
+ })
80
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
81
+ label: "App",
82
+ value: appName
83
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
84
+ label: "App ID",
85
+ value: appId ?? 'Not available',
86
+ selectable: true
87
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
88
+ label: "Environment ID",
89
+ value: environmentId ?? 'Not available',
90
+ selectable: true
91
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
92
+ label: "Region",
93
+ value: region
94
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
95
+ label: "App version",
96
+ value: appVersion ?? 'Not available'
97
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
98
+ accessibilityRole: "button",
99
+ onPress: close,
100
+ style: styles.closeButton,
101
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
102
+ style: styles.closeButtonText,
103
+ children: "Close"
104
+ })
105
+ })]
106
+ })
107
+ })
108
+ })]
109
+ });
110
+ }
111
+ function SessionDetail({
112
+ label,
113
+ value,
114
+ selectable = false,
115
+ singleLine = false
116
+ }) {
117
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
118
+ style: styles.row,
119
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
120
+ style: styles.label,
121
+ children: label
122
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
123
+ adjustsFontSizeToFit: singleLine,
124
+ minimumFontScale: 0.85,
125
+ numberOfLines: singleLine ? 1 : undefined,
126
+ selectable: selectable,
127
+ style: styles.value,
128
+ children: value
129
+ })]
130
+ });
131
+ }
132
+ const styles = _reactNative.StyleSheet.create({
133
+ content: {
134
+ flex: 1
135
+ },
136
+ backdrop: {
137
+ alignItems: 'center',
138
+ backgroundColor: 'rgba(0, 0, 0, 0.48)',
139
+ flex: 1,
140
+ justifyContent: 'center',
141
+ paddingHorizontal: 12,
142
+ paddingVertical: 24
143
+ },
144
+ panel: {
145
+ backgroundColor: '#FFFFFF',
146
+ borderRadius: 8,
147
+ maxWidth: 520,
148
+ paddingHorizontal: 16,
149
+ paddingVertical: 24,
150
+ width: '100%'
151
+ },
152
+ title: {
153
+ color: '#242424',
154
+ fontSize: 20,
155
+ fontWeight: '700',
156
+ marginBottom: 20
157
+ },
158
+ row: {
159
+ marginBottom: 14
160
+ },
161
+ label: {
162
+ color: '#616161',
163
+ fontSize: 12,
164
+ fontWeight: '600',
165
+ marginBottom: 3
166
+ },
167
+ value: {
168
+ color: '#242424',
169
+ fontSize: 15,
170
+ lineHeight: 21
171
+ },
172
+ copyButton: {
173
+ alignSelf: 'flex-start',
174
+ borderColor: '#0F6CBD',
175
+ borderRadius: 4,
176
+ borderWidth: 1,
177
+ marginBottom: 14,
178
+ marginTop: -4,
179
+ paddingHorizontal: 12,
180
+ paddingVertical: 7
181
+ },
182
+ copyButtonText: {
183
+ color: '#0F6CBD',
184
+ fontSize: 13,
185
+ fontWeight: '600'
186
+ },
187
+ disabledButton: {
188
+ opacity: 0.45
189
+ },
190
+ pressedButton: {
191
+ opacity: 0.7
192
+ },
193
+ closeButton: {
194
+ alignItems: 'center',
195
+ alignSelf: 'flex-end',
196
+ backgroundColor: '#0F6CBD',
197
+ borderRadius: 4,
198
+ marginTop: 8,
199
+ minWidth: 88,
200
+ paddingHorizontal: 18,
201
+ paddingVertical: 10
202
+ },
203
+ closeButtonText: {
204
+ color: '#FFFFFF',
205
+ fontSize: 14,
206
+ fontWeight: '600'
207
+ }
208
+ });