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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +60 -0
  2. package/compatibility/current.json +1 -1
  3. package/lib/NOTICE.txt +2957 -371
  4. package/lib/commonjs/auth/AuthContext.js +49 -22
  5. package/lib/commonjs/auth/targetAuthorization.js +53 -0
  6. package/lib/commonjs/bridge/NativePowerAppsBridge.js +33 -2
  7. package/lib/commonjs/bridge/PowerPagesBridge.js +1 -3
  8. package/lib/commonjs/bridge/setupNativeHost.js +6 -0
  9. package/lib/commonjs/config/expoConfig.js +14 -0
  10. package/lib/commonjs/config/runtimeTenantMode.js +16 -0
  11. package/lib/commonjs/config/runtimeTenantMode.web.js +9 -0
  12. package/lib/commonjs/config/tenantMode.js +68 -0
  13. package/lib/commonjs/connections/PowerPlatformConnectionApi.js +24 -27
  14. package/lib/commonjs/connections/connectionMetadata.js +2 -2
  15. package/lib/commonjs/connections/resolveConnections.js +8 -3
  16. package/lib/commonjs/connections/types.js +9 -2
  17. package/lib/commonjs/connections/useConnectionRefs.js +19 -10
  18. package/lib/commonjs/index.js +41 -2
  19. package/lib/commonjs/platform/CanvasAppResolution.js +33 -0
  20. package/lib/commonjs/platform/CanvasAppResolutionApi.js +69 -0
  21. package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +50 -13
  22. package/lib/commonjs/platform/GlobalDiscovery.js +40 -1
  23. package/lib/commonjs/provider/PowerAppsHostProvider.js +47 -8
  24. package/lib/commonjs/provider/PowerAppsProvider.js +175 -9
  25. package/lib/commonjs/target/DefaultPowerAppsExperience.js +564 -0
  26. package/lib/commonjs/target/PowerAppsExperience.js +41 -0
  27. package/lib/commonjs/target/PowerAppsTargetBootstrap.js +534 -0
  28. package/lib/commonjs/target/errors.js +24 -0
  29. package/lib/commonjs/target/types.js +1 -0
  30. package/lib/commonjs/telemetry/index.js +2 -2
  31. package/lib/module/auth/AuthContext.js +49 -22
  32. package/lib/module/auth/targetAuthorization.js +48 -0
  33. package/lib/module/bridge/NativePowerAppsBridge.js +33 -2
  34. package/lib/module/bridge/PowerPagesBridge.js +1 -3
  35. package/lib/module/bridge/setupNativeHost.js +5 -0
  36. package/lib/module/config/expoConfig.js +14 -0
  37. package/lib/module/config/runtimeTenantMode.js +12 -0
  38. package/lib/module/config/runtimeTenantMode.web.js +5 -0
  39. package/lib/module/config/tenantMode.js +61 -0
  40. package/lib/module/connections/PowerPlatformConnectionApi.js +24 -27
  41. package/lib/module/connections/connectionMetadata.js +2 -2
  42. package/lib/module/connections/resolveConnections.js +9 -4
  43. package/lib/module/connections/types.js +9 -2
  44. package/lib/module/connections/useConnectionRefs.js +20 -11
  45. package/lib/module/index.js +5 -2
  46. package/lib/module/platform/CanvasAppResolution.js +27 -0
  47. package/lib/module/platform/CanvasAppResolutionApi.js +65 -0
  48. package/lib/module/platform/DataverseGlobalDiscoveryApi.js +49 -14
  49. package/lib/module/platform/GlobalDiscovery.js +37 -1
  50. package/lib/module/provider/PowerAppsHostProvider.js +47 -8
  51. package/lib/module/provider/PowerAppsProvider.js +179 -13
  52. package/lib/module/target/DefaultPowerAppsExperience.js +559 -0
  53. package/lib/module/target/PowerAppsExperience.js +34 -0
  54. package/lib/module/target/PowerAppsTargetBootstrap.js +529 -0
  55. package/lib/module/target/errors.js +19 -0
  56. package/lib/module/target/types.js +1 -0
  57. package/lib/module/telemetry/index.js +1 -1
  58. package/lib/typescript/commonjs/auth/AuthContext.d.ts +11 -2
  59. package/lib/typescript/commonjs/auth/targetAuthorization.d.ts +15 -0
  60. package/lib/typescript/commonjs/bridge/NativePowerAppsBridge.d.ts +6 -0
  61. package/lib/typescript/commonjs/bridge/setupNativeHost.d.ts +2 -0
  62. package/lib/typescript/commonjs/config/runtimeTenantMode.d.ts +3 -0
  63. package/lib/typescript/commonjs/config/runtimeTenantMode.web.d.ts +3 -0
  64. package/lib/typescript/commonjs/config/tenantMode.d.ts +14 -0
  65. package/lib/typescript/commonjs/connections/PowerPlatformConnectionApi.d.ts +5 -2
  66. package/lib/typescript/commonjs/connections/connectionMetadata.d.ts +1 -1
  67. package/lib/typescript/commonjs/connections/types.d.ts +7 -1
  68. package/lib/typescript/commonjs/connections/useConnectionRefs.d.ts +11 -2
  69. package/lib/typescript/commonjs/index.d.ts +7 -3
  70. package/lib/typescript/commonjs/platform/CanvasAppResolution.d.ts +4 -0
  71. package/lib/typescript/commonjs/platform/CanvasAppResolutionApi.d.ts +6 -0
  72. package/lib/typescript/commonjs/platform/DataverseGlobalDiscoveryApi.d.ts +12 -2
  73. package/lib/typescript/commonjs/platform/GlobalDiscovery.d.ts +12 -0
  74. package/lib/typescript/commonjs/provider/PowerAppsHostProvider.d.ts +9 -1
  75. package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +14 -16
  76. package/lib/typescript/commonjs/target/DefaultPowerAppsExperience.d.ts +6 -0
  77. package/lib/typescript/commonjs/target/PowerAppsExperience.d.ts +61 -0
  78. package/lib/typescript/commonjs/target/PowerAppsTargetBootstrap.d.ts +15 -0
  79. package/lib/typescript/commonjs/target/errors.d.ts +13 -0
  80. package/lib/typescript/commonjs/target/types.d.ts +34 -0
  81. package/lib/typescript/commonjs/telemetry/index.d.ts +2 -2
  82. package/lib/typescript/module/auth/AuthContext.d.ts +11 -2
  83. package/lib/typescript/module/auth/targetAuthorization.d.ts +15 -0
  84. package/lib/typescript/module/bridge/NativePowerAppsBridge.d.ts +6 -0
  85. package/lib/typescript/module/bridge/setupNativeHost.d.ts +2 -0
  86. package/lib/typescript/module/config/runtimeTenantMode.d.ts +3 -0
  87. package/lib/typescript/module/config/runtimeTenantMode.web.d.ts +3 -0
  88. package/lib/typescript/module/config/tenantMode.d.ts +14 -0
  89. package/lib/typescript/module/connections/PowerPlatformConnectionApi.d.ts +5 -2
  90. package/lib/typescript/module/connections/connectionMetadata.d.ts +1 -1
  91. package/lib/typescript/module/connections/types.d.ts +7 -1
  92. package/lib/typescript/module/connections/useConnectionRefs.d.ts +11 -2
  93. package/lib/typescript/module/index.d.ts +7 -3
  94. package/lib/typescript/module/platform/CanvasAppResolution.d.ts +4 -0
  95. package/lib/typescript/module/platform/CanvasAppResolutionApi.d.ts +6 -0
  96. package/lib/typescript/module/platform/DataverseGlobalDiscoveryApi.d.ts +12 -2
  97. package/lib/typescript/module/platform/GlobalDiscovery.d.ts +12 -0
  98. package/lib/typescript/module/provider/PowerAppsHostProvider.d.ts +9 -1
  99. package/lib/typescript/module/provider/PowerAppsProvider.d.ts +14 -16
  100. package/lib/typescript/module/target/DefaultPowerAppsExperience.d.ts +6 -0
  101. package/lib/typescript/module/target/PowerAppsExperience.d.ts +61 -0
  102. package/lib/typescript/module/target/PowerAppsTargetBootstrap.d.ts +15 -0
  103. package/lib/typescript/module/target/errors.d.ts +13 -0
  104. package/lib/typescript/module/target/types.d.ts +34 -0
  105. package/lib/typescript/module/telemetry/index.d.ts +2 -2
  106. package/package.json +12 -5
  107. package/scripts/build-codegen-package.js +34 -3
  108. package/scripts/dev.js +405 -0
  109. package/scripts/upgrade-authoring.js +85 -28
  110. package/scripts/wrap.js +42 -5
  111. package/src/config/generated-config.d.ts +21 -0
@@ -23,8 +23,10 @@ var _connectionMetadata = require("./connectionMetadata.js");
23
23
  var _disambiguate = require("../connections/disambiguate.js");
24
24
  var _connectionState = require("./connectionState.js");
25
25
  var _index = require("../telemetry/index.js");
26
+ var _powerAppsNativeCommon = require("@microsoft/power-apps-native-common");
26
27
  var _http = require("@microsoft/power-apps-native-common/http");
27
28
  var _logger = require("../logger.js");
29
+ var _errors = require("../target/errors.js");
28
30
  /*!
29
31
  * power-apps-native-host — PowerPlatformConnectionApi
30
32
  *
@@ -135,8 +137,7 @@ async function fetchConnectionsForConnector(connectorId, environmentId, region,
135
137
  }
136
138
  });
137
139
  if (!res.ok) {
138
- const errorText = await res.text().catch(() => res.statusText);
139
- throw new Error(`Unable to list connector connections (HTTP ${res.status}): ${errorText}`);
140
+ throw new Error(`Unable to list connector connections (HTTP ${res.status})`);
140
141
  }
141
142
  const body = await res.json();
142
143
  return (body.value ?? []).map(c => {
@@ -157,7 +158,7 @@ async function fetchConnectionsForConnector(connectorId, environmentId, region,
157
158
  });
158
159
  } catch (error) {
159
160
  if (error instanceof Error) throw error;
160
- throw new Error(`Unable to list connector connections: ${String(error)}`);
161
+ throw new Error('Unable to list connector connections');
161
162
  }
162
163
  }
163
164
 
@@ -245,10 +246,9 @@ async function createConnection(connectorId, environmentId, region, token, displ
245
246
  body: JSON.stringify(body)
246
247
  });
247
248
  if (!res.ok) {
248
- const errText = await res.text().catch(() => res.statusText);
249
249
  const result = {
250
250
  status: 'error',
251
- message: `HTTP ${res.status}: ${errText}`
251
+ message: `Unable to create the connection (HTTP ${res.status})`
252
252
  };
253
253
  scenario.completeWithError({
254
254
  httpStatus: res.status
@@ -281,14 +281,13 @@ async function createConnection(connectorId, environmentId, region, token, displ
281
281
  body: JSON.stringify((0, _connectionMetadata.buildConsentLinkDefinition)(oauthRedirectUrl))
282
282
  });
283
283
  if (!consentRes.ok) {
284
- const errorText = await consentRes.text().catch(() => consentRes.statusText);
285
284
  scenario.completeWithError({
286
285
  httpStatus: consentRes.status,
287
286
  phase: 'getConsentLink'
288
287
  });
289
288
  return {
290
289
  status: 'error',
291
- message: `Unable to start connector consent (HTTP ${consentRes.status}): ${errorText}`
290
+ message: `Unable to start connector consent (HTTP ${consentRes.status})`
292
291
  };
293
292
  }
294
293
  const consentData = await consentRes.json();
@@ -317,7 +316,7 @@ async function createConnection(connectorId, environmentId, region, token, displ
317
316
  });
318
317
  return {
319
318
  status: 'error',
320
- message: String(e)
319
+ message: 'Unable to create the connection.'
321
320
  };
322
321
  }
323
322
  }
@@ -345,14 +344,13 @@ async function repairConnection(connectorId, connectionName, environmentId, regi
345
344
  })
346
345
  });
347
346
  if (!updateResponse.ok) {
348
- const errorText = await updateResponse.text().catch(() => updateResponse.statusText);
349
347
  scenario.completeWithError({
350
348
  httpStatus: updateResponse.status,
351
349
  phase: 'update'
352
350
  });
353
351
  return {
354
352
  status: 'error',
355
- message: `Unable to update the connection (HTTP ${updateResponse.status}): ${errorText}`
353
+ message: `Unable to update the connection (HTTP ${updateResponse.status})`
356
354
  };
357
355
  }
358
356
  if (!requiresApiConsent) {
@@ -371,7 +369,7 @@ async function repairConnection(connectorId, connectionName, environmentId, regi
371
369
  });
372
370
  return {
373
371
  status: 'error',
374
- message: `Unable to update the connection: ${String(error)}`
372
+ message: 'Unable to update the connection.'
375
373
  };
376
374
  }
377
375
  }
@@ -396,14 +394,13 @@ async function repairConnection(connectorId, connectionName, environmentId, regi
396
394
  body: JSON.stringify((0, _connectionMetadata.buildConsentLinkDefinition)(oauthRedirectUrl))
397
395
  });
398
396
  if (!response.ok) {
399
- const errorText = await response.text().catch(() => response.statusText);
400
397
  scenario.completeWithError({
401
398
  httpStatus: response.status,
402
399
  phase: 'getConsentLink'
403
400
  });
404
401
  return {
405
402
  status: 'error',
406
- message: `Unable to repair connector consent (HTTP ${response.status}): ${errorText}`
403
+ message: `Unable to repair connector consent (HTTP ${response.status})`
407
404
  };
408
405
  }
409
406
  const data = await response.json();
@@ -432,7 +429,7 @@ async function repairConnection(connectorId, connectionName, environmentId, regi
432
429
  });
433
430
  return {
434
431
  status: 'error',
435
- message: `Unable to repair connector consent: ${String(error)}`
432
+ message: 'Unable to repair connector consent.'
436
433
  };
437
434
  }
438
435
  }
@@ -602,8 +599,7 @@ async function fetchAppConnectionUsages(appId, environmentId, region, token) {
602
599
  }
603
600
  });
604
601
  if (!response.ok) {
605
- const errorText = await response.text().catch(() => response.statusText);
606
- throw new Error(`Unable to load app connection usages (HTTP ${response.status}): ${errorText}`);
602
+ throw new Error(`Unable to load app connection usages (HTTP ${response.status})`);
607
603
  }
608
604
  const data = await response.json();
609
605
  return (data.value ?? []).filter(usage => Boolean(usage.name && usage.properties?.reference && usage.properties?.apiId)).map(usage => ({
@@ -625,8 +621,7 @@ async function postConnectionUsage(appId, usage, environmentId, region, token) {
625
621
  body: JSON.stringify((0, _connectionMetadata.buildConnectionUsageRequest)(appId, usage))
626
622
  });
627
623
  if (!response.ok) {
628
- const errorText = await response.text().catch(() => response.statusText);
629
- throw new Error(`Unable to register connection usage (HTTP ${response.status}): ${errorText}`);
624
+ throw new Error(`Unable to register connection usage (HTTP ${response.status})`);
630
625
  }
631
626
  }
632
627
  async function reportScopeConsents(appId, usages, environmentId, region, token) {
@@ -641,8 +636,7 @@ async function reportScopeConsents(appId, usages, environmentId, region, token)
641
636
  body: JSON.stringify((0, _connectionMetadata.buildScopeConsentRequest)(usages))
642
637
  });
643
638
  if (!response.ok) {
644
- const errorText = await response.text().catch(() => response.statusText);
645
- throw new Error(`Unable to register connection scope consent (HTTP ${response.status}): ${errorText}`);
639
+ throw new Error(`Unable to register connection scope consent (HTTP ${response.status})`);
646
640
  }
647
641
  }
648
642
 
@@ -667,7 +661,7 @@ async function reportScopeConsents(appId, usages, environmentId, region, token)
667
661
  * @param environmentId - Environment GUID.
668
662
  * @param region - Cluster region (default "prod").
669
663
  * @param token - Bearer token for {@link powerPlatformScope}`(region)`.
670
- * @returns Processed launch data, or `null` when the app is not found.
664
+ * @returns Processed launch data. Missing or inaccessible apps throw a typed error.
671
665
  */
672
666
  async function fetchAppLaunchData(appId, environmentId, region, token) {
673
667
  const base = (0, _PowerPlatformEnvironmentApi.buildEnvironmentEndpoint)(environmentId, region);
@@ -683,16 +677,17 @@ async function fetchAppLaunchData(appId, environmentId, region, token) {
683
677
  body: '{}'
684
678
  });
685
679
  } catch (error) {
686
- throw new Error(`Unable to reach the Power Platform app launch endpoint: ${String(error)}`);
680
+ throw new _errors.TargetRuntimeError('service-unavailable', 'launch', true, 'The app launch service is temporarily unavailable. Try again.', undefined, error);
687
681
  }
688
682
  if (!res.ok) {
689
683
  const responseText = await res.text().catch(() => res.statusText);
690
684
  if ((0, _connectionMetadata.isAppLaunchAccessDenied)(res.status, responseText)) {
691
- throw new AppLaunchAccessDeniedError();
685
+ throw new _errors.TargetRuntimeError('app-access-denied', 'launch', false, 'You do not have access to this app. Ask the app owner or an administrator to share it with you.');
692
686
  }
693
- const failureMessage = (0, _connectionMetadata.getAppLaunchFailureMessage)(res.status, res.statusText, responseText);
694
- if (!failureMessage) return null;
695
- throw new Error(failureMessage);
687
+ if (!(0, _connectionMetadata.getAppLaunchFailureMessage)(res.status, res.statusText, responseText)) {
688
+ throw new _errors.TargetRuntimeError('app-not-found', 'launch', false, 'The configured app is missing from the selected environment.');
689
+ }
690
+ throw new _errors.TargetRuntimeError('service-unavailable', 'launch', res.status === 429 || res.status >= 500, res.status === 429 || res.status >= 500 ? 'The app launch service is temporarily unavailable. Try again.' : 'The app could not be loaded from the selected environment.');
696
691
  }
697
692
  try {
698
693
  const data = await res.json();
@@ -857,9 +852,11 @@ async function fetchAppLaunchData(appId, environmentId, region, token) {
857
852
  }
858
853
  }
859
854
  const conflictingDataSources = (0, _types2.findConnectionDataSourceConflicts)(connectionRequirements);
855
+ const telemetryLocation = (0, _powerAppsNativeCommon.tryResolveTelemetryLocationFromEnvironment)(data.app?.properties?.environment?.properties?.location, data.app?.properties?.environment?.properties?.cluster?.geoShortName);
860
856
  const result = {
861
857
  connectionRefs,
862
858
  dataverseOrgUrl,
859
+ telemetryLocation,
863
860
  databaseReferences: data.app?.properties?.databaseReferences ?? {},
864
861
  missingConnectors,
865
862
  missingConnectionReferences,
@@ -895,7 +892,7 @@ async function fetchAppLaunchData(appId, environmentId, region, token) {
895
892
  }));
896
893
  return result;
897
894
  } catch (error) {
898
- throw new Error(`The Power Platform app launch response was invalid: ${String(error)}`);
895
+ throw new Error('The Power Platform app launch response was invalid');
899
896
  }
900
897
  }
901
898
 
@@ -60,9 +60,9 @@ function hasOAuthParameter(parameters) {
60
60
  function buildConnectionUserConsentUrl(environmentEndpoint, connectorId, connectionId) {
61
61
  return `${environmentEndpoint}/connectivity/connectors/${encodeURIComponent((0, _types.getConnectorId)(connectorId))}` + `/connections/${encodeURIComponent(connectionId)}/userConsent?api-version=1`;
62
62
  }
63
- function getAppLaunchFailureMessage(status, statusText, responseText) {
63
+ function getAppLaunchFailureMessage(status, _statusText, _responseText) {
64
64
  if (status === 404) return null;
65
- return `Unable to load the published app (HTTP ${status}): ${responseText || statusText}`;
65
+ return `Unable to load the published app (HTTP ${status})`;
66
66
  }
67
67
  function isAppLaunchAccessDenied(status, responseText) {
68
68
  if (status !== 403) return false;
@@ -100,8 +100,12 @@ async function resolveViaStaticRefs({
100
100
  Authorization: `Bearer ${token}`
101
101
  };
102
102
 
103
- // Fetch the Dataverse instanceUrl only when the app uses Dataverse.
104
- const [instanceUrl, ...connResults] = await Promise.all([hasDataverse ? (0, _DataverseGlobalDiscoveryApi.fetchInstanceUrl)(environmentId, region, acquireToken, token) : Promise.resolve(undefined), ...Object.entries(directConnectionReferences).map(async ([localRefId, ref]) => {
103
+ // GDS provides authoritative geography when the environment has Dataverse,
104
+ // even if this app does not use it. Only Dataverse apps require the lookup.
105
+ const [instanceMetadata, ...connResults] = await Promise.all([(0, _DataverseGlobalDiscoveryApi.fetchInstanceMetadata)(environmentId, region, acquireToken, token).catch(error => {
106
+ if (hasDataverse) throw error;
107
+ return undefined;
108
+ }), ...Object.entries(directConnectionReferences).map(async ([localRefId, ref]) => {
105
109
  const apiId = (0, _types.normalizeApiId)(ref.id);
106
110
  const schema = schemaByApiId[apiId];
107
111
  if (!schema) {
@@ -257,7 +261,7 @@ async function resolveViaStaticRefs({
257
261
  unresolvedApiIds.push((0, _types.normalizeApiId)(dr.apiId));
258
262
  }
259
263
  }
260
- const dataverseOrgUrl = (instanceUrl ?? '').replace(/\/$/, '');
264
+ const dataverseOrgUrl = (instanceMetadata?.instanceUrl ?? '').replace(/\/$/, '');
261
265
 
262
266
  // Build the final AppConnectionReference map.
263
267
  const connectionRefs = {};
@@ -300,6 +304,7 @@ async function resolveViaStaticRefs({
300
304
  return {
301
305
  connectionRefs,
302
306
  dataverseOrgUrl,
307
+ telemetryLocation: instanceMetadata?.telemetryLocation,
303
308
  databaseReferences: {},
304
309
  missingConnectors: [...new Set(unresolvedApiIds)],
305
310
  missingConnectionReferences,
@@ -111,7 +111,7 @@ function hasCompleteStaticConnectionConfig(connectionReferences, schemaMap) {
111
111
  const directReferences = references.filter(reference => !isCompositeConnectionApiId(reference.id));
112
112
  return directReferences.length > 0 && directReferences.every(reference => Boolean(reference.id) && reference.dataSources.length > 0 && reference.dataSources.every(dataSource => Boolean(schemaMap[dataSource]?.name && schemaMap[dataSource]?.properties?.primaryRuntimeUrl)));
113
113
  }
114
- function buildConnectionResolutionKey(appId, environmentId, connectionReferences) {
114
+ function buildConnectionResolutionKey(appId, environmentId, connectionReferences, targetIdentity) {
115
115
  const references = Object.entries(connectionReferences).sort(([left], [right]) => left.localeCompare(right)).map(([localRefId, reference]) => ({
116
116
  localRefId,
117
117
  id: reference.id,
@@ -122,7 +122,14 @@ function buildConnectionResolutionKey(appId, environmentId, connectionReferences
122
122
  return JSON.stringify({
123
123
  appId: appId ?? '',
124
124
  environmentId,
125
- references
125
+ references,
126
+ ...(targetIdentity ? {
127
+ tenantId: targetIdentity.tenantId?.toLowerCase() ?? '',
128
+ appName: targetIdentity.appName ?? '',
129
+ region: targetIdentity.region?.toLowerCase() ?? '',
130
+ generation: targetIdentity.generation ?? 0,
131
+ accountIdentifier: targetIdentity.accountIdentifier ?? ''
132
+ } : {})
126
133
  });
127
134
  }
128
135
 
@@ -8,6 +8,7 @@ var _react = require("react");
8
8
  var _isDevPlayer = require("../utils/isDevPlayer.js");
9
9
  var _PowerPlatformEnvironmentApi = require("../platform/PowerPlatformEnvironmentApi.js");
10
10
  var _PowerPlatformConnectionApi = require("./PowerPlatformConnectionApi.js");
11
+ var _errors = require("../target/errors.js");
11
12
  var _resolveConnections = require("./resolveConnections.js");
12
13
  var _connectionState = require("./connectionState.js");
13
14
  var _logger = require("../logger.js");
@@ -71,7 +72,9 @@ function useConnectionRefs({
71
72
  schemaMap,
72
73
  onDisambiguationNeeded,
73
74
  onMissingConnection,
74
- isvClientId
75
+ isvClientId,
76
+ onTelemetryLocationResolved,
77
+ targetIdentity
75
78
  }) {
76
79
  const [connectionRefs, setConnectionRefs] = (0, _react.useState)({});
77
80
  const [isReady, setIsReady] = (0, _react.useState)(false);
@@ -94,7 +97,10 @@ function useConnectionRefs({
94
97
  const isBackgroundRetryRef = (0, _react.useRef)(false);
95
98
  const MAX_TOKEN_RETRIES = 5;
96
99
  const TOKEN_RETRY_DELAY_MS = 2000;
97
- const currentConfigKey = (0, _types.buildConnectionResolutionKey)(appId, environmentId, _isDevPlayer.isDevPlayer ? connectionReferences : {});
100
+ const currentConfigKey = (0, _types.buildConnectionResolutionKey)(appId, environmentId, _isDevPlayer.isDevPlayer ? connectionReferences : {}, targetIdentity ? {
101
+ ...targetIdentity,
102
+ region
103
+ } : undefined);
98
104
  (0, _react.useEffect)(() => {
99
105
  if (!isSignedIn) {
100
106
  tokenRetryCountRef.current = 0;
@@ -203,9 +209,6 @@ function useConnectionRefs({
203
209
  let result = null;
204
210
  if (appId && environmentId && !_isDevPlayer.isDevPlayer) {
205
211
  result = await (0, _PowerPlatformConnectionApi.fetchAppLaunchData)(appId, environmentId, region, token);
206
- if (!result) {
207
- throw new Error(`App "${appId}" is not available in environment "${environmentId}". Push the mobile app to this environment and try again.`);
208
- }
209
212
  if (result && onDisambiguationNeeded) {
210
213
  for (const requirement of [...result.missingConnectionReferences]) {
211
214
  const candidates = result.connectionCandidates[requirement.localRefId] ?? [];
@@ -263,6 +266,9 @@ function useConnectionRefs({
263
266
  });
264
267
  return;
265
268
  }
269
+ if (result.telemetryLocation) {
270
+ onTelemetryLocationResolved?.(result.telemetryLocation);
271
+ }
266
272
 
267
273
  // Pre-warm the Dataverse token while the user waits.
268
274
  if (result.dataverseOrgUrl) {
@@ -299,15 +305,18 @@ function useConnectionRefs({
299
305
  errorName: e instanceof Error ? e.name : 'UnknownError'
300
306
  });
301
307
  (0, _index.getAppLogger)().trackErrorEvent(_index.HostOperationNames.PlatformLoadConnectionsFailed, {
302
- error: String(e),
308
+ errorName: e instanceof Error ? e.name : 'UnknownError',
309
+ errorCode: e instanceof _errors.TargetRuntimeError ? e.code : undefined,
303
310
  hasAppId: Boolean(appId),
304
311
  hasEnvironmentId: Boolean(environmentId),
305
312
  connectionReferenceCount: Object.keys(connectionReferences).length,
306
313
  runningInDevPlayer: _isDevPlayer.isDevPlayer
307
314
  });
308
- const accessDenied = e instanceof _PowerPlatformConnectionApi.AppLaunchAccessDeniedError;
309
- setErrorKind(accessDenied ? 'app-access-denied' : 'generic');
310
- setError(accessDenied ? 'You don’t have access to this app. Ask the app owner or an administrator to share it with you, then try again.' : 'Unable to load this app from Power Platform. Try again later.');
315
+ const targetError = e instanceof _errors.TargetRuntimeError ? e : null;
316
+ const accessDenied = targetError?.code === 'app-access-denied';
317
+ const appNotFound = targetError?.code === 'app-not-found';
318
+ setErrorKind(accessDenied ? 'app-access-denied' : appNotFound ? 'app-not-found' : 'generic');
319
+ setError(targetError?.userMessage ?? (accessDenied ? 'You don’t have access to this app. Ask the app owner or an administrator to share it with you, then try again.' : 'Unable to load this app from Power Platform. Try again later.'));
311
320
  setIsReady(true);
312
321
  }
313
322
  });
@@ -316,7 +325,7 @@ function useConnectionRefs({
316
325
  if (retryTimer) clearTimeout(retryTimer);
317
326
  };
318
327
  // eslint-disable-next-line react-hooks/exhaustive-deps
319
- }, [isSignedIn, retryTick, appId, environmentId, region, connectionReferences, hasDataverse, schemaMap, isvClientId]);
328
+ }, [isSignedIn, retryTick, appId, environmentId, region, connectionReferences, hasDataverse, schemaMap, isvClientId, onTelemetryLocationResolved, targetIdentity?.tenantId, targetIdentity?.appName, targetIdentity?.generation, targetIdentity?.accountIdentifier]);
320
329
  return {
321
330
  connectionRefs,
322
331
  isReady,
@@ -63,6 +63,12 @@ Object.defineProperty(exports, "PowerAppsProvider", {
63
63
  return _PowerAppsProvider.PowerAppsProvider;
64
64
  }
65
65
  });
66
+ Object.defineProperty(exports, "PowerAppsRuntimeGate", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _PowerAppsExperience.PowerAppsRuntimeGate;
70
+ }
71
+ });
66
72
  Object.defineProperty(exports, "PowerPagesBridge", {
67
73
  enumerable: true,
68
74
  get: function () {
@@ -87,6 +93,12 @@ Object.defineProperty(exports, "base64ToUint8Array", {
87
93
  return _dataverseUtils.base64ToUint8Array;
88
94
  }
89
95
  });
96
+ Object.defineProperty(exports, "buildCanvasAppResolutionUrl", {
97
+ enumerable: true,
98
+ get: function () {
99
+ return _CanvasAppResolution.buildCanvasAppResolutionUrl;
100
+ }
101
+ });
90
102
  Object.defineProperty(exports, "buildCdsDataSources", {
91
103
  enumerable: true,
92
104
  get: function () {
@@ -159,6 +171,12 @@ Object.defineProperty(exports, "buildScopeConsentUrl", {
159
171
  return _connectionMetadata.buildScopeConsentUrl;
160
172
  }
161
173
  });
174
+ Object.defineProperty(exports, "canonicalizeDataverseOrigin", {
175
+ enumerable: true,
176
+ get: function () {
177
+ return _CanvasAppResolution.canonicalizeDataverseOrigin;
178
+ }
179
+ });
162
180
  Object.defineProperty(exports, "completePowerAppsAuthSession", {
163
181
  enumerable: true,
164
182
  get: function () {
@@ -261,10 +279,10 @@ Object.defineProperty(exports, "getConnectorId", {
261
279
  return _types.getConnectorId;
262
280
  }
263
281
  });
264
- Object.defineProperty(exports, "getCustomerTelemetryLogger", {
282
+ Object.defineProperty(exports, "getCustomEventsLogger", {
265
283
  enumerable: true,
266
284
  get: function () {
267
- return _index.getCustomerTelemetryLogger;
285
+ return _index.getCustomEventsLogger;
268
286
  }
269
287
  });
270
288
  Object.defineProperty(exports, "hasCompleteStaticConnectionConfig", {
@@ -279,6 +297,12 @@ Object.defineProperty(exports, "hasOAuthParameter", {
279
297
  return _connectionMetadata.hasOAuthParameter;
280
298
  }
281
299
  });
300
+ Object.defineProperty(exports, "invalidateNativeHostRuntime", {
301
+ enumerable: true,
302
+ get: function () {
303
+ return _setupNativeHost.invalidateNativeHostRuntime;
304
+ }
305
+ });
282
306
  Object.defineProperty(exports, "isCompositeConnectionApiId", {
283
307
  enumerable: true,
284
308
  get: function () {
@@ -333,6 +357,12 @@ Object.defineProperty(exports, "reportScopeConsents", {
333
357
  return _PowerPlatformConnectionApi.reportScopeConsents;
334
358
  }
335
359
  });
360
+ Object.defineProperty(exports, "resolveCanvasApp", {
361
+ enumerable: true,
362
+ get: function () {
363
+ return _CanvasAppResolutionApi.resolveCanvasApp;
364
+ }
365
+ });
336
366
  Object.defineProperty(exports, "serializeConnectionParameters", {
337
367
  enumerable: true,
338
368
  get: function () {
@@ -387,6 +417,12 @@ Object.defineProperty(exports, "useConnectionSetup", {
387
417
  return _useConnectionSetup.useConnectionSetup;
388
418
  }
389
419
  });
420
+ Object.defineProperty(exports, "usePowerAppsExperience", {
421
+ enumerable: true,
422
+ get: function () {
423
+ return _PowerAppsExperience.usePowerAppsExperience;
424
+ }
425
+ });
390
426
  Object.defineProperty(exports, "useThemeControl", {
391
427
  enumerable: true,
392
428
  get: function () {
@@ -408,8 +444,11 @@ var _AuthContext = require("./auth/AuthContext");
408
444
  var _completePowerAppsAuthSession = require("./auth/completePowerAppsAuthSession.js");
409
445
  var _PowerAppsHostProvider = require("./provider/PowerAppsHostProvider");
410
446
  var _PowerAppsProvider = require("./provider/PowerAppsProvider.js");
447
+ var _PowerAppsExperience = require("./target/PowerAppsExperience.js");
411
448
  var _PowerPlatformEnvironmentApi = require("./platform/PowerPlatformEnvironmentApi.js");
412
449
  var _DataverseGlobalDiscoveryApi = require("./platform/DataverseGlobalDiscoveryApi.js");
450
+ var _CanvasAppResolution = require("./platform/CanvasAppResolution.js");
451
+ var _CanvasAppResolutionApi = require("./platform/CanvasAppResolutionApi.js");
413
452
  var _DataverseDataSources = require("./platform/DataverseDataSources.js");
414
453
  var _useConnectionRefs = require("./connections/useConnectionRefs.js");
415
454
  var _PowerPlatformConnectionApi = require("./connections/PowerPlatformConnectionApi.js");
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.areDataverseOriginAliases = areDataverseOriginAliases;
7
+ exports.buildCanvasAppResolutionUrl = buildCanvasAppResolutionUrl;
8
+ exports.canonicalizeDataverseOrigin = canonicalizeDataverseOrigin;
9
+ function canonicalizeDataverseOrigin(value) {
10
+ const url = new URL(value);
11
+ if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash || url.pathname !== '' && url.pathname !== '/') {
12
+ throw new Error('Dataverse URL must be an HTTPS origin');
13
+ }
14
+ return url.origin.toLowerCase();
15
+ }
16
+ function areDataverseOriginAliases(left, right) {
17
+ const normalizeHost = value => {
18
+ const url = new URL(canonicalizeDataverseOrigin(value));
19
+ const labels = url.hostname.split('.');
20
+ if (labels[1] === 'api') labels.splice(1, 1);
21
+ return `${labels.join('.')}:${url.port}`;
22
+ };
23
+ return normalizeHost(left) === normalizeHost(right);
24
+ }
25
+ function buildCanvasAppResolutionUrl(dataverseApiUrl, appName) {
26
+ const origin = canonicalizeDataverseOrigin(dataverseApiUrl);
27
+ const query = new URLSearchParams({
28
+ '$select': 'name,uniquecanvasappid,canvasapptype,componentstate',
29
+ '$filter': 'name eq @appName and componentstate eq 0',
30
+ '@appName': `'${appName.replace(/'/g, "''")}'`
31
+ });
32
+ return `${origin}/api/data/v9.2/canvasapps?${query.toString()}`;
33
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resolveCanvasApp = resolveCanvasApp;
7
+ var _http = require("@microsoft/power-apps-native-common/http");
8
+ var _index = require("../telemetry/index.js");
9
+ var _errors = require("../target/errors.js");
10
+ var _CanvasAppResolution = require("./CanvasAppResolution.js");
11
+ const GUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
12
+ async function resolveCanvasApp(target, dataverseApiUrl, acquireToken, generation) {
13
+ const assertCurrent = () => {
14
+ if (generation && !generation.isCurrent(generation.value)) {
15
+ throw new _errors.TargetRuntimeError('stale-operation', 'app-resolution', false, 'The selected environment changed before app resolution completed.', target.id);
16
+ }
17
+ };
18
+ const origin = (0, _CanvasAppResolution.canonicalizeDataverseOrigin)(dataverseApiUrl);
19
+ const scenario = (0, _index.getAppLogger)().trackScenario(_index.HostOperationNames.PlatformFetchInstanceUrl, {
20
+ targetId: target.id,
21
+ generation: generation?.value
22
+ });
23
+ try {
24
+ const token = await acquireToken([`${origin}/user_impersonation`]);
25
+ assertCurrent();
26
+ if (!token) {
27
+ throw new _errors.TargetRuntimeError('app-metadata-access-denied', 'app-resolution', false, 'You do not have access to app metadata in the selected environment.', target.id);
28
+ }
29
+ const response = await _index.platformHttpClient.request((0, _CanvasAppResolution.buildCanvasAppResolutionUrl)(origin, target.appName), {
30
+ headers: {
31
+ Authorization: `Bearer ${token}`,
32
+ Accept: 'application/json'
33
+ }
34
+ });
35
+ assertCurrent();
36
+ if (response.status === 401 || response.status === 403) {
37
+ throw new _errors.TargetRuntimeError('app-metadata-access-denied', 'app-resolution', false, 'You do not have access to app metadata in the selected environment.', target.id);
38
+ }
39
+ if (!response.ok) throw new Error(`Canvas App metadata request failed with status ${response.status}`);
40
+ const payload = await response.json();
41
+ assertCurrent();
42
+ const rows = payload.value ?? [];
43
+ if (rows.length === 0) {
44
+ throw new _errors.TargetRuntimeError('app-metadata-missing', 'app-resolution', false, 'The configured app is missing from the selected environment.', target.id);
45
+ }
46
+ if (rows.length !== 1) {
47
+ throw new _errors.TargetRuntimeError('app-metadata-ambiguous', 'app-resolution', false, 'More than one app matches the selected environment configuration.', target.id);
48
+ }
49
+ const row = rows[0];
50
+ const appId = row.uniquecanvasappid?.toLowerCase();
51
+ if (row.name !== target.appName || row.componentstate !== 0 || !appId || !GUID_PATTERN.test(appId)) {
52
+ throw new _errors.TargetRuntimeError('app-metadata-missing', 'app-resolution', false, 'The configured app metadata is invalid in the selected environment.', target.id);
53
+ }
54
+ scenario.complete({
55
+ ...(0, _http.getHttpCorrelationProperties)(response.headers)
56
+ });
57
+ return {
58
+ ...target,
59
+ appId,
60
+ dataverseApiUrl: origin
61
+ };
62
+ } catch (error) {
63
+ scenario.fail(undefined, {
64
+ errorCode: error instanceof _errors.TargetRuntimeError ? error.code : 'service-unavailable'
65
+ });
66
+ if (error instanceof _errors.TargetRuntimeError) throw error;
67
+ throw new _errors.TargetRuntimeError('service-unavailable', 'app-resolution', true, 'App metadata is temporarily unavailable. Try again.', target.id, error);
68
+ }
69
+ }