@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.
- package/README.md +21 -10
- package/compatibility/current.json +31 -4
- package/lib/NOTICE.txt +1325 -24
- package/lib/commonjs/auth/AuthContext.js +110 -33
- package/lib/commonjs/bridge/NativePowerAppsBridge.js +11 -18
- package/lib/commonjs/bridge/PowerPagesBridge.js +27 -8
- package/lib/commonjs/bridge/bridgeState.js +40 -0
- package/lib/commonjs/config/babelConfig.js +13 -0
- package/lib/commonjs/config/expoConfig.js +71 -0
- package/lib/commonjs/config/metroConfig.js +70 -0
- package/lib/commonjs/config/metroLogger.js +182 -0
- package/lib/commonjs/config/tamaguiConfig.js +98 -0
- package/lib/commonjs/connections/ConnectionSetupScreen.js +459 -80
- package/lib/commonjs/connections/PowerPlatformConnectionApi.js +946 -0
- package/lib/commonjs/connections/connectionMetadata.js +127 -0
- package/lib/commonjs/connections/connectionState.js +96 -0
- package/lib/commonjs/connections/disambiguate.js +19 -11
- package/lib/commonjs/connections/resolveConnections.js +348 -0
- package/lib/commonjs/connections/types.js +106 -0
- package/lib/commonjs/{platform → connections}/useConnectionRefs.js +130 -65
- package/lib/commonjs/connections/useConnectionSetup.js +111 -52
- package/lib/commonjs/controls/FilePicker.js +6 -0
- package/lib/commonjs/controls/ImagePicker.js +8 -0
- package/lib/commonjs/index.js +167 -4
- package/lib/commonjs/logger.js +9 -6
- package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +48 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
- package/lib/commonjs/platform/DataverseDataSources.js +18 -0
- package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +94 -0
- package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
- package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
- package/lib/commonjs/provider/PowerAppsHostProvider.js +157 -25
- package/lib/commonjs/provider/PowerAppsProvider.js +178 -134
- package/lib/commonjs/provider/SessionDetailsGesture.js +208 -0
- package/lib/commonjs/telemetry/OfflineSdkTelemetry.js +95 -0
- package/lib/commonjs/telemetry/OfflineSdkTelemetry.web.js +9 -0
- package/lib/commonjs/telemetry/index.js +22 -3
- package/lib/module/auth/AuthContext.js +110 -33
- package/lib/module/bridge/NativePowerAppsBridge.js +12 -19
- package/lib/module/bridge/PowerPagesBridge.js +27 -8
- package/lib/module/bridge/bridgeState.js +34 -0
- package/lib/module/config/babelConfig.js +9 -0
- package/lib/module/config/expoConfig.js +67 -0
- package/lib/module/config/metroConfig.js +65 -0
- package/lib/module/config/metroLogger.js +175 -0
- package/lib/module/config/tamaguiConfig.js +93 -0
- package/lib/module/connections/ConnectionSetupScreen.js +460 -81
- package/lib/module/connections/PowerPlatformConnectionApi.js +932 -0
- package/lib/module/connections/connectionMetadata.js +112 -0
- package/lib/module/connections/connectionState.js +82 -0
- package/lib/module/connections/disambiguate.js +19 -12
- package/lib/module/connections/resolveConnections.js +343 -0
- package/lib/module/connections/types.js +91 -0
- package/lib/module/{platform → connections}/useConnectionRefs.js +131 -66
- package/lib/module/connections/useConnectionSetup.js +113 -54
- package/lib/module/controls/FilePicker.js +6 -0
- package/lib/module/controls/ImagePicker.js +8 -0
- package/lib/module/index.js +14 -4
- package/lib/module/logger.js +8 -6
- package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +44 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
- package/lib/module/platform/DataverseDataSources.js +13 -0
- package/lib/module/platform/DataverseGlobalDiscoveryApi.js +89 -0
- package/lib/module/platform/GlobalDiscovery.js +45 -0
- package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
- package/lib/module/provider/PowerAppsHostProvider.js +160 -28
- package/lib/module/provider/PowerAppsProvider.js +182 -138
- package/lib/module/provider/SessionDetailsGesture.js +203 -0
- package/lib/module/telemetry/OfflineSdkTelemetry.js +91 -0
- package/lib/module/telemetry/OfflineSdkTelemetry.web.js +5 -0
- package/lib/module/telemetry/index.js +15 -4
- package/lib/typescript/commonjs/auth/AuthContext.d.ts +3 -1
- package/lib/typescript/commonjs/auth/AuthContext.web.d.ts +1 -0
- package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/commonjs/config/babelConfig.d.ts +12 -0
- package/lib/typescript/commonjs/config/expoConfig.d.ts +21 -0
- package/lib/typescript/commonjs/config/metroConfig.d.ts +6 -0
- package/lib/typescript/commonjs/config/metroLogger.d.ts +21 -0
- package/lib/typescript/commonjs/config/tamaguiConfig.d.ts +1792 -0
- package/lib/typescript/commonjs/connections/ConnectionSetupScreen.d.ts +28 -7
- package/lib/typescript/commonjs/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
- package/lib/typescript/commonjs/connections/connectionMetadata.d.ts +66 -0
- package/lib/typescript/commonjs/connections/connectionState.d.ts +16 -0
- package/lib/typescript/commonjs/connections/disambiguate.d.ts +4 -2
- package/lib/typescript/commonjs/{platform → connections}/resolveConnections.d.ts +22 -20
- package/lib/typescript/commonjs/connections/types.d.ts +129 -1
- package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +36 -25
- package/lib/typescript/commonjs/connections/useConnectionSetup.d.ts +12 -8
- package/lib/typescript/commonjs/controls/FilePicker.d.ts +7 -1
- package/lib/typescript/commonjs/controls/ImagePicker.d.ts +9 -1
- package/lib/typescript/commonjs/index.d.ts +18 -10
- package/lib/typescript/commonjs/logger.d.ts +4 -4
- package/lib/typescript/commonjs/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
- package/lib/typescript/commonjs/platform/DataverseDataSources.d.ts +28 -0
- package/lib/typescript/commonjs/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
- package/lib/typescript/commonjs/platform/GlobalDiscovery.d.ts +4 -0
- package/lib/typescript/commonjs/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
- package/lib/typescript/commonjs/provider/PowerAppsHostProvider.d.ts +29 -18
- package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +54 -9
- package/lib/typescript/commonjs/provider/SessionDetailsGesture.d.ts +13 -0
- package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.d.ts +15 -0
- package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
- package/lib/typescript/commonjs/telemetry/index.d.ts +13 -1
- package/lib/typescript/module/auth/AuthContext.d.ts +3 -1
- package/lib/typescript/module/auth/AuthContext.web.d.ts +1 -0
- package/lib/typescript/module/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/module/config/babelConfig.d.ts +12 -0
- package/lib/typescript/module/config/expoConfig.d.ts +21 -0
- package/lib/typescript/module/config/metroConfig.d.ts +6 -0
- package/lib/typescript/module/config/metroLogger.d.ts +21 -0
- package/lib/typescript/module/config/tamaguiConfig.d.ts +1792 -0
- package/lib/typescript/module/connections/ConnectionSetupScreen.d.ts +28 -7
- package/lib/typescript/module/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
- package/lib/typescript/module/connections/connectionMetadata.d.ts +66 -0
- package/lib/typescript/module/connections/connectionState.d.ts +16 -0
- package/lib/typescript/module/connections/disambiguate.d.ts +4 -2
- package/lib/typescript/module/{platform → connections}/resolveConnections.d.ts +22 -20
- package/lib/typescript/module/connections/types.d.ts +129 -1
- package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +36 -25
- package/lib/typescript/module/connections/useConnectionSetup.d.ts +12 -8
- package/lib/typescript/module/controls/FilePicker.d.ts +7 -1
- package/lib/typescript/module/controls/ImagePicker.d.ts +9 -1
- package/lib/typescript/module/index.d.ts +18 -10
- package/lib/typescript/module/logger.d.ts +4 -4
- package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
- package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
- package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
- package/lib/typescript/module/platform/DataverseDataSources.d.ts +28 -0
- package/lib/typescript/module/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
- package/lib/typescript/module/platform/GlobalDiscovery.d.ts +4 -0
- package/lib/typescript/module/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
- package/lib/typescript/module/provider/PowerAppsHostProvider.d.ts +29 -18
- package/lib/typescript/module/provider/PowerAppsProvider.d.ts +54 -9
- package/lib/typescript/module/provider/SessionDetailsGesture.d.ts +13 -0
- package/lib/typescript/module/telemetry/OfflineSdkTelemetry.d.ts +15 -0
- package/lib/typescript/module/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
- package/lib/typescript/module/telemetry/index.d.ts +13 -1
- package/package.json +52 -13
- package/scripts/build-codegen-package.js +283 -0
- package/scripts/start-web.mjs +9 -5
- package/scripts/upgrade/runtime.js +139 -24
- package/scripts/upgrade-authoring.js +274 -180
- package/scripts/upgrade.js +10 -16
- package/src/config/generated-config.d.ts +4 -0
- package/src/config/index.d.ts +3 -0
- package/src/config/tsconfig.json +26 -0
- package/lib/commonjs/platform/PowerPlatformConnectionApi.js +0 -606
- package/lib/commonjs/platform/resolveConnections.js +0 -264
- package/lib/module/platform/PowerPlatformConnectionApi.js +0 -595
- package/lib/module/platform/resolveConnections.js +0 -259
|
@@ -4,6 +4,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.ConnectionStatus = void 0;
|
|
7
|
+
exports.buildConnectionRequirements = buildConnectionRequirements;
|
|
8
|
+
exports.buildConnectionResolutionKey = buildConnectionResolutionKey;
|
|
9
|
+
exports.findConnectionDataSourceConflicts = findConnectionDataSourceConflicts;
|
|
10
|
+
exports.getConnectionDatasetName = getConnectionDatasetName;
|
|
11
|
+
exports.getConnectorId = getConnectorId;
|
|
12
|
+
exports.getFlowConnectionName = getFlowConnectionName;
|
|
13
|
+
exports.getFlowDataSourceNames = getFlowDataSourceNames;
|
|
14
|
+
exports.hasCompleteStaticConnectionConfig = hasCompleteStaticConnectionConfig;
|
|
15
|
+
exports.isCompositeConnectionApiId = isCompositeConnectionApiId;
|
|
16
|
+
exports.normalizeApiId = normalizeApiId;
|
|
7
17
|
/*!
|
|
8
18
|
* power-apps-native-host — connection disambiguation types
|
|
9
19
|
*
|
|
@@ -24,7 +34,100 @@ let ConnectionStatus = exports.ConnectionStatus = /*#__PURE__*/function (Connect
|
|
|
24
34
|
ConnectionStatus["NotConnected"] = "NotConnected";
|
|
25
35
|
return ConnectionStatus;
|
|
26
36
|
}({});
|
|
37
|
+
function normalizeApiId(apiId) {
|
|
38
|
+
const connectorId = apiId.split('/').filter(Boolean).pop() ?? apiId;
|
|
39
|
+
return `/providers/Microsoft.PowerApps/apis/${connectorId.toLowerCase()}`;
|
|
40
|
+
}
|
|
41
|
+
function getConnectorId(apiId) {
|
|
42
|
+
return (apiId.split('/').filter(Boolean).pop() ?? apiId).toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
function getConnectionDatasetName(reference) {
|
|
45
|
+
const datasetNames = Object.keys(reference.dataSets ?? {});
|
|
46
|
+
return datasetNames.length === 1 ? datasetNames[0] : '';
|
|
47
|
+
}
|
|
48
|
+
function getFlowConnectionName(reference) {
|
|
49
|
+
const workflowNameHint = reference.parameterHintsV2?.workflowName?.value;
|
|
50
|
+
const workflowEntityIdHint = reference.parameterHintsV2?.workflowEntityId?.value;
|
|
51
|
+
return reference.workflowDetails?.workflowName ?? (typeof workflowNameHint === 'string' ? workflowNameHint : undefined) ?? reference.workflowDetails?.workflowEntityId ?? (typeof workflowEntityIdHint === 'string' ? workflowEntityIdHint : '');
|
|
52
|
+
}
|
|
53
|
+
function getFlowDataSourceNames(reference) {
|
|
54
|
+
const names = new Set(reference.dataSources);
|
|
55
|
+
const workflowDisplayNameHint = reference.parameterHintsV2?.workflowDisplayName?.value;
|
|
56
|
+
const displayName = reference.workflowDetails?.workflowDisplayName ?? (typeof workflowDisplayNameHint === 'string' ? workflowDisplayNameHint : undefined);
|
|
57
|
+
if (displayName) names.add(`${displayName.charAt(0).toLowerCase()}${displayName.slice(1)}`);
|
|
58
|
+
return [...names];
|
|
59
|
+
}
|
|
60
|
+
function buildConnectionRequirements(connectionReferences, scopesByApiId = {}) {
|
|
61
|
+
return Object.entries(connectionReferences).filter(([, reference]) => !isCompositeConnectionApiId(reference.id)).map(([localRefId, reference]) => {
|
|
62
|
+
const appActions = new Set(reference.appActions ?? []);
|
|
63
|
+
let isFlowDependent = false;
|
|
64
|
+
for (const dependentId of reference.dependents ?? []) {
|
|
65
|
+
const dependent = connectionReferences[dependentId];
|
|
66
|
+
if (!dependent || getConnectorId(dependent.id) !== 'shared_logicflows') continue;
|
|
67
|
+
isFlowDependent = true;
|
|
68
|
+
for (const action of dependent.nestedActions ?? []) {
|
|
69
|
+
const hint = action.flowConnectionRef ? dependent.parameterHintsV2?.[action.flowConnectionRef] : undefined;
|
|
70
|
+
if (hint?.value === localRefId && action.actionName) appActions.add(action.actionName);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const apiId = normalizeApiId(reference.id);
|
|
74
|
+
return {
|
|
75
|
+
localRefId,
|
|
76
|
+
apiId,
|
|
77
|
+
connectorId: getConnectorId(reference.id),
|
|
78
|
+
dataSources: reference.dataSources,
|
|
79
|
+
displayName: reference.displayName,
|
|
80
|
+
iconUri: reference.iconUri,
|
|
81
|
+
appActions: [...appActions],
|
|
82
|
+
sharedConnectionId: reference.sharedConnectionId,
|
|
83
|
+
gatewayObjectIdHint: reference.gatewayObjectIdHint,
|
|
84
|
+
authenticationType: reference.authenticationType,
|
|
85
|
+
parameterSetName: reference.parameterSetName,
|
|
86
|
+
apiScopes: scopesByApiId[apiId] ?? {
|
|
87
|
+
will: [],
|
|
88
|
+
wont: []
|
|
89
|
+
},
|
|
90
|
+
isFlowDependent
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function isCompositeConnectionApiId(apiId) {
|
|
95
|
+
const connectorId = getConnectorId(apiId);
|
|
96
|
+
return connectorId === 'shared_excel' || connectorId === 'shared_logicflows';
|
|
97
|
+
}
|
|
98
|
+
function findConnectionDataSourceConflicts(requirements) {
|
|
99
|
+
const owners = new Map();
|
|
100
|
+
const conflicts = new Set();
|
|
101
|
+
for (const requirement of requirements) {
|
|
102
|
+
for (const dataSource of requirement.dataSources) {
|
|
103
|
+
const owner = owners.get(dataSource);
|
|
104
|
+
if (owner && owner !== requirement.localRefId) conflicts.add(dataSource);else owners.set(dataSource, requirement.localRefId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return [...conflicts];
|
|
108
|
+
}
|
|
109
|
+
function hasCompleteStaticConnectionConfig(connectionReferences, schemaMap) {
|
|
110
|
+
const references = Object.values(connectionReferences);
|
|
111
|
+
const directReferences = references.filter(reference => !isCompositeConnectionApiId(reference.id));
|
|
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
|
+
}
|
|
114
|
+
function buildConnectionResolutionKey(appId, environmentId, connectionReferences) {
|
|
115
|
+
const references = Object.entries(connectionReferences).sort(([left], [right]) => left.localeCompare(right)).map(([localRefId, reference]) => ({
|
|
116
|
+
localRefId,
|
|
117
|
+
id: reference.id,
|
|
118
|
+
dataSources: [...reference.dataSources].sort(),
|
|
119
|
+
sharedConnectionId: reference.sharedConnectionId ?? '',
|
|
120
|
+
parameterSetName: reference.parameterSetName ?? ''
|
|
121
|
+
}));
|
|
122
|
+
return JSON.stringify({
|
|
123
|
+
appId: appId ?? '',
|
|
124
|
+
environmentId,
|
|
125
|
+
references
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
27
129
|
/** A single connection instance returned by the Power Platform connectivity API. */
|
|
130
|
+
|
|
28
131
|
/**
|
|
29
132
|
* Result of attempting to match a single connection reference to an instance.
|
|
30
133
|
*
|
|
@@ -32,10 +135,12 @@ let ConnectionStatus = exports.ConnectionStatus = /*#__PURE__*/function (Connect
|
|
|
32
135
|
* - `missing` — no connections found for this connector in the user's environment.
|
|
33
136
|
* - `ambiguous` — multiple Connected connections found; the app must pick one.
|
|
34
137
|
*/
|
|
138
|
+
|
|
35
139
|
/**
|
|
36
140
|
* Disambiguation result for a single connection reference (one apiId, possibly
|
|
37
141
|
* mapped to multiple data source names in the final connections map).
|
|
38
142
|
*/
|
|
143
|
+
|
|
39
144
|
/**
|
|
40
145
|
* Callback invoked when a connection reference has multiple Connected candidate
|
|
41
146
|
* connections. The consuming app should present a native picker UI (e.g. a
|
|
@@ -48,6 +153,7 @@ let ConnectionStatus = exports.ConnectionStatus = /*#__PURE__*/function (Connect
|
|
|
48
153
|
* @param context.apiId — connector API identifier
|
|
49
154
|
* @param context.candidates — list of Connected connection instances to choose from
|
|
50
155
|
*/
|
|
156
|
+
|
|
51
157
|
/**
|
|
52
158
|
* Callback invoked when the user has no connection for a required connector.
|
|
53
159
|
*
|
|
@@ -6,13 +6,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.useConnectionRefs = useConnectionRefs;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _isDevPlayer = require("../utils/isDevPlayer.js");
|
|
9
|
-
var _PowerPlatformEnvironmentApi = require("
|
|
10
|
-
var _types = require("../connections/types.js");
|
|
9
|
+
var _PowerPlatformEnvironmentApi = require("../platform/PowerPlatformEnvironmentApi.js");
|
|
11
10
|
var _PowerPlatformConnectionApi = require("./PowerPlatformConnectionApi.js");
|
|
12
11
|
var _resolveConnections = require("./resolveConnections.js");
|
|
12
|
+
var _connectionState = require("./connectionState.js");
|
|
13
13
|
var _logger = require("../logger.js");
|
|
14
14
|
var _index = require("../telemetry/index.js");
|
|
15
15
|
var _NativePowerAppsBridge = require("../bridge/NativePowerAppsBridge.js");
|
|
16
|
+
var _types = require("./types.js");
|
|
16
17
|
/*!
|
|
17
18
|
* power-apps-native-host — useConnectionRefs
|
|
18
19
|
*
|
|
@@ -54,17 +55,10 @@ var _NativePowerAppsBridge = require("../bridge/NativePowerAppsBridge.js");
|
|
|
54
55
|
* disambiguation support for environments where multiple connections exist for
|
|
55
56
|
* the same connector.
|
|
56
57
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* 2. Acquires a Power Platform API token.
|
|
62
|
-
* 3. In parallel: fetches the Dataverse instanceUrl and ALL connections for
|
|
63
|
-
* each configured connector.
|
|
64
|
-
* 4. Runs disambiguation: resolves single matches, invokes `onDisambiguationNeeded`
|
|
65
|
-
* for multiple matches, and invokes `onMissingConnection` for absent ones.
|
|
66
|
-
* 5. Pre-warms the Dataverse token in the MSAL cache.
|
|
67
|
-
* 6. Sets isReady=true with the fully-populated connections map.
|
|
58
|
+
* Outside Dev Player, the published app launch endpoint is authoritative.
|
|
59
|
+
* Dev Player resolves unpublished local references through per-connector APIs.
|
|
60
|
+
* Both paths disambiguate candidates, pre-warm Dataverse authentication, and
|
|
61
|
+
* return a fully populated bridge configuration.
|
|
68
62
|
*/
|
|
69
63
|
function useConnectionRefs({
|
|
70
64
|
isSignedIn,
|
|
@@ -73,6 +67,7 @@ function useConnectionRefs({
|
|
|
73
67
|
environmentId,
|
|
74
68
|
region = 'prod',
|
|
75
69
|
connectionReferences,
|
|
70
|
+
hasDataverse,
|
|
76
71
|
schemaMap,
|
|
77
72
|
onDisambiguationNeeded,
|
|
78
73
|
onMissingConnection,
|
|
@@ -81,31 +76,37 @@ function useConnectionRefs({
|
|
|
81
76
|
const [connectionRefs, setConnectionRefs] = (0, _react.useState)({});
|
|
82
77
|
const [isReady, setIsReady] = (0, _react.useState)(false);
|
|
83
78
|
const [error, setError] = (0, _react.useState)(null);
|
|
79
|
+
const [errorKind, setErrorKind] = (0, _react.useState)(null);
|
|
84
80
|
const [missingConnectors, setMissingConnectors] = (0, _react.useState)([]);
|
|
81
|
+
const [missingConnectionReferences, setMissingConnectionReferences] = (0, _react.useState)([]);
|
|
82
|
+
const [connectionRequirements, setConnectionRequirements] = (0, _react.useState)([]);
|
|
83
|
+
const [resourceConsents, setResourceConsents] = (0, _react.useState)([]);
|
|
84
|
+
const [configurationErrors, setConfigurationErrors] = (0, _react.useState)([]);
|
|
85
|
+
const [requiresConnectionConsent, setRequiresConnectionConsent] = (0, _react.useState)(false);
|
|
86
|
+
const [resolvedConfigKey, setResolvedConfigKey] = (0, _react.useState)(null);
|
|
85
87
|
const [dataverseOrgUrl, setDataverseOrgUrl] = (0, _react.useState)('');
|
|
88
|
+
const [databaseReferences, setDatabaseReferences] = (0, _react.useState)({});
|
|
86
89
|
|
|
87
|
-
// Bounded re-resolution for
|
|
88
|
-
// cold boot is usually a silent-auth miss (the account exists, but MSAL hasn't
|
|
89
|
-
// produced a token yet); without a retry the effect — keyed on isSignedIn —
|
|
90
|
-
// would never re-resolve once a token becomes available, leaving the bridge on
|
|
91
|
-
// the static fallback refs (no runtimeUrl) for the whole session. retryTick
|
|
92
|
-
// re-runs the effect; tokenRetryCountRef caps the attempts so it can never loop.
|
|
90
|
+
// Bounded re-resolution for transient silent-token misses.
|
|
93
91
|
const [retryTick, setRetryTick] = (0, _react.useState)(0);
|
|
94
92
|
const tokenRetryCountRef = (0, _react.useRef)(0);
|
|
95
|
-
//
|
|
96
|
-
// retry below (not an initial resolution or a sign-in). Used to avoid
|
|
97
|
-
// clobbering an already-ready UI: a retry must re-resolve in the background
|
|
98
|
-
// without dropping isReady, which would otherwise unmount the whole signed-in
|
|
99
|
-
// subtree (spinner) on every tick.
|
|
93
|
+
// Dev Player retries in the background without dropping its locally ready UI.
|
|
100
94
|
const isBackgroundRetryRef = (0, _react.useRef)(false);
|
|
101
95
|
const MAX_TOKEN_RETRIES = 5;
|
|
102
96
|
const TOKEN_RETRY_DELAY_MS = 2000;
|
|
97
|
+
const currentConfigKey = (0, _types.buildConnectionResolutionKey)(appId, environmentId, _isDevPlayer.isDevPlayer ? connectionReferences : {});
|
|
103
98
|
(0, _react.useEffect)(() => {
|
|
104
99
|
if (!isSignedIn) {
|
|
105
100
|
tokenRetryCountRef.current = 0;
|
|
106
101
|
isBackgroundRetryRef.current = false;
|
|
107
102
|
return;
|
|
108
103
|
}
|
|
104
|
+
if (!_isDevPlayer.isDevPlayer && (!appId || !environmentId)) {
|
|
105
|
+
setErrorKind('generic');
|
|
106
|
+
setError('The production app requires both an app ID and an environment ID before it can load from Power Platform.');
|
|
107
|
+
setIsReady(true);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
109
110
|
|
|
110
111
|
// Consume the background-retry flag once per run so a later initial run or
|
|
111
112
|
// sign-in can never inherit a stale value.
|
|
@@ -123,6 +124,7 @@ function useConnectionRefs({
|
|
|
123
124
|
// an online (offline-disabled) played app never resolves its instanceUrl in
|
|
124
125
|
// the Dev Player and every Dataverse read fails with "No instanceUrl found".
|
|
125
126
|
if (_isDevPlayer.isDevPlayer && !hasConnectionRefs && !environmentId) {
|
|
127
|
+
setResolvedConfigKey(currentConfigKey);
|
|
126
128
|
setIsReady(true);
|
|
127
129
|
return;
|
|
128
130
|
}
|
|
@@ -131,50 +133,63 @@ function useConnectionRefs({
|
|
|
131
133
|
// (and no appId to fetch from the launch API).
|
|
132
134
|
// Mark ready immediately so the bridge can initialise without any network calls.
|
|
133
135
|
if (!environmentId && !appId) {
|
|
136
|
+
setResolvedConfigKey(currentConfigKey);
|
|
134
137
|
setIsReady(true);
|
|
135
138
|
return;
|
|
136
139
|
}
|
|
137
140
|
let cancelled = false;
|
|
138
141
|
let retryTimer;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
const resolutionScenario = (0, _index.getAppLogger)().trackScenario(_index.HostOperationNames.PlatformResolveConnectionRefs, {
|
|
143
|
+
mode: _isDevPlayer.isDevPlayer ? 'devPlayer' : 'publishedApp',
|
|
144
|
+
hasAppId: Boolean(appId),
|
|
145
|
+
connectionReferenceCount: Object.keys(connectionReferences).length
|
|
146
|
+
});
|
|
147
|
+
// Preserve the locally ready Dev Player UI during a background retry.
|
|
143
148
|
if (!isBackgroundRetry) {
|
|
144
149
|
setIsReady(false);
|
|
145
150
|
setError(null);
|
|
151
|
+
setErrorKind(null);
|
|
146
152
|
setMissingConnectors([]);
|
|
153
|
+
setMissingConnectionReferences([]);
|
|
154
|
+
setConnectionRequirements([]);
|
|
155
|
+
setResourceConsents([]);
|
|
156
|
+
setConfigurationErrors([]);
|
|
157
|
+
setRequiresConnectionConsent(false);
|
|
158
|
+
setResolvedConfigKey(null);
|
|
159
|
+
setDataverseOrgUrl('');
|
|
160
|
+
setDatabaseReferences({});
|
|
147
161
|
}
|
|
148
162
|
async function loadConnections() {
|
|
149
163
|
const token = await acquireToken([(0, _PowerPlatformEnvironmentApi.powerPlatformScope)(region)]);
|
|
150
|
-
if (cancelled)
|
|
164
|
+
if (cancelled) {
|
|
165
|
+
resolutionScenario.complete({
|
|
166
|
+
result: 'cancelled'
|
|
167
|
+
});
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
151
170
|
if (!token) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
// Still mark ready so the host mounts the UI (the offline SDK serves local
|
|
163
|
-
// SQLite without a token) instead of gating on !isReady forever.
|
|
164
|
-
setConnectionRefs((0, _NativePowerAppsBridge.buildConnectionReferences)(connectionReferences));
|
|
165
|
-
setIsReady(true);
|
|
166
|
-
// Schedule a bounded re-resolution so a transient silent-auth miss
|
|
167
|
-
// recovers once a token is available, instead of staying on the static
|
|
168
|
-
// fallback refs for the rest of the session. Capped by MAX_TOKEN_RETRIES
|
|
169
|
-
// so it can never spin.
|
|
171
|
+
resolutionScenario.completeWithError({
|
|
172
|
+
reason: 'tokenUnavailable'
|
|
173
|
+
});
|
|
174
|
+
// Dev Player can render local metadata while token recovery continues;
|
|
175
|
+
// standalone apps stay blocked because production has no static fallback.
|
|
176
|
+
if (_isDevPlayer.isDevPlayer) {
|
|
177
|
+
setConnectionRefs((0, _NativePowerAppsBridge.buildConnectionReferences)(connectionReferences));
|
|
178
|
+
setIsReady(true);
|
|
179
|
+
setResolvedConfigKey(currentConfigKey);
|
|
180
|
+
}
|
|
170
181
|
if (tokenRetryCountRef.current < MAX_TOKEN_RETRIES) {
|
|
171
182
|
tokenRetryCountRef.current += 1;
|
|
172
183
|
retryTimer = setTimeout(() => {
|
|
173
184
|
if (!cancelled) {
|
|
174
|
-
isBackgroundRetryRef.current =
|
|
185
|
+
isBackgroundRetryRef.current = _isDevPlayer.isDevPlayer;
|
|
175
186
|
setRetryTick(t => t + 1);
|
|
176
187
|
}
|
|
177
188
|
}, TOKEN_RETRY_DELAY_MS);
|
|
189
|
+
} else if (!_isDevPlayer.isDevPlayer) {
|
|
190
|
+
setErrorKind('generic');
|
|
191
|
+
setError('Unable to authenticate with Power Platform to load this app. Sign in again and retry.');
|
|
192
|
+
setIsReady(true);
|
|
178
193
|
}
|
|
179
194
|
return;
|
|
180
195
|
}
|
|
@@ -188,30 +203,50 @@ function useConnectionRefs({
|
|
|
188
203
|
let result = null;
|
|
189
204
|
if (appId && environmentId && !_isDevPlayer.isDevPlayer) {
|
|
190
205
|
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
|
+
if (result && onDisambiguationNeeded) {
|
|
210
|
+
for (const requirement of [...result.missingConnectionReferences]) {
|
|
211
|
+
const candidates = result.connectionCandidates[requirement.localRefId] ?? [];
|
|
212
|
+
if (candidates.length < 2) continue;
|
|
213
|
+
const selectedId = await onDisambiguationNeeded({
|
|
214
|
+
localRefId: requirement.localRefId,
|
|
215
|
+
apiId: requirement.apiId,
|
|
216
|
+
candidates
|
|
217
|
+
});
|
|
218
|
+
if (selectedId) {
|
|
219
|
+
(0, _connectionState.selectLaunchConnection)(result, requirement.localRefId, selectedId);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
191
223
|
if (result && isvClientId) {
|
|
192
|
-
await (0, _resolveConnections.applyAclGrants)(result.connectionRefs, environmentId,
|
|
193
|
-
|
|
194
|
-
|
|
224
|
+
const failedConnectionNames = await (0, _resolveConnections.applyAclGrants)(result.connectionRefs, result.connectionRequirements, environmentId, region, acquireToken);
|
|
225
|
+
(0, _connectionState.invalidateFailedAclGrants)(result, failedConnectionNames);
|
|
226
|
+
} else if (result) {
|
|
227
|
+
(0, _logger.debugWarn)('[useConnectionRefs] could not grant user-selected connections; treating them as setup-required');
|
|
195
228
|
(0, _index.getAppLogger)().trackErrorEvent(_index.HostOperationNames.PlatformConnectionAclGrant, {
|
|
196
229
|
phase: 'launchAclVerify',
|
|
197
|
-
reason:
|
|
198
|
-
connectionRefCount:
|
|
230
|
+
reason: 'missingIsvClientId',
|
|
231
|
+
connectionRefCount: Object.keys(result.connectionRefs).length
|
|
199
232
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
}
|
|
233
|
+
const unresolved = new Set((0, _connectionState.getConnectionNamesRequiringAclGrant)(result.connectionRefs, result.connectionRequirements));
|
|
234
|
+
(0, _connectionState.invalidateFailedAclGrants)(result, unresolved);
|
|
235
|
+
}
|
|
236
|
+
if (result) {
|
|
237
|
+
(0, _connectionState.applyRegisteredConnectionUsages)(result, result.registeredConnectionUsages);
|
|
207
238
|
}
|
|
208
239
|
}
|
|
209
240
|
|
|
210
241
|
// Slow path: per-connector resolution.
|
|
211
|
-
// Used
|
|
242
|
+
// Used only in Dev Player, where unpublished local app metadata is expected.
|
|
212
243
|
if (!result) {
|
|
244
|
+
if (!_isDevPlayer.isDevPlayer) {
|
|
245
|
+
throw new Error('Unable to load the production app from the Power Platform launch endpoint.');
|
|
246
|
+
}
|
|
213
247
|
result = await (0, _resolveConnections.resolveViaStaticRefs)({
|
|
214
248
|
connectionReferences,
|
|
249
|
+
hasDataverse,
|
|
215
250
|
schemaMap,
|
|
216
251
|
environmentId,
|
|
217
252
|
region,
|
|
@@ -222,7 +257,12 @@ function useConnectionRefs({
|
|
|
222
257
|
onMissingConnection
|
|
223
258
|
});
|
|
224
259
|
}
|
|
225
|
-
if (cancelled)
|
|
260
|
+
if (cancelled) {
|
|
261
|
+
resolutionScenario.complete({
|
|
262
|
+
result: 'cancelled'
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
226
266
|
|
|
227
267
|
// Pre-warm the Dataverse token while the user waits.
|
|
228
268
|
if (result.dataverseOrgUrl) {
|
|
@@ -231,8 +271,20 @@ function useConnectionRefs({
|
|
|
231
271
|
if (!cancelled) {
|
|
232
272
|
setConnectionRefs(result.connectionRefs);
|
|
233
273
|
setMissingConnectors(result.missingConnectors);
|
|
274
|
+
setMissingConnectionReferences(result.missingConnectionReferences);
|
|
275
|
+
setConnectionRequirements(result.connectionRequirements);
|
|
276
|
+
setResourceConsents(result.resourceConsents);
|
|
277
|
+
setConfigurationErrors(result.configurationErrors);
|
|
278
|
+
setRequiresConnectionConsent(result.requiresConnectionConsent);
|
|
234
279
|
setDataverseOrgUrl(result.dataverseOrgUrl);
|
|
280
|
+
setDatabaseReferences(result.databaseReferences);
|
|
281
|
+
setResolvedConfigKey(currentConfigKey);
|
|
235
282
|
setIsReady(true);
|
|
283
|
+
resolutionScenario.complete({
|
|
284
|
+
result: 'resolved',
|
|
285
|
+
missingConnectionReferenceCount: result.missingConnectionReferences.length,
|
|
286
|
+
configurationErrorCount: result.configurationErrors.length
|
|
287
|
+
});
|
|
236
288
|
}
|
|
237
289
|
}
|
|
238
290
|
loadConnections().catch(e => {
|
|
@@ -243,6 +295,9 @@ function useConnectionRefs({
|
|
|
243
295
|
// production without raising a __DEV__ LogBox redbox over the
|
|
244
296
|
// otherwise-working UI. We still recover via setIsReady below.
|
|
245
297
|
(0, _logger.debugLog)('[useConnectionRefs] Failed to load connections:', e);
|
|
298
|
+
resolutionScenario.fail(undefined, {
|
|
299
|
+
errorName: e instanceof Error ? e.name : 'UnknownError'
|
|
300
|
+
});
|
|
246
301
|
(0, _index.getAppLogger)().trackErrorEvent(_index.HostOperationNames.PlatformLoadConnectionsFailed, {
|
|
247
302
|
error: String(e),
|
|
248
303
|
hasAppId: Boolean(appId),
|
|
@@ -250,7 +305,9 @@ function useConnectionRefs({
|
|
|
250
305
|
connectionReferenceCount: Object.keys(connectionReferences).length,
|
|
251
306
|
runningInDevPlayer: _isDevPlayer.isDevPlayer
|
|
252
307
|
});
|
|
253
|
-
|
|
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.');
|
|
254
311
|
setIsReady(true);
|
|
255
312
|
}
|
|
256
313
|
});
|
|
@@ -259,12 +316,20 @@ function useConnectionRefs({
|
|
|
259
316
|
if (retryTimer) clearTimeout(retryTimer);
|
|
260
317
|
};
|
|
261
318
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
262
|
-
}, [isSignedIn, retryTick]);
|
|
319
|
+
}, [isSignedIn, retryTick, appId, environmentId, region, connectionReferences, hasDataverse, schemaMap, isvClientId]);
|
|
263
320
|
return {
|
|
264
321
|
connectionRefs,
|
|
265
322
|
isReady,
|
|
266
323
|
error,
|
|
324
|
+
errorKind,
|
|
267
325
|
missingConnectors,
|
|
268
|
-
|
|
326
|
+
missingConnectionReferences,
|
|
327
|
+
connectionRequirements,
|
|
328
|
+
resourceConsents,
|
|
329
|
+
configurationErrors,
|
|
330
|
+
requiresConnectionConsent,
|
|
331
|
+
resolvedConfigKey,
|
|
332
|
+
dataverseOrgUrl,
|
|
333
|
+
databaseReferences
|
|
269
334
|
};
|
|
270
335
|
}
|