@microsoft/power-apps-native-host 0.2.22 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +162 -26
  2. package/compatibility/current.json +87 -0
  3. package/lib/NOTICE.txt +140 -1226
  4. package/lib/commonjs/auth/AuthContext.js +74 -18
  5. package/lib/commonjs/auth/AuthContext.web.js +32 -0
  6. package/lib/commonjs/auth/completePowerAppsAuthSession.js +16 -0
  7. package/lib/commonjs/bridge/NativePowerAppsBridge.js +20 -17
  8. package/lib/commonjs/bridge/PowerPagesBridge.js +157 -0
  9. package/lib/commonjs/bridge/bridgeState.js +40 -0
  10. package/lib/commonjs/connections/ConnectionSetupScreen.js +459 -80
  11. package/lib/commonjs/connections/PowerPlatformConnectionApi.js +946 -0
  12. package/lib/commonjs/connections/connectionMetadata.js +127 -0
  13. package/lib/commonjs/connections/connectionState.js +96 -0
  14. package/lib/commonjs/connections/disambiguate.js +19 -11
  15. package/lib/commonjs/connections/resolveConnections.js +347 -0
  16. package/lib/commonjs/connections/types.js +106 -0
  17. package/lib/commonjs/{platform → connections}/useConnectionRefs.js +128 -65
  18. package/lib/commonjs/connections/useConnectionSetup.js +111 -52
  19. package/lib/commonjs/controls/FilePicker.js +6 -0
  20. package/lib/commonjs/controls/ImagePicker.js +8 -0
  21. package/lib/commonjs/index.js +188 -6
  22. package/lib/commonjs/logger.js +9 -6
  23. package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
  24. package/lib/commonjs/offline/useOfflineIntegration.js +12 -0
  25. package/lib/commonjs/offline/useOfflineIntegration.web.js +11 -0
  26. package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +46 -0
  27. package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
  28. package/lib/commonjs/platform/DataverseDataSources.js +14 -0
  29. package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +49 -0
  30. package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
  31. package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
  32. package/lib/commonjs/provider/PowerAppsHostProvider.js +156 -25
  33. package/lib/commonjs/provider/PowerAppsHostProvider.web.js +41 -0
  34. package/lib/commonjs/provider/PowerAppsProvider.js +229 -133
  35. package/lib/commonjs/provider/SessionDetailsGesture.js +216 -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 +74 -18
  40. package/lib/module/auth/AuthContext.web.js +26 -0
  41. package/lib/module/auth/completePowerAppsAuthSession.js +11 -0
  42. package/lib/module/bridge/NativePowerAppsBridge.js +21 -18
  43. package/lib/module/bridge/PowerPagesBridge.js +151 -0
  44. package/lib/module/bridge/bridgeState.js +34 -0
  45. package/lib/module/connections/ConnectionSetupScreen.js +460 -81
  46. package/lib/module/connections/PowerPlatformConnectionApi.js +932 -0
  47. package/lib/module/connections/connectionMetadata.js +112 -0
  48. package/lib/module/connections/connectionState.js +82 -0
  49. package/lib/module/connections/disambiguate.js +19 -12
  50. package/lib/module/connections/resolveConnections.js +342 -0
  51. package/lib/module/connections/types.js +91 -0
  52. package/lib/module/{platform → connections}/useConnectionRefs.js +129 -66
  53. package/lib/module/connections/useConnectionSetup.js +113 -54
  54. package/lib/module/controls/FilePicker.js +6 -0
  55. package/lib/module/controls/ImagePicker.js +8 -0
  56. package/lib/module/index.js +14 -6
  57. package/lib/module/logger.js +8 -6
  58. package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
  59. package/lib/module/offline/useOfflineIntegration.js +3 -0
  60. package/lib/module/offline/useOfflineIntegration.web.js +7 -0
  61. package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +42 -0
  62. package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
  63. package/lib/module/platform/DataverseDataSources.js +10 -0
  64. package/lib/module/platform/DataverseGlobalDiscoveryApi.js +45 -0
  65. package/lib/module/platform/GlobalDiscovery.js +45 -0
  66. package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
  67. package/lib/module/provider/PowerAppsHostProvider.js +159 -28
  68. package/lib/module/provider/PowerAppsHostProvider.web.js +36 -0
  69. package/lib/module/provider/PowerAppsProvider.js +233 -137
  70. package/lib/module/provider/SessionDetailsGesture.js +211 -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 +21 -0
  76. package/lib/typescript/commonjs/auth/completePowerAppsAuthSession.d.ts +8 -0
  77. package/lib/typescript/commonjs/bridge/PowerPagesBridge.d.ts +18 -0
  78. package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -0
  79. package/lib/typescript/commonjs/connections/ConnectionSetupScreen.d.ts +28 -7
  80. package/lib/typescript/commonjs/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
  81. package/lib/typescript/commonjs/connections/connectionMetadata.d.ts +66 -0
  82. package/lib/typescript/commonjs/connections/connectionState.d.ts +16 -0
  83. package/lib/typescript/commonjs/connections/disambiguate.d.ts +4 -2
  84. package/lib/typescript/commonjs/{platform → connections}/resolveConnections.d.ts +19 -19
  85. package/lib/typescript/commonjs/connections/types.d.ts +129 -1
  86. package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +33 -24
  87. package/lib/typescript/commonjs/connections/useConnectionSetup.d.ts +12 -8
  88. package/lib/typescript/commonjs/controls/FilePicker.d.ts +7 -1
  89. package/lib/typescript/commonjs/controls/ImagePicker.d.ts +9 -1
  90. package/lib/typescript/commonjs/index.d.ts +20 -10
  91. package/lib/typescript/commonjs/logger.d.ts +4 -4
  92. package/lib/typescript/commonjs/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
  93. package/lib/typescript/commonjs/offline/useOfflineIntegration.d.ts +2 -0
  94. package/lib/typescript/commonjs/offline/useOfflineIntegration.web.d.ts +4 -0
  95. package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
  96. package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
  97. package/lib/typescript/commonjs/platform/DataverseDataSources.d.ts +27 -0
  98. package/lib/typescript/commonjs/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
  99. package/lib/typescript/commonjs/platform/GlobalDiscovery.d.ts +4 -0
  100. package/lib/typescript/commonjs/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
  101. package/lib/typescript/commonjs/provider/PowerAppsHostProvider.d.ts +29 -18
  102. package/lib/typescript/commonjs/provider/PowerAppsHostProvider.web.d.ts +5 -0
  103. package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +32 -10
  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 +21 -0
  110. package/lib/typescript/module/auth/completePowerAppsAuthSession.d.ts +8 -0
  111. package/lib/typescript/module/bridge/PowerPagesBridge.d.ts +18 -0
  112. package/lib/typescript/module/bridge/bridgeState.d.ts +5 -0
  113. package/lib/typescript/module/connections/ConnectionSetupScreen.d.ts +28 -7
  114. package/lib/typescript/module/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
  115. package/lib/typescript/module/connections/connectionMetadata.d.ts +66 -0
  116. package/lib/typescript/module/connections/connectionState.d.ts +16 -0
  117. package/lib/typescript/module/connections/disambiguate.d.ts +4 -2
  118. package/lib/typescript/module/{platform → connections}/resolveConnections.d.ts +19 -19
  119. package/lib/typescript/module/connections/types.d.ts +129 -1
  120. package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +33 -24
  121. package/lib/typescript/module/connections/useConnectionSetup.d.ts +12 -8
  122. package/lib/typescript/module/controls/FilePicker.d.ts +7 -1
  123. package/lib/typescript/module/controls/ImagePicker.d.ts +9 -1
  124. package/lib/typescript/module/index.d.ts +24 -14
  125. package/lib/typescript/module/logger.d.ts +4 -4
  126. package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
  127. package/lib/typescript/module/offline/useOfflineIntegration.d.ts +2 -0
  128. package/lib/typescript/module/offline/useOfflineIntegration.web.d.ts +4 -0
  129. package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
  130. package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
  131. package/lib/typescript/module/platform/DataverseDataSources.d.ts +27 -0
  132. package/lib/typescript/module/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
  133. package/lib/typescript/module/platform/GlobalDiscovery.d.ts +4 -0
  134. package/lib/typescript/module/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
  135. package/lib/typescript/module/provider/PowerAppsHostProvider.d.ts +29 -18
  136. package/lib/typescript/module/provider/PowerAppsHostProvider.web.d.ts +5 -0
  137. package/lib/typescript/module/provider/PowerAppsProvider.d.ts +34 -12
  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 +43 -18
  143. package/scripts/build-ios-base.js +66 -27
  144. package/scripts/bundle.js +212 -5
  145. package/scripts/generate-connector-schemas.js +8 -6
  146. package/scripts/metro-logger.js +213 -0
  147. package/scripts/start-web.mjs +137 -0
  148. package/scripts/upgrade/runtime.js +463 -0
  149. package/scripts/upgrade/system.js +244 -0
  150. package/scripts/upgrade-authoring.js +534 -0
  151. package/scripts/upgrade.js +188 -0
  152. package/scripts/wrap.js +536 -0
  153. package/lib/commonjs/platform/PowerPlatformConnectionApi.js +0 -606
  154. package/lib/commonjs/platform/resolveConnections.js +0 -264
  155. package/lib/module/platform/PowerPlatformConnectionApi.js +0 -595
  156. package/lib/module/platform/resolveConnections.js +0 -259
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.buildConnectionParameterSets = buildConnectionParameterSets;
7
+ exports.buildConnectionUsageRequest = buildConnectionUsageRequest;
8
+ exports.buildConnectionUsageUrl = buildConnectionUsageUrl;
9
+ exports.buildConnectionUserConsentUrl = buildConnectionUserConsentUrl;
10
+ exports.buildConsentLinkDefinition = buildConsentLinkDefinition;
11
+ exports.buildScopeConsentRequest = buildScopeConsentRequest;
12
+ exports.buildScopeConsentUrl = buildScopeConsentUrl;
13
+ exports.getAppLaunchFailureMessage = getAppLaunchFailureMessage;
14
+ exports.hasOAuthParameter = hasOAuthParameter;
15
+ exports.isAppLaunchAccessDenied = isAppLaunchAccessDenied;
16
+ exports.parseConnectionParameters = parseConnectionParameters;
17
+ exports.serializeConnectionParameters = serializeConnectionParameters;
18
+ var _types = require("./types.js");
19
+ function parseConnectionParameters(parameters) {
20
+ return Object.entries(parameters ?? {}).flatMap(([name, parameter]) => {
21
+ if (!parameter.uiDefinition) return [];
22
+ const constraints = parameter.uiDefinition.constraints;
23
+ const type = (parameter.type ?? 'string').toLowerCase();
24
+ const supportedType = type === 'string' || type === 'securestring' || type === 'boolean' || type === 'integer' || type === 'clientcertificate' ? type : null;
25
+ if (!supportedType) return [];
26
+ return [{
27
+ name,
28
+ displayName: parameter.uiDefinition.displayName ?? name,
29
+ type: supportedType,
30
+ required: constraints?.required === true || constraints?.required === 'true',
31
+ hidden: constraints?.hidden === true || constraints?.hidden === 'true',
32
+ capabilities: constraints?.capability,
33
+ allowedValues: constraints?.allowedValues?.filter(item => Boolean(item.value)).map(item => ({
34
+ value: item.value,
35
+ displayName: item.displayName ?? item.value
36
+ })),
37
+ defaultValue: parameter.defaultValue
38
+ }];
39
+ });
40
+ }
41
+ function buildConnectionParameterSets(connectionParameters, parameterSets) {
42
+ const declaredSets = (parameterSets ?? []).filter(item => Boolean(item.name)).map(item => ({
43
+ name: item.name,
44
+ displayName: item.uiDefinition?.displayName ?? item.name,
45
+ parameters: parseConnectionParameters(item.connectionParameters ?? item.parameters),
46
+ requiresApiConsent: hasOAuthParameter(item.connectionParameters ?? item.parameters),
47
+ gatewayParameterName: Object.entries(item.connectionParameters ?? item.parameters ?? {}).find(([, parameter]) => parameter.type?.toLowerCase() === 'gatewaysetting')?.[0]
48
+ }));
49
+ return declaredSets.length > 0 ? declaredSets : [{
50
+ name: undefined,
51
+ displayName: 'Default',
52
+ parameters: parseConnectionParameters(connectionParameters),
53
+ requiresApiConsent: hasOAuthParameter(connectionParameters),
54
+ gatewayParameterName: Object.entries(connectionParameters ?? {}).find(([, parameter]) => parameter.type?.toLowerCase() === 'gatewaysetting')?.[0]
55
+ }];
56
+ }
57
+ function hasOAuthParameter(parameters) {
58
+ return Object.values(parameters ?? {}).some(parameter => parameter.type?.toLowerCase() === 'oauthsetting');
59
+ }
60
+ function buildConnectionUserConsentUrl(environmentEndpoint, connectorId, connectionId) {
61
+ return `${environmentEndpoint}/connectivity/connectors/${encodeURIComponent((0, _types.getConnectorId)(connectorId))}` + `/connections/${encodeURIComponent(connectionId)}/userConsent?api-version=1`;
62
+ }
63
+ function getAppLaunchFailureMessage(status, statusText, responseText) {
64
+ if (status === 404) return null;
65
+ return `Unable to load the published app (HTTP ${status}): ${responseText || statusText}`;
66
+ }
67
+ function isAppLaunchAccessDenied(status, responseText) {
68
+ if (status !== 403) return false;
69
+ try {
70
+ const body = JSON.parse(responseText);
71
+ return body.error?.code === 'PowerAppsNoAccess' || body.error?.details?.some(detail => detail.code === 'PowerAppsNoAccess') === true;
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+ function buildConsentLinkDefinition(redirectUrl) {
77
+ return {
78
+ redirectUrl
79
+ };
80
+ }
81
+ function serializeConnectionParameters(input) {
82
+ const parameters = {
83
+ ...(input?.parameters ?? {}),
84
+ ...(input?.gatewayObjectId && input.gatewayParameterName ? {
85
+ [input.gatewayParameterName]: {
86
+ gatewayObjectId: input.gatewayObjectId
87
+ }
88
+ } : {})
89
+ };
90
+ if (!input?.parameterSetName) return {
91
+ connectionParameters: parameters
92
+ };
93
+ return {
94
+ connectionParametersSet: {
95
+ name: input.parameterSetName,
96
+ values: Object.fromEntries(Object.entries(parameters).map(([name, value]) => [name, {
97
+ value
98
+ }]))
99
+ }
100
+ };
101
+ }
102
+ function buildConnectionUsageUrl(environmentBaseUrl, environmentId, usage) {
103
+ return `${environmentBaseUrl}/powerapps/apis/${encodeURIComponent((0, _types.getConnectorId)(usage.apiId))}` + `/connections/${encodeURIComponent(usage.connectionId)}/usages` + `?api-version=1&$filter=environment eq '${environmentId}'`;
104
+ }
105
+ function buildConnectionUsageRequest(appId, usage) {
106
+ const resourceId = appId.startsWith('/providers/') ? appId : `/providers/Microsoft.PowerApps/apps/${appId}`;
107
+ return {
108
+ properties: {
109
+ reference: usage.localRefId,
110
+ resourceId,
111
+ appActions: usage.appActions
112
+ }
113
+ };
114
+ }
115
+ function buildScopeConsentUrl(environmentBaseUrl, appId) {
116
+ const appName = appId.split('/').filter(Boolean).pop() ?? appId;
117
+ return `${environmentBaseUrl}/powerapps/apps/${encodeURIComponent(appName)}` + '/reportScopesConsent?api-version=1';
118
+ }
119
+ function buildScopeConsentRequest(usages) {
120
+ return {
121
+ consents: usages.map(usage => ({
122
+ connectionId: usage.connectionId,
123
+ consentType: 'userConsent',
124
+ scopes: usage.apiScopes
125
+ }))
126
+ };
127
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.applyRegisteredConnectionSelections = applyRegisteredConnectionSelections;
7
+ exports.applyRegisteredConnectionUsages = applyRegisteredConnectionUsages;
8
+ exports.getConnectionNamesRequiringAclGrant = getConnectionNamesRequiringAclGrant;
9
+ exports.getUnregisteredConnectionRequirements = getUnregisteredConnectionRequirements;
10
+ exports.hasRegisteredConnectionConsent = hasRegisteredConnectionConsent;
11
+ exports.invalidateFailedAclGrants = invalidateFailedAclGrants;
12
+ exports.isTransientConnectionConsentStatus = isTransientConnectionConsentStatus;
13
+ exports.selectLaunchConnection = selectLaunchConnection;
14
+ exports.shouldGrantConnectionUserConsent = shouldGrantConnectionUserConsent;
15
+ exports.shouldPersistConnectionUsages = shouldPersistConnectionUsages;
16
+ exports.shouldShowConnectionReview = shouldShowConnectionReview;
17
+ var _types = require("./types.js");
18
+ var _disambiguate = require("./disambiguate.js");
19
+ function isTransientConnectionConsentStatus(status) {
20
+ return status === 408 || status === 429 || status >= 500;
21
+ }
22
+ function shouldGrantConnectionUserConsent(requirement, runningInDevPlayer) {
23
+ return runningInDevPlayer || !requirement.sharedConnectionId;
24
+ }
25
+ function getConnectionNamesRequiringAclGrant(connectionRefs, connectionRequirements) {
26
+ const connectionNames = [];
27
+ const seen = new Set();
28
+ for (const requirement of connectionRequirements) {
29
+ if (!shouldGrantConnectionUserConsent(requirement, false)) continue;
30
+ const connectionName = requirement.dataSources.map(dataSource => connectionRefs[dataSource]?.connectionName).find(selectedName => Boolean(selectedName));
31
+ if (!connectionName || seen.has(connectionName)) continue;
32
+ seen.add(connectionName);
33
+ connectionNames.push(connectionName);
34
+ }
35
+ return connectionNames;
36
+ }
37
+ function invalidateFailedAclGrants(result, failedConnectionNames) {
38
+ if (failedConnectionNames.size === 0) return;
39
+ for (const requirement of result.connectionRequirements) {
40
+ const selected = requirement.dataSources.map(dataSource => result.connectionRefs[dataSource]).find(Boolean);
41
+ if (!selected || !failedConnectionNames.has(selected.connectionName)) continue;
42
+ for (const dataSource of requirement.dataSources) {
43
+ const reference = result.connectionRefs[dataSource];
44
+ if (reference) reference.connectionName = '';
45
+ }
46
+ if (!result.missingConnectionReferences.some(item => item.localRefId === requirement.localRefId)) {
47
+ result.missingConnectionReferences.push(requirement);
48
+ }
49
+ if (!result.missingConnectors.includes(requirement.apiId)) {
50
+ result.missingConnectors.push(requirement.apiId);
51
+ }
52
+ }
53
+ }
54
+ function selectLaunchConnection(result, localRefId, connectionId) {
55
+ const requirement = result.connectionRequirements.find(item => item.localRefId === localRefId);
56
+ const candidate = result.connectionCandidates[localRefId]?.find(item => (0, _disambiguate.connectionIdsEqual)(item.id, connectionId));
57
+ if (!requirement || !candidate) return false;
58
+ for (const dataSource of requirement.dataSources) {
59
+ const reference = result.connectionRefs[dataSource];
60
+ if (reference) reference.connectionName = candidate.id;
61
+ }
62
+ result.missingConnectionReferences = result.missingConnectionReferences.filter(item => item.localRefId !== localRefId);
63
+ if (!result.missingConnectionReferences.some(item => item.apiId === requirement.apiId)) {
64
+ result.missingConnectors = result.missingConnectors.filter(apiId => apiId !== requirement.apiId);
65
+ }
66
+ return true;
67
+ }
68
+ function getUnregisteredConnectionRequirements(result, usages = result.registeredConnectionUsages) {
69
+ return result.connectionRequirements.filter(requirement => {
70
+ const selectedConnectionId = requirement.dataSources.map(dataSource => result.connectionRefs[dataSource]?.connectionName).find(Boolean);
71
+ if (!selectedConnectionId) return true;
72
+ return !usages.some(usage => usage.reference.toLowerCase() === requirement.localRefId.toLowerCase() && (0, _types.normalizeApiId)(usage.apiId) === requirement.apiId && (0, _disambiguate.connectionIdsEqual)(usage.connectionId, selectedConnectionId) && (usage.appActions.length === 0 || (requirement.appActions ?? []).every(action => usage.appActions.includes(action))));
73
+ });
74
+ }
75
+ function applyRegisteredConnectionSelections(result, usages) {
76
+ for (const requirement of result.connectionRequirements) {
77
+ const usage = usages.find(item => item.reference.toLowerCase() === requirement.localRefId.toLowerCase() && (0, _types.normalizeApiId)(item.apiId) === requirement.apiId);
78
+ if (!usage) continue;
79
+ const candidate = result.connectionCandidates[requirement.localRefId]?.find(item => (0, _disambiguate.connectionIdsEqual)(item.id, usage.connectionId));
80
+ if (candidate) selectLaunchConnection(result, requirement.localRefId, candidate.id);
81
+ }
82
+ }
83
+ function hasRegisteredConnectionConsent(result, usages = result.registeredConnectionUsages) {
84
+ return getUnregisteredConnectionRequirements(result, usages).length === 0;
85
+ }
86
+ function applyRegisteredConnectionUsages(result, usages) {
87
+ applyRegisteredConnectionSelections(result, usages);
88
+ result.registeredConnectionUsages = usages;
89
+ result.requiresConnectionConsent = getUnregisteredConnectionRequirements(result, usages).length > 0;
90
+ }
91
+ function shouldPersistConnectionUsages(runningInDevPlayer, appId) {
92
+ return !runningInDevPlayer && Boolean(appId);
93
+ }
94
+ function shouldShowConnectionReview(runningInDevPlayer, requiresConnectionConsent, hasResourceConsents) {
95
+ return !runningInDevPlayer && (requiresConnectionConsent || hasResourceConsents);
96
+ }
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.connectionIdsEqual = connectionIdsEqual;
6
7
  exports.disambiguateConnections = disambiguateConnections;
7
8
  exports.extractConnectionId = extractConnectionId;
8
9
  var _types = require("./types.js");
@@ -35,11 +36,20 @@ var _types = require("./types.js");
35
36
  function disambiguateConnections(connectionReferences, allConnectionsByApiId) {
36
37
  const resolutions = [];
37
38
  for (const [localRefId, ref] of Object.entries(connectionReferences)) {
38
- const apiId = ref.id;
39
- const all = allConnectionsByApiId[apiId] ?? [];
39
+ const apiId = (0, _types.normalizeApiId)(ref.id);
40
+ const all = allConnectionsByApiId[apiId] ?? allConnectionsByApiId[ref.id] ?? [];
40
41
  const connected = all.filter(c => c.status === _types.ConnectionStatus.Connected);
41
42
  let result;
42
- if (connected.length === 1) {
43
+ if (ref.sharedConnectionId) {
44
+ const sharedId = extractConnectionId(ref.sharedConnectionId);
45
+ const shared = connected.find(connection => connectionIdsEqual(connection.id, sharedId));
46
+ result = shared ? {
47
+ kind: 'resolved',
48
+ connectionId: shared.id
49
+ } : {
50
+ kind: 'missing'
51
+ };
52
+ } else if (connected.length === 1) {
43
53
  result = {
44
54
  kind: 'resolved',
45
55
  connectionId: connected[0].id
@@ -73,16 +83,14 @@ function disambiguateConnections(connectionReferences, allConnectionsByApiId) {
73
83
  * "abc12345def6789012345678901234ab" (bare UUID, no dashes)
74
84
  * "abc12345-def6-7890-1234-5678901234ab" (UUID with dashes)
75
85
  *
76
- * Returns the 32-char hex ID (dashes stripped) or the raw string if no UUID
77
- * pattern is found.
86
+ * Returns the terminal resource name exactly as supplied by Power Platform.
87
+ * Some connectors require dashed GUIDs while others use compact IDs.
78
88
  */
79
89
  function extractConnectionId(rawName) {
80
- // Match a standard UUID (with or without dashes) at the end of the string.
81
- const match = rawName.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i);
82
- if (match) {
83
- return match[1].replace(/-/g, '');
84
- }
85
- // Some connections use a 32-char hex ID without dashes, after a slash.
86
90
  const slashIdx = rawName.lastIndexOf('/');
87
91
  return slashIdx >= 0 ? rawName.slice(slashIdx + 1) : rawName;
92
+ }
93
+ function connectionIdsEqual(left, right) {
94
+ const normalize = value => extractConnectionId(value).replace(/-/g, '').toLowerCase();
95
+ return normalize(left) === normalize(right);
88
96
  }
@@ -0,0 +1,347 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.applyAclGrants = applyAclGrants;
7
+ exports.resolveViaStaticRefs = resolveViaStaticRefs;
8
+ var _PowerPlatformConnectionApi = require("./PowerPlatformConnectionApi.js");
9
+ var _connectionState = require("./connectionState.js");
10
+ var _PowerPlatformEnvironmentApi = require("../platform/PowerPlatformEnvironmentApi.js");
11
+ var _DataverseGlobalDiscoveryApi = require("../platform/DataverseGlobalDiscoveryApi.js");
12
+ var _disambiguate = require("../connections/disambiguate.js");
13
+ var _types = require("./types.js");
14
+ var _index = require("../telemetry/index.js");
15
+ /*!
16
+ * power-apps-native-host — resolveConnections
17
+ *
18
+ * Pure async helpers for the two connection-resolution strategies used by
19
+ * useConnectionRefs:
20
+ *
21
+ * • resolveViaStaticRefs — per-connector resolution using the static
22
+ * connectionReferences map from power.config.json. Used only by Dev Player
23
+ * for unpublished local apps. Handles pre-disambiguation ACL grants so
24
+ * inaccessible connections are excluded before the user is asked to pick.
25
+ *
26
+ * • applyAclGrants — post-resolution user consent used by the fast path
27
+ * (production APKs via fetchAppLaunchData).
28
+ *
29
+ * Both helpers return / consume the shared AppLaunchResult shape so the
30
+ * hook orchestrator can handle them uniformly.
31
+ */
32
+
33
+ const API_VERSION = '1';
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // ConnectorSchema
37
+ // ---------------------------------------------------------------------------
38
+
39
+ /**
40
+ * Connector schema entry generated by `generate-connector-schemas`.
41
+ * Keyed by data source name in the `schemaMap` passed to `useConnectionRefs`.
42
+ */
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // resolveViaStaticRefs
46
+ // ---------------------------------------------------------------------------
47
+
48
+ /**
49
+ * Resolve connections from the static `connectionReferences` map.
50
+ *
51
+ * Steps:
52
+ * 1. Build an apiId → schema lookup.
53
+ * 2. In parallel: fetch the Dataverse instanceUrl and all connection instances
54
+ * for every connector.
55
+ * 3. If `isvClientId` is set, run pre-disambiguation user consent — connections
56
+ * where the grant fails are marked `NeedsAclGrant` and excluded from
57
+ * resolution, prompting the user to create a new connection.
58
+ * 4. Disambiguate: resolve single matches, invoke callbacks for ambiguous /
59
+ * missing cases, perform one-shot retries when `onMissingConnection` returns
60
+ * `true`.
61
+ * 5. Build and return an `AppLaunchResult`-shaped object.
62
+ */
63
+ async function resolveViaStaticRefs({
64
+ connectionReferences,
65
+ schemaMap,
66
+ environmentId,
67
+ region,
68
+ acquireToken,
69
+ token,
70
+ isvClientId,
71
+ onDisambiguationNeeded,
72
+ onMissingConnection
73
+ }) {
74
+ const directConnectionReferences = Object.fromEntries(Object.entries(connectionReferences).filter(([, reference]) => !(0, _types.isCompositeConnectionApiId)(reference.id)));
75
+ const flowConnectionReferences = Object.fromEntries(Object.entries(connectionReferences).filter(([, reference]) => (0, _types.getConnectorId)(reference.id) === 'shared_logicflows'));
76
+ // Build apiId → schema lookup from the static refs.
77
+ const schemaByApiId = Object.fromEntries(Object.values(directConnectionReferences).map(ref => {
78
+ const schema = ref.dataSources.map(ds => schemaMap[ds]).find(Boolean);
79
+ return schema ? [(0, _types.normalizeApiId)(ref.id), schema] : null;
80
+ }).filter(entry => entry !== null));
81
+ await Promise.all(Object.values({
82
+ ...directConnectionReferences,
83
+ ...flowConnectionReferences
84
+ }).map(async reference => {
85
+ const apiId = (0, _types.normalizeApiId)(reference.id);
86
+ if (schemaByApiId[apiId]) return;
87
+ const metadata = await (0, _PowerPlatformConnectionApi.fetchConnectorMetadata)((0, _types.getConnectorId)(reference.id), environmentId, region, token);
88
+ if (!metadata?.primaryRuntimeUrl) return;
89
+ schemaByApiId[apiId] = {
90
+ name: metadata.name,
91
+ properties: {
92
+ primaryRuntimeUrl: metadata.primaryRuntimeUrl,
93
+ scopes: metadata.scopes
94
+ }
95
+ };
96
+ }));
97
+ const base = (0, _PowerPlatformEnvironmentApi.buildEnvironmentEndpoint)(environmentId, region);
98
+ const headers = {
99
+ Authorization: `Bearer ${token}`
100
+ };
101
+
102
+ // Fetch Dataverse instanceUrl and all connection instances in parallel.
103
+ const [instanceUrl, ...connResults] = await Promise.all([(0, _DataverseGlobalDiscoveryApi.fetchInstanceUrl)(environmentId, region, acquireToken, token), ...Object.entries(directConnectionReferences).map(async ([localRefId, ref]) => {
104
+ const apiId = (0, _types.normalizeApiId)(ref.id);
105
+ const schema = schemaByApiId[apiId];
106
+ if (!schema) {
107
+ return {
108
+ localRefId,
109
+ apiId,
110
+ dataSources: ref.dataSources,
111
+ instances: []
112
+ };
113
+ }
114
+ const url = `${base}/connectivity/connectors/${schema.name}/connections` + `?api-version=${API_VERSION}&$filter=environment eq '${environmentId}'`;
115
+ try {
116
+ const res = await _index.platformHttpClient.request(url, {
117
+ headers
118
+ });
119
+ if (!res.ok) {
120
+ return {
121
+ localRefId,
122
+ apiId,
123
+ dataSources: ref.dataSources,
124
+ instances: []
125
+ };
126
+ }
127
+ const body = await res.json();
128
+ const instances = (body.value ?? []).map(c => {
129
+ const connected = c.properties?.statuses?.[0]?.status === 'Connected';
130
+ return {
131
+ id: (0, _disambiguate.extractConnectionId)(c.name),
132
+ name: c.name,
133
+ apiId,
134
+ ownerId: c.properties?.createdBy?.id,
135
+ status: connected ? _types.ConnectionStatus.Connected : _types.ConnectionStatus.NotConnected,
136
+ displayName: c.properties?.displayName,
137
+ isAuthenticated: connected
138
+ };
139
+ });
140
+ return {
141
+ localRefId,
142
+ apiId,
143
+ dataSources: ref.dataSources,
144
+ instances
145
+ };
146
+ } catch {
147
+ return {
148
+ localRefId,
149
+ apiId,
150
+ dataSources: ref.dataSources,
151
+ instances: []
152
+ };
153
+ }
154
+ })]);
155
+
156
+ // Pre-disambiguation delegated consent grants (ISV apps only).
157
+ //
158
+ // Connections where the grant fails are marked NeedsAclGrant so
159
+ // disambiguation treats them as unavailable and surfaces the
160
+ // "missing connection" flow, steering the user to create a new one. Fixed
161
+ if (isvClientId) {
162
+ const consentToken = await acquireToken([(0, _PowerPlatformEnvironmentApi.connectionUserConsentScope)(region)]);
163
+ if (consentToken) {
164
+ const attemptedGrants = new Set();
165
+ await Promise.all(connResults.map(async r => {
166
+ const reference = directConnectionReferences[r.localRefId];
167
+ if (!reference || !(0, _connectionState.shouldGrantConnectionUserConsent)(reference, true)) return;
168
+ const connId = schemaByApiId[r.apiId]?.name;
169
+ if (!connId) return;
170
+ await Promise.all(r.instances.map(async inst => {
171
+ if (inst.status !== _types.ConnectionStatus.Connected) return;
172
+ if (reference?.sharedConnectionId && !(0, _disambiguate.connectionIdsEqual)(inst.id, reference.sharedConnectionId)) return;
173
+ const grantKey = `${connId.toLowerCase()}/${inst.id.toLowerCase()}`;
174
+ if (attemptedGrants.has(grantKey)) return;
175
+ attemptedGrants.add(grantKey);
176
+ const ok = await (0, _PowerPlatformConnectionApi.grantConnectionUserConsent)(connId, inst.id, environmentId, region, consentToken);
177
+ if (!ok) inst.status = _types.ConnectionStatus.NeedsAclGrant;
178
+ }));
179
+ }));
180
+ } else {
181
+ for (const result of connResults) {
182
+ for (const instance of result.instances) {
183
+ if (instance.status === _types.ConnectionStatus.Connected) {
184
+ instance.status = _types.ConnectionStatus.NeedsAclGrant;
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ // Disambiguation.
192
+ const allConnectionsByApiId = {};
193
+ for (const r of connResults) {
194
+ allConnectionsByApiId[r.apiId] = r.instances;
195
+ }
196
+ const disambiguationResults = (0, _disambiguate.disambiguateConnections)(directConnectionReferences, allConnectionsByApiId);
197
+ const resolvedIds = {};
198
+ const unresolvedApiIds = [];
199
+ for (const dr of disambiguationResults) {
200
+ if (dr.result.kind === 'resolved') {
201
+ resolvedIds[dr.localRefId] = dr.result.connectionId;
202
+ } else if (dr.result.kind === 'ambiguous') {
203
+ const picked = onDisambiguationNeeded ? await onDisambiguationNeeded({
204
+ localRefId: dr.localRefId,
205
+ apiId: dr.apiId,
206
+ candidates: dr.result.candidates
207
+ }) : null;
208
+ if (picked) {
209
+ resolvedIds[dr.localRefId] = picked;
210
+ } else {
211
+ resolvedIds[dr.localRefId] = '';
212
+ unresolvedApiIds.push((0, _types.normalizeApiId)(dr.apiId));
213
+ }
214
+ } else {
215
+ // kind === 'missing'
216
+ let retried = false;
217
+ if (onMissingConnection) {
218
+ retried = await onMissingConnection({
219
+ localRefId: dr.localRefId,
220
+ apiId: dr.apiId
221
+ });
222
+ }
223
+ if (retried) {
224
+ // One-shot retry for this specific connector.
225
+ const schema = schemaByApiId[dr.apiId];
226
+ if (schema) {
227
+ try {
228
+ const url = `${base}/connectivity/connectors/${schema.name}/connections` + `?api-version=${API_VERSION}&$filter=environment eq '${environmentId}'`;
229
+ const res = await _index.platformHttpClient.request(url, {
230
+ headers
231
+ });
232
+ if (res.ok) {
233
+ const body = await res.json();
234
+ const retryInstances = (body.value ?? []).map(c => {
235
+ const connected = c.properties?.statuses?.[0]?.status === 'Connected';
236
+ return {
237
+ id: (0, _disambiguate.extractConnectionId)(c.name),
238
+ name: c.name,
239
+ apiId: dr.apiId,
240
+ status: connected ? _types.ConnectionStatus.Connected : _types.ConnectionStatus.NotConnected,
241
+ isAuthenticated: connected
242
+ };
243
+ });
244
+ const connected = retryInstances.find(i => i.status === _types.ConnectionStatus.Connected);
245
+ if (connected) {
246
+ resolvedIds[dr.localRefId] = connected.id;
247
+ continue;
248
+ }
249
+ }
250
+ } catch {
251
+ // Fall through to missing.
252
+ }
253
+ }
254
+ }
255
+ resolvedIds[dr.localRefId] = '';
256
+ unresolvedApiIds.push((0, _types.normalizeApiId)(dr.apiId));
257
+ }
258
+ }
259
+ const dataverseOrgUrl = (instanceUrl ?? '').replace(/\/$/, '');
260
+
261
+ // Build the final AppConnectionReference map.
262
+ const connectionRefs = {};
263
+ for (const [localRefId, ref] of Object.entries(directConnectionReferences)) {
264
+ const normalizedApiId = (0, _types.normalizeApiId)(ref.id);
265
+ const schema = schemaByApiId[normalizedApiId];
266
+ const connectionName = resolvedIds[localRefId] ?? '';
267
+ const isDataverse = ref.id.includes('commondataserviceforapps');
268
+ const entry = {
269
+ apiId: normalizedApiId,
270
+ runtimeUrl: schema?.properties.primaryRuntimeUrl ?? '',
271
+ connectionName,
272
+ datasetName: isDataverse ? dataverseOrgUrl : (0, _types.getConnectionDatasetName)(ref)
273
+ };
274
+ for (const ds of ref.dataSources) {
275
+ connectionRefs[ds] = entry;
276
+ }
277
+ }
278
+ for (const ref of Object.values(flowConnectionReferences)) {
279
+ const normalizedApiId = (0, _types.normalizeApiId)(ref.id);
280
+ const schema = schemaByApiId[normalizedApiId];
281
+ const entry = {
282
+ apiId: normalizedApiId,
283
+ runtimeUrl: schema?.properties.primaryRuntimeUrl ?? '',
284
+ connectionName: (0, _types.getFlowConnectionName)(ref),
285
+ datasetName: ''
286
+ };
287
+ for (const dataSource of (0, _types.getFlowDataSourceNames)(ref)) {
288
+ connectionRefs[dataSource] = entry;
289
+ }
290
+ }
291
+ const scopesByApiId = Object.fromEntries(Object.entries(schemaByApiId).map(([apiId, schema]) => [apiId, {
292
+ will: schema.properties.scopes?.will ?? [],
293
+ wont: schema.properties.scopes?.wont ?? []
294
+ }]));
295
+ const requirements = (0, _types.buildConnectionRequirements)(connectionReferences, scopesByApiId);
296
+ const requirementsByLocalRefId = Object.fromEntries(requirements.map(requirement => [requirement.localRefId, requirement]));
297
+ const missingConnectionReferences = Object.entries(resolvedIds).filter(([, connectionId]) => !connectionId).map(([localRefId]) => requirementsByLocalRefId[localRefId]).filter(requirement => Boolean(requirement));
298
+ const connectionCandidates = Object.fromEntries(connResults.map(result => [result.localRefId, result.instances]));
299
+ return {
300
+ connectionRefs,
301
+ dataverseOrgUrl,
302
+ databaseReferences: {},
303
+ missingConnectors: [...new Set(unresolvedApiIds)],
304
+ missingConnectionReferences,
305
+ connectionRequirements: Object.values(requirementsByLocalRefId),
306
+ connectionCandidates,
307
+ resourceConsents: [],
308
+ configurationErrors: (0, _types.findConnectionDataSourceConflicts)(requirements).map(dataSource => `Data source "${dataSource}" is assigned to multiple connection references.`),
309
+ registeredConnectionUsages: [],
310
+ requiresConnectionConsent: requirements.length > 0
311
+ };
312
+ }
313
+
314
+ // ---------------------------------------------------------------------------
315
+ // applyAclGrants
316
+ // ---------------------------------------------------------------------------
317
+
318
+ /**
319
+ * Run idempotent post-resolution delegated consent grants for the calling app.
320
+ *
321
+ * Used by the fast path (production APKs via `fetchAppLaunchData`) where the
322
+ * launch API has already resolved the user's connections. Grants are applied
323
+ * only to user-selected connections; fixed shared connections are already
324
+ * authorized by their owner and must not receive delegated user consent.
325
+ *
326
+ * For the slow path the grants run before disambiguation inside
327
+ * `resolveViaStaticRefs`, where they can still influence which connections
328
+ * are considered available.
329
+ *
330
+ * Returns the connection names whose ACL grants failed so callers can fail closed.
331
+ */
332
+ async function applyAclGrants(connectionRefs, connectionRequirements, environmentId, region, acquireToken) {
333
+ const connectionNames = (0, _connectionState.getConnectionNamesRequiringAclGrant)(connectionRefs, connectionRequirements);
334
+ if (connectionNames.length === 0) return new Set();
335
+ const connectionNamesSet = new Set(connectionNames);
336
+ const consentToken = await acquireToken([(0, _PowerPlatformEnvironmentApi.connectionUserConsentScope)(region)]);
337
+ if (!consentToken) return new Set(connectionNames);
338
+ const seen = new Set();
339
+ const failed = new Set();
340
+ await Promise.all(Object.values(connectionRefs).map(async ref => {
341
+ if (!ref.connectionName || !connectionNamesSet.has(ref.connectionName) || seen.has(ref.connectionName)) return;
342
+ seen.add(ref.connectionName);
343
+ const granted = await (0, _PowerPlatformConnectionApi.grantConnectionUserConsent)(ref.apiId, ref.connectionName, environmentId, region, consentToken);
344
+ if (!granted) failed.add(ref.connectionName);
345
+ }));
346
+ return failed;
347
+ }