@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.
- package/README.md +162 -26
- package/compatibility/current.json +87 -0
- package/lib/NOTICE.txt +140 -1226
- package/lib/commonjs/auth/AuthContext.js +74 -18
- package/lib/commonjs/auth/AuthContext.web.js +32 -0
- package/lib/commonjs/auth/completePowerAppsAuthSession.js +16 -0
- package/lib/commonjs/bridge/NativePowerAppsBridge.js +20 -17
- package/lib/commonjs/bridge/PowerPagesBridge.js +157 -0
- package/lib/commonjs/bridge/bridgeState.js +40 -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 +347 -0
- package/lib/commonjs/connections/types.js +106 -0
- package/lib/commonjs/{platform → connections}/useConnectionRefs.js +128 -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 +188 -6
- package/lib/commonjs/logger.js +9 -6
- package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
- package/lib/commonjs/offline/useOfflineIntegration.js +12 -0
- package/lib/commonjs/offline/useOfflineIntegration.web.js +11 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +46 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
- package/lib/commonjs/platform/DataverseDataSources.js +14 -0
- package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +49 -0
- package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
- package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
- package/lib/commonjs/provider/PowerAppsHostProvider.js +156 -25
- package/lib/commonjs/provider/PowerAppsHostProvider.web.js +41 -0
- package/lib/commonjs/provider/PowerAppsProvider.js +229 -133
- package/lib/commonjs/provider/SessionDetailsGesture.js +216 -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 +74 -18
- package/lib/module/auth/AuthContext.web.js +26 -0
- package/lib/module/auth/completePowerAppsAuthSession.js +11 -0
- package/lib/module/bridge/NativePowerAppsBridge.js +21 -18
- package/lib/module/bridge/PowerPagesBridge.js +151 -0
- package/lib/module/bridge/bridgeState.js +34 -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 +342 -0
- package/lib/module/connections/types.js +91 -0
- package/lib/module/{platform → connections}/useConnectionRefs.js +129 -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 -6
- package/lib/module/logger.js +8 -6
- package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
- package/lib/module/offline/useOfflineIntegration.js +3 -0
- package/lib/module/offline/useOfflineIntegration.web.js +7 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +42 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
- package/lib/module/platform/DataverseDataSources.js +10 -0
- package/lib/module/platform/DataverseGlobalDiscoveryApi.js +45 -0
- package/lib/module/platform/GlobalDiscovery.js +45 -0
- package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
- package/lib/module/provider/PowerAppsHostProvider.js +159 -28
- package/lib/module/provider/PowerAppsHostProvider.web.js +36 -0
- package/lib/module/provider/PowerAppsProvider.js +233 -137
- package/lib/module/provider/SessionDetailsGesture.js +211 -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 +21 -0
- package/lib/typescript/commonjs/auth/completePowerAppsAuthSession.d.ts +8 -0
- package/lib/typescript/commonjs/bridge/PowerPagesBridge.d.ts +18 -0
- package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -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 +19 -19
- package/lib/typescript/commonjs/connections/types.d.ts +129 -1
- package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +33 -24
- 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 +20 -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/useOfflineIntegration.d.ts +2 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegration.web.d.ts +4 -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 +27 -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/PowerAppsHostProvider.web.d.ts +5 -0
- package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +32 -10
- 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 +21 -0
- package/lib/typescript/module/auth/completePowerAppsAuthSession.d.ts +8 -0
- package/lib/typescript/module/bridge/PowerPagesBridge.d.ts +18 -0
- package/lib/typescript/module/bridge/bridgeState.d.ts +5 -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 +19 -19
- package/lib/typescript/module/connections/types.d.ts +129 -1
- package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +33 -24
- 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 +24 -14
- package/lib/typescript/module/logger.d.ts +4 -4
- package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
- package/lib/typescript/module/offline/useOfflineIntegration.d.ts +2 -0
- package/lib/typescript/module/offline/useOfflineIntegration.web.d.ts +4 -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 +27 -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/PowerAppsHostProvider.web.d.ts +5 -0
- package/lib/typescript/module/provider/PowerAppsProvider.d.ts +34 -12
- 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 +43 -18
- package/scripts/build-ios-base.js +66 -27
- package/scripts/bundle.js +212 -5
- package/scripts/generate-connector-schemas.js +8 -6
- package/scripts/metro-logger.js +213 -0
- package/scripts/start-web.mjs +137 -0
- package/scripts/upgrade/runtime.js +463 -0
- package/scripts/upgrade/system.js +244 -0
- package/scripts/upgrade-authoring.js +534 -0
- package/scripts/upgrade.js +188 -0
- package/scripts/wrap.js +536 -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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SessionDetailsGesture = SessionDetailsGesture;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var Clipboard = _interopRequireWildcard(require("expo-clipboard"));
|
|
10
|
+
var _reactNativeGestureHandler = require("react-native-gesture-handler");
|
|
11
|
+
var _index = require("../telemetry/index.js");
|
|
12
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
14
|
+
const SWIPE_DISTANCE = 80;
|
|
15
|
+
function SessionDetailsGesture({
|
|
16
|
+
enabled,
|
|
17
|
+
appName,
|
|
18
|
+
appId,
|
|
19
|
+
environmentId,
|
|
20
|
+
region,
|
|
21
|
+
appVersion,
|
|
22
|
+
children
|
|
23
|
+
}) {
|
|
24
|
+
const [visible, setVisible] = (0, _react.useState)(false);
|
|
25
|
+
const [sessionId, setSessionId] = (0, _react.useState)();
|
|
26
|
+
const [copied, setCopied] = (0, _react.useState)(false);
|
|
27
|
+
const showSessionDetails = (0, _react.useCallback)(() => {
|
|
28
|
+
setSessionId((0, _index.getAppLogger)().sessionId);
|
|
29
|
+
setCopied(false);
|
|
30
|
+
setVisible(true);
|
|
31
|
+
}, []);
|
|
32
|
+
const gesture = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().enabled(enabled && _reactNative.Platform.OS !== 'web').minPointers(3).maxPointers(3).runOnJS(true).onEnd(({
|
|
33
|
+
translationX,
|
|
34
|
+
translationY
|
|
35
|
+
}) => {
|
|
36
|
+
if (translationY >= SWIPE_DISTANCE && translationY > Math.abs(translationX)) {
|
|
37
|
+
showSessionDetails();
|
|
38
|
+
}
|
|
39
|
+
}), [enabled, showSessionDetails]);
|
|
40
|
+
const close = (0, _react.useCallback)(() => setVisible(false), []);
|
|
41
|
+
const copySessionId = (0, _react.useCallback)(async () => {
|
|
42
|
+
if (!sessionId) return;
|
|
43
|
+
await Clipboard.setStringAsync(sessionId);
|
|
44
|
+
setCopied(true);
|
|
45
|
+
}, [sessionId]);
|
|
46
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
47
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
|
|
48
|
+
gesture: gesture,
|
|
49
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
50
|
+
style: styles.content,
|
|
51
|
+
children: children
|
|
52
|
+
})
|
|
53
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
|
|
54
|
+
animationType: "fade",
|
|
55
|
+
onRequestClose: close,
|
|
56
|
+
transparent: true,
|
|
57
|
+
visible: visible,
|
|
58
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
59
|
+
accessibilityRole: "button",
|
|
60
|
+
accessibilityLabel: "Close session details",
|
|
61
|
+
onPress: close,
|
|
62
|
+
style: styles.backdrop,
|
|
63
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
64
|
+
accessible: false,
|
|
65
|
+
onPress: event => event.stopPropagation(),
|
|
66
|
+
style: styles.panel,
|
|
67
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
68
|
+
style: styles.title,
|
|
69
|
+
children: "Session details"
|
|
70
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
71
|
+
label: "Telemetry session ID",
|
|
72
|
+
value: sessionId ?? 'Not available',
|
|
73
|
+
selectable: true,
|
|
74
|
+
singleLine: true
|
|
75
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
76
|
+
accessibilityRole: "button",
|
|
77
|
+
disabled: !sessionId,
|
|
78
|
+
onPress: () => {
|
|
79
|
+
void copySessionId();
|
|
80
|
+
},
|
|
81
|
+
style: ({
|
|
82
|
+
pressed
|
|
83
|
+
}) => [styles.copyButton, !sessionId && styles.disabledButton, pressed && styles.pressedButton],
|
|
84
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
85
|
+
style: styles.copyButtonText,
|
|
86
|
+
children: copied ? 'Copied' : 'Copy session ID'
|
|
87
|
+
})
|
|
88
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
89
|
+
label: "App",
|
|
90
|
+
value: appName
|
|
91
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
92
|
+
label: "App ID",
|
|
93
|
+
value: appId ?? 'Not available',
|
|
94
|
+
selectable: true
|
|
95
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
96
|
+
label: "Environment ID",
|
|
97
|
+
value: environmentId ?? 'Not available',
|
|
98
|
+
selectable: true
|
|
99
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
100
|
+
label: "Region",
|
|
101
|
+
value: region
|
|
102
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(SessionDetail, {
|
|
103
|
+
label: "App version",
|
|
104
|
+
value: appVersion ?? 'Not available'
|
|
105
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
106
|
+
accessibilityRole: "button",
|
|
107
|
+
onPress: close,
|
|
108
|
+
style: styles.closeButton,
|
|
109
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
110
|
+
style: styles.closeButtonText,
|
|
111
|
+
children: "Close"
|
|
112
|
+
})
|
|
113
|
+
})]
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function SessionDetail({
|
|
120
|
+
label,
|
|
121
|
+
value,
|
|
122
|
+
selectable = false,
|
|
123
|
+
singleLine = false
|
|
124
|
+
}) {
|
|
125
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
126
|
+
style: styles.row,
|
|
127
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
128
|
+
style: styles.label,
|
|
129
|
+
children: label
|
|
130
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
131
|
+
adjustsFontSizeToFit: singleLine,
|
|
132
|
+
minimumFontScale: 0.85,
|
|
133
|
+
numberOfLines: singleLine ? 1 : undefined,
|
|
134
|
+
selectable: selectable,
|
|
135
|
+
style: styles.value,
|
|
136
|
+
children: value
|
|
137
|
+
})]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const styles = _reactNative.StyleSheet.create({
|
|
141
|
+
content: {
|
|
142
|
+
flex: 1
|
|
143
|
+
},
|
|
144
|
+
backdrop: {
|
|
145
|
+
alignItems: 'center',
|
|
146
|
+
backgroundColor: 'rgba(0, 0, 0, 0.48)',
|
|
147
|
+
flex: 1,
|
|
148
|
+
justifyContent: 'center',
|
|
149
|
+
paddingHorizontal: 12,
|
|
150
|
+
paddingVertical: 24
|
|
151
|
+
},
|
|
152
|
+
panel: {
|
|
153
|
+
backgroundColor: '#FFFFFF',
|
|
154
|
+
borderRadius: 8,
|
|
155
|
+
maxWidth: 520,
|
|
156
|
+
paddingHorizontal: 16,
|
|
157
|
+
paddingVertical: 24,
|
|
158
|
+
width: '100%'
|
|
159
|
+
},
|
|
160
|
+
title: {
|
|
161
|
+
color: '#242424',
|
|
162
|
+
fontSize: 20,
|
|
163
|
+
fontWeight: '700',
|
|
164
|
+
marginBottom: 20
|
|
165
|
+
},
|
|
166
|
+
row: {
|
|
167
|
+
marginBottom: 14
|
|
168
|
+
},
|
|
169
|
+
label: {
|
|
170
|
+
color: '#616161',
|
|
171
|
+
fontSize: 12,
|
|
172
|
+
fontWeight: '600',
|
|
173
|
+
marginBottom: 3
|
|
174
|
+
},
|
|
175
|
+
value: {
|
|
176
|
+
color: '#242424',
|
|
177
|
+
fontSize: 15,
|
|
178
|
+
lineHeight: 21
|
|
179
|
+
},
|
|
180
|
+
copyButton: {
|
|
181
|
+
alignSelf: 'flex-start',
|
|
182
|
+
borderColor: '#0F6CBD',
|
|
183
|
+
borderRadius: 4,
|
|
184
|
+
borderWidth: 1,
|
|
185
|
+
marginBottom: 14,
|
|
186
|
+
marginTop: -4,
|
|
187
|
+
paddingHorizontal: 12,
|
|
188
|
+
paddingVertical: 7
|
|
189
|
+
},
|
|
190
|
+
copyButtonText: {
|
|
191
|
+
color: '#0F6CBD',
|
|
192
|
+
fontSize: 13,
|
|
193
|
+
fontWeight: '600'
|
|
194
|
+
},
|
|
195
|
+
disabledButton: {
|
|
196
|
+
opacity: 0.45
|
|
197
|
+
},
|
|
198
|
+
pressedButton: {
|
|
199
|
+
opacity: 0.7
|
|
200
|
+
},
|
|
201
|
+
closeButton: {
|
|
202
|
+
alignItems: 'center',
|
|
203
|
+
alignSelf: 'flex-end',
|
|
204
|
+
backgroundColor: '#0F6CBD',
|
|
205
|
+
borderRadius: 4,
|
|
206
|
+
marginTop: 8,
|
|
207
|
+
minWidth: 88,
|
|
208
|
+
paddingHorizontal: 18,
|
|
209
|
+
paddingVertical: 10
|
|
210
|
+
},
|
|
211
|
+
closeButtonText: {
|
|
212
|
+
color: '#FFFFFF',
|
|
213
|
+
fontSize: 14,
|
|
214
|
+
fontWeight: '600'
|
|
215
|
+
}
|
|
216
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.configureOfflineSdkTelemetry = configureOfflineSdkTelemetry;
|
|
7
|
+
var _powerAppsNativeCommon = require("@microsoft/power-apps-native-common");
|
|
8
|
+
var OfflineSdk = _interopRequireWildcard(require("@microsoft/power-apps-native-offline"));
|
|
9
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
|
+
/**
|
|
11
|
+
* Operation names for this adapter's own diagnostics, following the
|
|
12
|
+
* `PowerAppsHost.<Subsystem>.<Action>` convention used by `HostOperationNames`.
|
|
13
|
+
*
|
|
14
|
+
* Declared locally rather than imported from `./index`: this module must stay
|
|
15
|
+
* fail-open and side-effect free, and the barrel constructs HTTP clients at
|
|
16
|
+
* import time. Two string constants are not worth that dependency.
|
|
17
|
+
*/
|
|
18
|
+
const OfflineTelemetryBindFailed = 'PowerAppsHost.Offline.TelemetryBind.Failed';
|
|
19
|
+
const OfflineTelemetryUnbindFailed = 'PowerAppsHost.Offline.TelemetryUnbind.Failed';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Non-sensitive error discriminator. Records the error's constructor name only,
|
|
23
|
+
* never its message, so diagnostics cannot leak user or tenant data.
|
|
24
|
+
*/
|
|
25
|
+
function getSafeErrorName(error) {
|
|
26
|
+
return error instanceof Error ? error.constructor.name : typeof error;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* True when the resolved SDK exposes the v1 host-telemetry transport.
|
|
31
|
+
*
|
|
32
|
+
* Reading a missing export yields `undefined` rather than throwing, so this
|
|
33
|
+
* probe is safe on SDK builds that predate the transport. Keeping it separate
|
|
34
|
+
* from the `try`/`catch` below is what lets an out-of-range SDK stay a silent,
|
|
35
|
+
* expected no-op while genuine wiring failures still get reported.
|
|
36
|
+
*
|
|
37
|
+
* The version equality matters as much as the `typeof`: a future transport
|
|
38
|
+
* revision with a different sink shape would accept a v1 sink and silently
|
|
39
|
+
* malform every event rather than throw.
|
|
40
|
+
*/
|
|
41
|
+
function isTransportSupported() {
|
|
42
|
+
return typeof OfflineSdk.configureOfflineHostTelemetry === 'function' && OfflineSdk.OFFLINE_HOST_TELEMETRY_TRANSPORT_VERSION === 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Forwards the privacy-safe Offline SDK transport through the host's existing
|
|
47
|
+
* app logger so offline events carry the same session, device, and user data.
|
|
48
|
+
*
|
|
49
|
+
* The host owns exactly one thing here: binding the SDK transport to this
|
|
50
|
+
* host's logger. Buffering and teardown semantics live in the SDK.
|
|
51
|
+
*
|
|
52
|
+
* Setup and teardown are fail-open but not silent. This runs from an effect in
|
|
53
|
+
* the provider that roots the app, so an unguarded throw would take down the
|
|
54
|
+
* whole tree — telemetry is never worth an app that will not start. An
|
|
55
|
+
* unexpected failure is therefore downgraded to a logged diagnostic rather than
|
|
56
|
+
* swallowed, so broken wiring stays observable.
|
|
57
|
+
*/
|
|
58
|
+
function configureOfflineSdkTelemetry(forwardEvents) {
|
|
59
|
+
if (!isTransportSupported()) {
|
|
60
|
+
return () => undefined;
|
|
61
|
+
}
|
|
62
|
+
const stopForwarding = () => {
|
|
63
|
+
try {
|
|
64
|
+
OfflineSdk.configureOfflineHostTelemetry(undefined);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
(0, _powerAppsNativeCommon.getAppLogger)().trackErrorEvent(OfflineTelemetryUnbindFailed, {
|
|
67
|
+
errorName: getSafeErrorName(e)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
if (!forwardEvents) {
|
|
72
|
+
stopForwarding();
|
|
73
|
+
return stopForwarding;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
OfflineSdk.configureOfflineHostTelemetry({
|
|
77
|
+
// Resolved per event, not captured: the Dev Player swaps the logger when
|
|
78
|
+
// it switches apps, and a captured instance would strand events.
|
|
79
|
+
//
|
|
80
|
+
// `name` is the operation name only. Deliberately not passed as the
|
|
81
|
+
// optional third `eventName` argument: that overrides the canonical
|
|
82
|
+
// `PowerAppsClient.Activity`/`.Error` 1DS event names, which would hide
|
|
83
|
+
// every offline event from the queries and dashboards that filter on
|
|
84
|
+
// them. The name already reaches 1DS as `operation_Name`.
|
|
85
|
+
trackActivityEvent: (name, properties) => (0, _powerAppsNativeCommon.getAppLogger)().trackActivityEvent(name, properties),
|
|
86
|
+
trackErrorEvent: (name, properties) => (0, _powerAppsNativeCommon.getAppLogger)().trackErrorEvent(name, properties)
|
|
87
|
+
});
|
|
88
|
+
} catch (e) {
|
|
89
|
+
(0, _powerAppsNativeCommon.getAppLogger)().trackErrorEvent(OfflineTelemetryBindFailed, {
|
|
90
|
+
errorName: getSafeErrorName(e)
|
|
91
|
+
});
|
|
92
|
+
return () => undefined;
|
|
93
|
+
}
|
|
94
|
+
return stopForwarding;
|
|
95
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.HostOperationNames = void 0;
|
|
6
|
+
exports.bridgeHttpClient = exports.HostOperationNames = void 0;
|
|
7
7
|
Object.defineProperty(exports, "configureAppLogger", {
|
|
8
8
|
enumerable: true,
|
|
9
9
|
get: function () {
|
|
@@ -16,6 +16,15 @@ Object.defineProperty(exports, "getAppLogger", {
|
|
|
16
16
|
return _powerAppsNativeCommon.getAppLogger;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
+
Object.defineProperty(exports, "getCustomerTelemetryLogger", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () {
|
|
22
|
+
return _powerAppsNativeCommon.getCustomerTelemetryLogger;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
exports.platformHttpClient = void 0;
|
|
26
|
+
var _http = require("@microsoft/power-apps-native-common/http");
|
|
27
|
+
var _logger = require("../logger.js");
|
|
19
28
|
var _powerAppsNativeCommon = require("@microsoft/power-apps-native-common");
|
|
20
29
|
/*!
|
|
21
30
|
* Copyright (C) Microsoft Corporation. All rights reserved.
|
|
@@ -57,14 +66,24 @@ const HostOperationNames = exports.HostOperationNames = {
|
|
|
57
66
|
/** Top-level React error boundary caught an unhandled JS error. */
|
|
58
67
|
RuntimeUnhandledJsError: 'PowerAppsHost.Runtime.UnhandledJsError',
|
|
59
68
|
// ── Platform APIs ─────────────────────────────────────────────────────────
|
|
69
|
+
/** Power Platform RP HTTP request, including backend correlation IDs. */
|
|
70
|
+
PlatformHttpRequest: 'PowerAppsHost.Platform.HttpRequest',
|
|
60
71
|
/** Resolve Dataverse instanceUrl from Power Platform environment API. */
|
|
61
72
|
PlatformFetchInstanceUrl: 'PowerAppsHost.Platform.FetchInstanceUrl',
|
|
62
73
|
/** useConnectionRefs failed to resolve connections (recoverable). Recorded only on failure. */
|
|
63
74
|
PlatformLoadConnectionsFailed: 'PowerAppsHost.Platform.LoadConnections.Failed',
|
|
64
75
|
/** Create a new Power Platform connection. */
|
|
65
76
|
PlatformCreateConnection: 'PowerAppsHost.Platform.CreateConnection',
|
|
77
|
+
/** Repair an existing Power Platform connection. */
|
|
78
|
+
PlatformRepairConnection: 'PowerAppsHost.Platform.RepairConnection',
|
|
79
|
+
/** Poll a connection until it becomes active. */
|
|
80
|
+
PlatformPollConnectionStatus: 'PowerAppsHost.Platform.PollConnectionStatus',
|
|
66
81
|
/** Resolve app connection references for the current launch. */
|
|
67
82
|
PlatformResolveConnectionRefs: 'PowerAppsHost.Platform.ResolveConnectionRefs',
|
|
68
83
|
/** Grant this app access to a Power Platform connection ACL. */
|
|
69
|
-
PlatformConnectionAclGrant: 'PowerAppsHost.Platform.ConnectionAclGrant'
|
|
70
|
-
|
|
84
|
+
PlatformConnectionAclGrant: 'PowerAppsHost.Platform.ConnectionAclGrant',
|
|
85
|
+
/** Installed Offline SDK predates the SDK-owned routing contract. */
|
|
86
|
+
OfflineRoutingContractUnsupported: 'PowerAppsHost.Offline.RoutingContract.Unsupported'
|
|
87
|
+
};
|
|
88
|
+
const bridgeHttpClient = exports.bridgeHttpClient = new _http.HttpClient(HostOperationNames.BridgeHttpRequest, _logger.isDebugLoggingEnabled);
|
|
89
|
+
const platformHttpClient = exports.platformHttpClient = new _http.HttpClient(HostOperationNames.PlatformHttpRequest, _logger.isDebugLoggingEnabled);
|
|
@@ -31,10 +31,49 @@ const SIGN_IN_SCOPES = ['https://api.powerplatform.com/.default'];
|
|
|
31
31
|
function getSafeErrorName(error) {
|
|
32
32
|
return error instanceof Error ? error.constructor.name : typeof error;
|
|
33
33
|
}
|
|
34
|
+
function accountsMatch(left, right) {
|
|
35
|
+
return left.identifier === right.identifier && left.tenantId === right.tenantId;
|
|
36
|
+
}
|
|
37
|
+
async function validateRequiredScopes(pca, account, scopes) {
|
|
38
|
+
for (const scope of scopes) {
|
|
39
|
+
await pca.acquireTokenSilent({
|
|
40
|
+
scopes: [scope],
|
|
41
|
+
account
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function acquireRequiredScopesInteractively(pca, scopes) {
|
|
46
|
+
const [primaryScope, ...additionalScopes] = scopes;
|
|
47
|
+
const primaryResult = await pca.acquireToken({
|
|
48
|
+
scopes: [primaryScope],
|
|
49
|
+
prompt: 'select_account'
|
|
50
|
+
});
|
|
51
|
+
const signedInAccount = primaryResult.account;
|
|
52
|
+
for (const scope of additionalScopes) {
|
|
53
|
+
try {
|
|
54
|
+
await pca.acquireTokenSilent({
|
|
55
|
+
scopes: [scope],
|
|
56
|
+
account: signedInAccount
|
|
57
|
+
});
|
|
58
|
+
} catch {
|
|
59
|
+
const result = await pca.acquireToken({
|
|
60
|
+
scopes: [scope],
|
|
61
|
+
loginHint: signedInAccount.username,
|
|
62
|
+
prompt: 'login'
|
|
63
|
+
});
|
|
64
|
+
if (!accountsMatch(signedInAccount, result.account)) {
|
|
65
|
+
throw new Error('Sign in with the same account for all required Power Platform permissions.');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await validateRequiredScopes(pca, signedInAccount, scopes);
|
|
70
|
+
return signedInAccount;
|
|
71
|
+
}
|
|
34
72
|
const AuthContext = /*#__PURE__*/createContext(null);
|
|
35
73
|
export function AuthProvider({
|
|
36
74
|
msalConfig,
|
|
37
75
|
intuneConfig,
|
|
76
|
+
requiredScopes = [],
|
|
38
77
|
children
|
|
39
78
|
}) {
|
|
40
79
|
const [isAuthReady, setIsAuthReady] = useState(false);
|
|
@@ -99,6 +138,8 @@ export function AuthProvider({
|
|
|
99
138
|
// Skip MSAL entirely; treat the session as already signed in so the app
|
|
100
139
|
// renders without requiring credentials.
|
|
101
140
|
const noAuthMode = !effectiveClientId;
|
|
141
|
+
const requiredScopeKey = [...new Set(requiredScopes)].join('|');
|
|
142
|
+
const effectiveRequiredScopes = requiredScopeKey ? requiredScopeKey.split('|') : SIGN_IN_SCOPES;
|
|
102
143
|
const pcaRef = useRef(null);
|
|
103
144
|
useEffect(() => {
|
|
104
145
|
if (noAuthMode) {
|
|
@@ -124,8 +165,20 @@ export function AuthProvider({
|
|
|
124
165
|
useBroker,
|
|
125
166
|
platform: Platform.OS
|
|
126
167
|
});
|
|
127
|
-
pca.init().then(() => pca.getAccounts()).then(accounts => {
|
|
128
|
-
|
|
168
|
+
pca.init().then(() => pca.getAccounts()).then(async accounts => {
|
|
169
|
+
let restoredAccount = accounts[0] ?? null;
|
|
170
|
+
if (restoredAccount) {
|
|
171
|
+
try {
|
|
172
|
+
await validateRequiredScopes(pca, restoredAccount, effectiveRequiredScopes);
|
|
173
|
+
} catch (tokenError) {
|
|
174
|
+
await pca.signOut({
|
|
175
|
+
account: restoredAccount
|
|
176
|
+
}).catch(() => undefined);
|
|
177
|
+
restoredAccount = null;
|
|
178
|
+
setError(new Error('Your session has expired. Sign in again to continue.'));
|
|
179
|
+
debugWarn('[AuthProvider] restored account is missing a required token:', tokenError);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
129
182
|
setAccount(restoredAccount);
|
|
130
183
|
if (restoredAccount) {
|
|
131
184
|
getAppLogger().identifyUser({
|
|
@@ -149,7 +202,7 @@ export function AuthProvider({
|
|
|
149
202
|
});
|
|
150
203
|
// Re-initialize only when the effective broker/identity settings change.
|
|
151
204
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
152
|
-
}, [effectiveClientId, effectiveTenantId, effectiveRedirectUri, useBroker]);
|
|
205
|
+
}, [effectiveClientId, effectiveTenantId, effectiveRedirectUri, requiredScopeKey, useBroker]);
|
|
153
206
|
const signIn = useCallback(async () => {
|
|
154
207
|
const pca = pcaRef.current;
|
|
155
208
|
if (!pca) return;
|
|
@@ -163,13 +216,11 @@ export function AuthProvider({
|
|
|
163
216
|
if (!pca.isInitialized) {
|
|
164
217
|
await pca.init();
|
|
165
218
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
});
|
|
169
|
-
setAccount(result.account);
|
|
219
|
+
const signedInAccount = await acquireRequiredScopesInteractively(pca, effectiveRequiredScopes);
|
|
220
|
+
setAccount(signedInAccount);
|
|
170
221
|
getAppLogger().identifyUser({
|
|
171
|
-
objectId:
|
|
172
|
-
tenantId:
|
|
222
|
+
objectId: signedInAccount.identifier,
|
|
223
|
+
tenantId: signedInAccount.tenantId
|
|
173
224
|
});
|
|
174
225
|
// Register the signed-in account with Intune MAM so the SDK can apply
|
|
175
226
|
// app protection policies (PIN, wipe, copy-paste restriction, etc.).
|
|
@@ -178,9 +229,9 @@ export function AuthProvider({
|
|
|
178
229
|
if (intuneEnabled) {
|
|
179
230
|
try {
|
|
180
231
|
await registerAndEnrollAccount({
|
|
181
|
-
upn:
|
|
182
|
-
aadId:
|
|
183
|
-
tenantId:
|
|
232
|
+
upn: signedInAccount.username,
|
|
233
|
+
aadId: signedInAccount.identifier,
|
|
234
|
+
tenantId: signedInAccount.tenantId
|
|
184
235
|
});
|
|
185
236
|
getAppLogger().trackActivityEvent(HostOperationNames.AuthIntuneEnroll);
|
|
186
237
|
} catch (intuneErr) {
|
|
@@ -201,7 +252,7 @@ export function AuthProvider({
|
|
|
201
252
|
} finally {
|
|
202
253
|
setIsLoading(false);
|
|
203
254
|
}
|
|
204
|
-
}, [intuneEnabled, useBroker]);
|
|
255
|
+
}, [intuneEnabled, requiredScopeKey, useBroker]);
|
|
205
256
|
const acquireToken = useCallback(async scopes => {
|
|
206
257
|
const pca = pcaRef.current;
|
|
207
258
|
if (!pca || !account) return null;
|
|
@@ -212,18 +263,23 @@ export function AuthProvider({
|
|
|
212
263
|
});
|
|
213
264
|
return result.accessToken;
|
|
214
265
|
} catch (e) {
|
|
215
|
-
// Silent acquisition failed — do NOT fall back to interactive here.
|
|
216
|
-
// Interactive sign-in is handled exclusively by signIn(). Falling back
|
|
217
|
-
// to interactive from acquireToken triggers an unexpected login webview
|
|
218
|
-
// whenever a connector needs a token the cache doesn't hold yet.
|
|
219
266
|
debugWarn('[AuthContext] acquireTokenSilent failed for scopes:', scopes, e);
|
|
220
267
|
getAppLogger().trackErrorEvent(HostOperationNames.AuthAcquireTokenSilentFailed, {
|
|
221
268
|
scopeCount: scopes.length,
|
|
222
269
|
errorName: getSafeErrorName(e)
|
|
223
270
|
});
|
|
271
|
+
if (scopes.some(scope => effectiveRequiredScopes.includes(scope))) {
|
|
272
|
+
await pca.signOut({
|
|
273
|
+
account
|
|
274
|
+
}).catch(signOutError => {
|
|
275
|
+
debugWarn('[AuthContext] failed to clear an invalid session:', signOutError);
|
|
276
|
+
});
|
|
277
|
+
setError(new Error('Your session has expired. Sign in again to continue.'));
|
|
278
|
+
setAccount(null);
|
|
279
|
+
}
|
|
224
280
|
return null;
|
|
225
281
|
}
|
|
226
|
-
}, [account]);
|
|
282
|
+
}, [account, requiredScopeKey]);
|
|
227
283
|
const signOut = useCallback(async () => {
|
|
228
284
|
const pca = pcaRef.current;
|
|
229
285
|
if (!pca || !account) return;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext } from 'react';
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
const hostedWebAuthState = {
|
|
6
|
+
isLoading: false,
|
|
7
|
+
isAuthReady: true,
|
|
8
|
+
isSignedIn: true,
|
|
9
|
+
hasRealAccount: false,
|
|
10
|
+
error: null,
|
|
11
|
+
acquireToken: async () => null,
|
|
12
|
+
signIn: async () => undefined,
|
|
13
|
+
signOut: async () => undefined
|
|
14
|
+
};
|
|
15
|
+
const AuthContext = /*#__PURE__*/createContext(hostedWebAuthState);
|
|
16
|
+
export function AuthProvider({
|
|
17
|
+
children
|
|
18
|
+
}) {
|
|
19
|
+
return /*#__PURE__*/_jsx(AuthContext.Provider, {
|
|
20
|
+
value: hostedWebAuthState,
|
|
21
|
+
children: children
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function useAuth() {
|
|
25
|
+
return useContext(AuthContext);
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as WebBrowser from 'expo-web-browser';
|
|
4
|
+
/**
|
|
5
|
+
* Completes an Expo web authentication popup when the current route is its
|
|
6
|
+
* redirect target. Call this at module initialization in the OAuth callback
|
|
7
|
+
* route; navigation after completion remains application-owned.
|
|
8
|
+
*/
|
|
9
|
+
export function completePowerAppsAuthSession(options) {
|
|
10
|
+
return WebBrowser.maybeCompleteAuthSession(options);
|
|
11
|
+
}
|
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { debugLog, debugWarn } from "../logger.js";
|
|
15
|
-
import { getAppLogger, HostOperationNames } from "../telemetry/index.js";
|
|
15
|
+
import { bridgeHttpClient, getAppLogger, HostOperationNames } from "../telemetry/index.js";
|
|
16
|
+
import { getHttpCorrelationProperties } from '@microsoft/power-apps-native-common/http';
|
|
16
17
|
import { sanitizeUrl } from '@microsoft/power-apps-native-common';
|
|
18
|
+
import { assertSuccessfulHttpStatus, getRequestBodyForMethod, updateBridgeOptionsInPlace } from "./bridgeState.js";
|
|
17
19
|
function getSafeErrorName(error) {
|
|
18
20
|
return error instanceof Error ? error.constructor.name : typeof error;
|
|
19
21
|
}
|
|
@@ -115,7 +117,7 @@ export class NativePowerAppsBridge {
|
|
|
115
117
|
* via globalThis would have no effect — mutating options is the correct path.
|
|
116
118
|
*/
|
|
117
119
|
updateOptions(options) {
|
|
118
|
-
this._options = options;
|
|
120
|
+
this._options = updateBridgeOptionsInPlace(this._options, options);
|
|
119
121
|
}
|
|
120
122
|
async initialize() {
|
|
121
123
|
// No handshake required for the native path.
|
|
@@ -198,10 +200,6 @@ export class NativePowerAppsBridge {
|
|
|
198
200
|
method
|
|
199
201
|
} = requestConfig;
|
|
200
202
|
const urlLabel = sanitizeUrl(url.replace(/^https?:\/\/[^/]+/, '').slice(0, 100));
|
|
201
|
-
const scenario = getAppLogger().trackScenario(HostOperationNames.BridgeHttpRequest, {
|
|
202
|
-
httpMethod: method,
|
|
203
|
-
url: urlLabel
|
|
204
|
-
});
|
|
205
203
|
const isBlob = bodyParam instanceof Blob;
|
|
206
204
|
|
|
207
205
|
// The SDK builds Authorization headers with the "paauth" scheme (its web-player
|
|
@@ -226,11 +224,12 @@ export class NativePowerAppsBridge {
|
|
|
226
224
|
// SDK passed a plain object — JSON-stringify it as a fallback
|
|
227
225
|
bodyInit = JSON.stringify(bodyParam);
|
|
228
226
|
}
|
|
227
|
+
bodyInit = getRequestBodyForMethod(method, bodyInit);
|
|
229
228
|
headers = normalizeJsonBodyHeaders(headers, bodyInit);
|
|
230
229
|
debugLog(`[bridge] → ${method} ${urlLabel}`);
|
|
231
230
|
let response;
|
|
232
231
|
try {
|
|
233
|
-
response = await
|
|
232
|
+
response = await bridgeHttpClient.request(url, {
|
|
234
233
|
method,
|
|
235
234
|
headers: headers,
|
|
236
235
|
body: bodyInit
|
|
@@ -238,9 +237,6 @@ export class NativePowerAppsBridge {
|
|
|
238
237
|
} catch (fetchErr) {
|
|
239
238
|
debugWarn(`[bridge] fetch THREW for ${method} ${urlLabel}:`, fetchErr);
|
|
240
239
|
debugLog(`[bridge] fetch THREW for ${method} ${urlLabel} | req body: ${typeof bodyInit === 'string' ? bodyInit.slice(0, 500) : bodyInit != null ? '<non-string body>' : '<no body>'}`);
|
|
241
|
-
scenario.fail(undefined, {
|
|
242
|
-
errorName: getSafeErrorName(fetchErr)
|
|
243
|
-
});
|
|
244
240
|
throw fetchErr;
|
|
245
241
|
}
|
|
246
242
|
const responseHeaders = {};
|
|
@@ -251,20 +247,27 @@ export class NativePowerAppsBridge {
|
|
|
251
247
|
const sdkKey = key === 'content-type' ? 'Content-Type' : key;
|
|
252
248
|
responseHeaders[sdkKey] = value;
|
|
253
249
|
});
|
|
254
|
-
const buffer = await response.arrayBuffer();
|
|
255
250
|
debugLog(`[bridge] ${method} ${urlLabel} → ${response.status}`);
|
|
251
|
+
const correlationProperties = getHttpCorrelationProperties(response.headers);
|
|
252
|
+
let buffer;
|
|
253
|
+
try {
|
|
254
|
+
buffer = await response.arrayBuffer();
|
|
255
|
+
} catch (readErr) {
|
|
256
|
+
debugWarn(`[bridge] HTTP ${response.status} for ${method} ${urlLabel} | failed to read response body:`, readErr);
|
|
257
|
+
getAppLogger().trackErrorEvent(HostOperationNames.BridgeHttpRequest, {
|
|
258
|
+
phase: 'readResponseBody',
|
|
259
|
+
errorName: getSafeErrorName(readErr),
|
|
260
|
+
httpStatus: response.status,
|
|
261
|
+
...correlationProperties
|
|
262
|
+
});
|
|
263
|
+
throw readErr;
|
|
264
|
+
}
|
|
256
265
|
if (!response.ok) {
|
|
257
266
|
const bodyText = new TextDecoder().decode(buffer).slice(0, 1000);
|
|
258
267
|
debugWarn(`[bridge] HTTP ${response.status} for ${method} ${urlLabel} | res: ${bodyText}`);
|
|
259
268
|
debugLog(`[bridge] HTTP ${response.status} for ${method} ${urlLabel} | req: ${typeof bodyInit === 'string' ? bodyInit.slice(0, 500) : bodyInit != null ? '<non-string body>' : '<no body>'} | res: ${bodyText}`);
|
|
260
|
-
scenario.completeWithError({
|
|
261
|
-
httpStatus: response.status
|
|
262
|
-
});
|
|
263
|
-
} else {
|
|
264
|
-
scenario.complete({
|
|
265
|
-
httpStatus: response.status
|
|
266
|
-
});
|
|
267
269
|
}
|
|
270
|
+
assertSuccessfulHttpStatus(response.status, method);
|
|
268
271
|
return [{
|
|
269
272
|
status: response.status,
|
|
270
273
|
headers: responseHeaders
|