codeapp-js 0.3.0 → 1.0.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/AI/codeapp.agent.md +105 -0
- package/AI/skills/connections/SKILL.md +47 -0
- package/AI/skills/dataverse/SKILL.md +99 -0
- package/AI/skills/environment-variables/SKILL.md +89 -0
- package/AI/skills/frontend-design/SKILL.md +34 -0
- package/AI/skills/jira/SKILL.md +81 -0
- package/AI/skills/office365-groups/SKILL.md +61 -0
- package/AI/skills/office365-outlook/SKILL.md +52 -0
- package/AI/skills/office365-users/SKILL.md +78 -0
- package/AI/skills/sharepoint/SKILL.md +77 -0
- package/AI/skills/sql/SKILL.md +85 -0
- package/AI/skills/start/SKILL.md +46 -0
- package/AI/skills/teams/SKILL.md +55 -0
- package/{examples/combined demo/.power/schemas/office365groups/office365groups.Schema.json → codeApp/.power/schemas/office365groups/office365groups.Schema.json} +2203 -2203
- package/codeApp/dist/codeapp.js +95 -1792
- package/codeApp/dist/connectors/azureKeyvault.js +459 -0
- package/codeApp/dist/connectors/jira.js +1247 -0
- package/codeApp/dist/connectors/office365groups.js +642 -0
- package/codeApp/dist/connectors/office365users.js +513 -0
- package/codeApp/dist/connectors/outlook.js +1393 -0
- package/{dev files/sharepoint.js → codeApp/dist/connectors/sharepoint.js} +239 -112
- package/codeApp/dist/connectors/sql.js +149 -0
- package/codeApp/dist/connectors/teams.js +280 -0
- package/codeApp/dist/power-apps-data.js +16 -2
- package/examples/{kanban → apps/kanban}/dist/dataverse.js +94 -94
- package/examples/{kanban → apps/kanban}/dist/environmentVar.js +55 -55
- package/examples/{kanban → apps/kanban}/dist/index.css +605 -605
- package/examples/{kanban → apps/kanban}/dist/index.html +21 -21
- package/examples/{kanban → apps/kanban}/dist/index.js +860 -860
- package/examples/{kanban → apps/kanban}/dist/office365groups.js +97 -97
- package/examples/apps/kanban/dist/office365users.js +451 -0
- package/examples/{kanban → apps/kanban}/dist/outlook.js +162 -162
- package/examples/{planning Poker/dist/power-apps-data.js → apps/kanban/dist/power-apps-data.js} +2953 -2953
- package/examples/{kanban → apps/kanban}/dist/sharepoint.js +435 -339
- package/examples/{kanban → apps/kanban}/power.config.json +35 -35
- package/examples/{planning Poker → apps/planning Poker}/additional files/customizations (tables).xml +6428 -6428
- package/examples/{planning Poker → apps/planning Poker}/additional files/dataverse-tables.json +165 -165
- package/examples/{planning Poker → apps/planning Poker}/additional files/readme.md +122 -122
- package/examples/{planning Poker → apps/planning Poker}/dist/dataverse.js +78 -78
- package/examples/{planning Poker → apps/planning Poker}/dist/index.html +198 -198
- package/examples/{planning Poker → apps/planning Poker}/dist/index.js +954 -954
- package/examples/{todo/dist/power-apps-data.js → apps/planning Poker/dist/power-apps-data.js } +2953 -2953
- package/examples/{planning Poker → apps/planning Poker}/dist/styles.css +815 -815
- package/examples/{planning Poker → apps/planning Poker}/power.config.json +50 -50
- package/examples/{outlook Demo2 → apps/solution explorer}/dist/codeapp.js +9 -245
- package/examples/apps/solution explorer/dist/index.html +80 -0
- package/examples/apps/solution explorer/dist/index.js +735 -0
- package/examples/apps/solution explorer/dist/styles.css +571 -0
- package/examples/apps/solution explorer/power.config.json +151 -0
- package/examples/{todo → apps/todo}/dist/dataverse.js +64 -64
- package/examples/{todo → apps/todo}/dist/index.html +75 -75
- package/examples/{todo → apps/todo}/dist/index.js +8 -8
- package/examples/{kanban → apps/todo}/dist/power-apps-data.js +2953 -2953
- package/examples/{todo → apps/todo}/dist/renderer.js +375 -375
- package/examples/{todo → apps/todo}/dist/styles.css +691 -691
- package/examples/{todo → apps/todo}/power.config.json +34 -34
- package/examples/combined demo/.power/schemas/appschemas/dataSourcesInfo.ts +6275 -7830
- package/examples/combined demo/.power/schemas/jira/jira.Schema.json +6903 -0
- package/examples/combined demo/.power/schemas/keyvault/keyvault.Schema.json +1600 -0
- package/examples/combined demo/.power/schemas/teams/teams.Schema.json +11112 -0
- package/examples/combined demo/dist/codeapp.js +394 -1098
- package/examples/{outlook Demo2/OutlookDemo_1_0_0_1.zip → combined demo/dist/icon-512.png} +0 -0
- package/examples/combined demo/dist/index.html +29 -511
- package/examples/combined demo/dist/index.js +490 -470
- package/examples/combined demo/dist/office365users.js +513 -0
- package/examples/combined demo/dist/outlook.js +1393 -0
- package/examples/combined demo/dist/power-apps-data.js +3079 -3006
- package/examples/combined demo/dist/styles.css +483 -0
- package/examples/combined demo/power.config.json +33 -42
- package/examples/combined demo/src/generated/index.ts +12 -14
- package/examples/combined demo/src/generated/models/AzureKeyVaultModel.ts +107 -0
- package/examples/combined demo/src/generated/models/JiraModel.ts +501 -0
- package/examples/combined demo/src/generated/services/AzureKeyVaultService.ts +257 -0
- package/examples/combined demo/src/generated/services/JiraService.ts +1124 -0
- package/examples/dataverse Demo/dist/codeapp.js +394 -1085
- package/examples/dataverse Demo/dist/icon-512.png +0 -0
- package/examples/dataverse Demo/dist/index.html +146 -54
- package/examples/dataverse Demo/dist/index.js +693 -83
- package/examples/dataverse Demo/dist/power-apps-data.js +3079 -2911
- package/examples/dataverse Demo/dist/styles.css +528 -0
- package/examples/dataverse Demo/power.config.json +41 -35
- package/examples/dataverse Demo/readme.md +79 -79
- package/examples/groups Demo/dist/codeapp.js +394 -1085
- package/examples/groups Demo/dist/icon-512.png +0 -0
- package/examples/groups Demo/dist/index.html +21 -25
- package/examples/groups Demo/dist/index.js +304 -113
- package/examples/groups Demo/dist/office365groups.js +642 -0
- package/examples/groups Demo/dist/power-apps-data.js +3079 -2911
- package/examples/groups Demo/dist/styles.css +509 -0
- package/examples/groups Demo/power.config.json +25 -25
- package/examples/myProfile/dist/codeapp.js +398 -0
- package/examples/myProfile/dist/index.html +21 -184
- package/examples/myProfile/dist/index.js +324 -141
- package/examples/myProfile/dist/office365users.js +517 -169
- package/examples/myProfile/dist/power-apps-data.js +3080 -2953
- package/examples/myProfile/dist/styles.css +458 -0
- package/examples/myProfile/power.config.json +24 -23
- package/examples/outlook Demo/dist/codeapp.js +394 -1085
- package/examples/outlook Demo/dist/index.html +150 -35
- package/examples/outlook Demo/dist/index.js +516 -170
- package/examples/outlook Demo/dist/outlook.js +1393 -121
- package/examples/outlook Demo/dist/power-apps-data.js +3079 -2911
- package/examples/outlook Demo/dist/styles.css +408 -84
- package/examples/outlook Demo/power.config.json +24 -23
- package/examples/outlook Demo/readme.md +92 -82
- package/examples/sharePoint Demo/dist/codeapp.js +394 -1085
- package/examples/sharePoint Demo/dist/icon-512.png +0 -0
- package/examples/sharePoint Demo/dist/index.html +22 -255
- package/examples/sharePoint Demo/dist/index.js +899 -262
- package/examples/sharePoint Demo/dist/power-apps-data.js +3079 -2911
- package/examples/sharePoint Demo/dist/sharepoint.js +466 -0
- package/examples/sharePoint Demo/dist/styles.css +587 -0
- package/examples/sharePoint Demo/power.config.json +23 -22
- package/package.json +1 -1
- package/readme.md +465 -76
- package/.vscode/settings.json +0 -6
- package/dev files/customConnector.js +0 -98
- package/dev files/dataverse.js +0 -120
- package/dev files/environmentVar.js +0 -55
- package/dev files/office365groups.js +0 -65
- package/dev files/office365users.js +0 -169
- package/dev files/outlook.js +0 -330
- package/dev files/power-apps-data.js +0 -2952
- package/examples/combined demo/.power/schemas/office365/office365.Schema.json +0 -21098
- package/examples/combined demo/.power/schemas/office365users/office365users.Schema.json +0 -2094
- package/examples/kanban/agent/decision-log.md +0 -9
- package/examples/kanban/agent/mockup-01-editorial-glass.html +0 -159
- package/examples/kanban/agent/mockup-02-dark-rail.html +0 -147
- package/examples/kanban/agent/mockup-03-paper-grid.html +0 -114
- package/examples/kanban/agent/mockup-04-neon-minimal.html +0 -141
- package/examples/kanban/agent/mockup-05-mono-architect.html +0 -119
- package/examples/kanban/dist/office365users.js +0 -169
- package/examples/kanban/src/generated/index.ts +0 -14
- package/examples/kanban/src/generated/models/Office365GroupsModel.ts +0 -363
- package/examples/kanban/src/generated/models/Office365OutlookModel.ts +0 -2046
- package/examples/kanban/src/generated/models/Office365UsersModel.ts +0 -254
- package/examples/kanban/src/generated/services/Office365GroupsService.ts +0 -326
- package/examples/kanban/src/generated/services/Office365OutlookService.ts +0 -2476
- package/examples/kanban/src/generated/services/Office365UsersService.ts +0 -358
- package/examples/outlook Demo2/agent/decision-log.md +0 -7
- package/examples/outlook Demo2/dist/index.html +0 -98
- package/examples/outlook Demo2/dist/index.js +0 -272
- package/examples/outlook Demo2/dist/styles.css +0 -639
- package/examples/outlook Demo2/power.config.json +0 -23
- package/examples/planning Poker/.vscode/settings.json +0 -5
- package/examples/sharePoint Demo/agent/decision-log.md +0 -17
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/index.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/models/Office365GroupsModel.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/models/Office365OutlookModel.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/models/Office365UsersModel.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/services/Office365GroupsService.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/services/Office365OutlookService.ts +0 -0
- /package/examples/{outlook Demo2 → apps/kanban}/src/generated/services/Office365UsersService.ts +0 -0
- /package/examples/{planning Poker → apps/planning Poker}/additional files/AgilePoker_1_0_0_1.zip +0 -0
- /package/examples/{planning Poker → apps/planning Poker}/additional files/PokerTables_1_0_0_1.zip +0 -0
- /package/examples/{outlook Demo2 → apps/solution explorer}/dist/icon-512.png +0 -0
- /package/examples/{outlook Demo2 → apps/solution explorer}/dist/power-apps-data.js +0 -0
- /package/examples/{todo → apps/todo}/dist/icon192.png +0 -0
|
@@ -1,2952 +0,0 @@
|
|
|
1
|
-
/* power-apps-data.js - Standalone Power Apps SDK for Code Apps
|
|
2
|
-
Converted from @microsoft/power-apps v1.0.4
|
|
3
|
-
Zero dependencies - all code is self-contained */
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
-
|
|
8
|
-
var DefaultPowerAppsBridge = class {
|
|
9
|
-
constructor() {
|
|
10
|
-
__publicField(this, "_antiCSRFToken");
|
|
11
|
-
__publicField(this, "_callbacks", {});
|
|
12
|
-
__publicField(this, "_currentCallbackId", 0);
|
|
13
|
-
__publicField(this, "_instanceId", Date.now().toString());
|
|
14
|
-
__publicField(this, "_messageChannel", new window.MessageChannel());
|
|
15
|
-
__publicField(this, "_postMessageQueue", []);
|
|
16
|
-
__publicField(this, "_postMessageSource");
|
|
17
|
-
__publicField(this, "_handleMessageEvent", (messageEvent) => {
|
|
18
|
-
const message = messageEvent.data;
|
|
19
|
-
if (message && typeof message.isPluginCall === "boolean") {
|
|
20
|
-
if (message.isPluginCall) {
|
|
21
|
-
const callbackId = message.callbackId;
|
|
22
|
-
const status = message.status;
|
|
23
|
-
const args = message.args;
|
|
24
|
-
const keepCallback = message.keepCallback;
|
|
25
|
-
try {
|
|
26
|
-
const callback = this._callbacks[callbackId];
|
|
27
|
-
if (keepCallback) {
|
|
28
|
-
if (callback && callback.onUpdate) {
|
|
29
|
-
callback.onUpdate(message.args?.[0]);
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
if (callback) {
|
|
33
|
-
if (status === 1) {
|
|
34
|
-
callback.resolve(args[0]);
|
|
35
|
-
} else if (status !== 0) {
|
|
36
|
-
callback.reject(args);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (!keepCallback) {
|
|
40
|
-
delete this._callbacks[callbackId];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
console.error(error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} else if (message && message.messageType === "initCommunication") {
|
|
48
|
-
this._antiCSRFToken = message.antiCSRFToken;
|
|
49
|
-
this._postMessageSource = this._messageChannel.port1;
|
|
50
|
-
if (this._postMessageSource) {
|
|
51
|
-
for (let i = 0; i < this._postMessageQueue.length; i++) {
|
|
52
|
-
this._postMessageQueue[i].antiCSRFToken = this._antiCSRFToken;
|
|
53
|
-
this._postMessageSource.postMessage(this._postMessageQueue[i]);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
async initialize() {
|
|
60
|
-
this._messageChannel.port1.onmessage = this._handleMessageEvent;
|
|
61
|
-
window.parent.postMessage({
|
|
62
|
-
messageType: "initCommunicationWithPort",
|
|
63
|
-
instanceId: this._instanceId
|
|
64
|
-
}, "*", [this._messageChannel.port2]);
|
|
65
|
-
}
|
|
66
|
-
async executePluginAsync(pluginName, pluginAction, params = [], onUpdate) {
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const callbackId = this._getCallbackId(pluginName);
|
|
69
|
-
this._callbacks[callbackId] = { resolve, reject, onUpdate };
|
|
70
|
-
this._sendMessage({
|
|
71
|
-
isPluginCall: true,
|
|
72
|
-
callbackId,
|
|
73
|
-
service: pluginName,
|
|
74
|
-
action: pluginAction,
|
|
75
|
-
actionArgs: params,
|
|
76
|
-
antiCSRFToken: this._antiCSRFToken
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
_sendMessage(message) {
|
|
81
|
-
if (!this._postMessageSource) {
|
|
82
|
-
this._postMessageQueue.push(message);
|
|
83
|
-
} else {
|
|
84
|
-
this._postMessageSource.postMessage(message);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
_getCallbackId(pluginName) {
|
|
88
|
-
return "instanceId=" + this._instanceId + "_" + pluginName + this._currentCallbackId++;
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
var bridgePromise;
|
|
93
|
-
async function executePluginAsync(pluginName, pluginAction, params = [], update) {
|
|
94
|
-
const powerAppsBridge = await getBridge();
|
|
95
|
-
return powerAppsBridge.executePluginAsync(pluginName, pluginAction, params, update);
|
|
96
|
-
}
|
|
97
|
-
async function getBridge() {
|
|
98
|
-
if (!bridgePromise) {
|
|
99
|
-
bridgePromise = new Promise(async (resolve, reject) => {
|
|
100
|
-
try {
|
|
101
|
-
const bridge = window && window.powerAppsBridge ? window.powerAppsBridge : new DefaultPowerAppsBridge();
|
|
102
|
-
await bridge.initialize();
|
|
103
|
-
resolve(bridge);
|
|
104
|
-
} catch (error) {
|
|
105
|
-
reject(error);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
return bridgePromise;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
var context;
|
|
113
|
-
async function getContext() {
|
|
114
|
-
if (context) {
|
|
115
|
-
return context;
|
|
116
|
-
}
|
|
117
|
-
context = await executePluginAsync("AppLifecycle", "getContext");
|
|
118
|
-
return context;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
var IncompatibleMessageReceiver = class {
|
|
122
|
-
constructor(versionInfo, incompatibilityDescription) {
|
|
123
|
-
__publicField(this, "versionInfo");
|
|
124
|
-
__publicField(this, "incompatibilityDescription");
|
|
125
|
-
__publicField(this, "isCompatible", false);
|
|
126
|
-
this.versionInfo = versionInfo;
|
|
127
|
-
this.incompatibilityDescription = incompatibilityDescription;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
var SendMessageOperation = class {
|
|
132
|
-
constructor(resultPromise, sendUpdate) {
|
|
133
|
-
__publicField(this, "resultPromise");
|
|
134
|
-
__publicField(this, "sendUpdate");
|
|
135
|
-
/**
|
|
136
|
-
* When completed is false onMessageReceived and sendUpdate will be visible.
|
|
137
|
-
* When completed is true then these are hidden.
|
|
138
|
-
*/
|
|
139
|
-
__publicField(this, "completed", false);
|
|
140
|
-
__publicField(this, "onMessageReceived");
|
|
141
|
-
this.resultPromise = resultPromise;
|
|
142
|
-
this.sendUpdate = sendUpdate;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
var CompatibleMessageReceiver = class {
|
|
147
|
-
constructor(_receiverName, versionInfo) {
|
|
148
|
-
__publicField(this, "_receiverName");
|
|
149
|
-
__publicField(this, "versionInfo");
|
|
150
|
-
__publicField(this, "isCompatible", true);
|
|
151
|
-
this._receiverName = _receiverName;
|
|
152
|
-
this.versionInfo = versionInfo;
|
|
153
|
-
}
|
|
154
|
-
async sendMessage(message, onMessageReceived) {
|
|
155
|
-
let resolveOperationPromise;
|
|
156
|
-
let rejectOperationPromise;
|
|
157
|
-
const operationPromise = new Promise((resolve, reject) => {
|
|
158
|
-
resolveOperationPromise = resolve;
|
|
159
|
-
rejectOperationPromise = reject;
|
|
160
|
-
});
|
|
161
|
-
const correlationId = crypto.randomUUID();
|
|
162
|
-
const handleMessage = (compatibleReceiverMessage) => {
|
|
163
|
-
try {
|
|
164
|
-
if (sendMessageOperation.completed) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (compatibleReceiverMessage) {
|
|
168
|
-
if (compatibleReceiverMessage.isUpdate) {
|
|
169
|
-
if (sendMessageOperation.onMessageReceived) {
|
|
170
|
-
try {
|
|
171
|
-
sendMessageOperation.onMessageReceived(compatibleReceiverMessage.message);
|
|
172
|
-
} catch (error) {
|
|
173
|
-
sendMessageOperation.completed = true;
|
|
174
|
-
rejectOperationPromise(error);
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
sendMessageOperation.completed = true;
|
|
178
|
-
rejectOperationPromise(new Error(`Native receiver expected a message handler, but no handler was supplied. Message: ${compatibleReceiverMessage.message}`));
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
sendMessageOperation.completed = true;
|
|
182
|
-
resolveOperationPromise(compatibleReceiverMessage.message);
|
|
183
|
-
}
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
} catch {
|
|
187
|
-
}
|
|
188
|
-
sendMessageOperation.completed = true;
|
|
189
|
-
resolveOperationPromise(compatibleReceiverMessage.message);
|
|
190
|
-
};
|
|
191
|
-
const handleError = (error) => {
|
|
192
|
-
sendMessageOperation.completed = true;
|
|
193
|
-
rejectOperationPromise(error);
|
|
194
|
-
};
|
|
195
|
-
const sendUpdate = (updateMessage) => {
|
|
196
|
-
if (sendMessageOperation.completed) {
|
|
197
|
-
throw new Error("Tried to send update for completed operation.");
|
|
198
|
-
}
|
|
199
|
-
executePluginAsync("SendMessagePlugin", "sendMessage", [
|
|
200
|
-
this._receiverName,
|
|
201
|
-
updateMessage,
|
|
202
|
-
correlationId
|
|
203
|
-
]);
|
|
204
|
-
};
|
|
205
|
-
const sendMessageOperation = new SendMessageOperation(operationPromise, sendUpdate);
|
|
206
|
-
sendMessageOperation.onMessageReceived = onMessageReceived;
|
|
207
|
-
try {
|
|
208
|
-
await executePluginAsync("SendMessagePlugin", "sendMessage", [this._receiverName, message, correlationId], (response) => {
|
|
209
|
-
handleMessage(response);
|
|
210
|
-
});
|
|
211
|
-
} catch (error) {
|
|
212
|
-
handleError(error);
|
|
213
|
-
}
|
|
214
|
-
return sendMessageOperation;
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
var SendMessage = class _SendMessage {
|
|
219
|
-
static createInstanceAsync() {
|
|
220
|
-
return Promise.resolve(new _SendMessage());
|
|
221
|
-
}
|
|
222
|
-
async getMessageReceiverAsync(receiverName, isCompatibleChecker) {
|
|
223
|
-
const versionInfo = await this._getVersionInfo(receiverName);
|
|
224
|
-
if (versionInfo) {
|
|
225
|
-
const compatibilityCheckerResult = isCompatibleChecker(versionInfo);
|
|
226
|
-
if (compatibilityCheckerResult.isCompatible === false) {
|
|
227
|
-
return new IncompatibleMessageReceiver(versionInfo, compatibilityCheckerResult.incompatibilityDescription || "");
|
|
228
|
-
} else {
|
|
229
|
-
return new CompatibleMessageReceiver(receiverName, versionInfo);
|
|
230
|
-
}
|
|
231
|
-
} else {
|
|
232
|
-
return new IncompatibleMessageReceiver(void 0, `No receiver ${receiverName} registered.`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
async _getVersionInfo(receiverName) {
|
|
236
|
-
const result = await executePluginAsync("SendMessagePlugin", "getVersionInfo", [receiverName]);
|
|
237
|
-
return result;
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
var loggerInstance;
|
|
242
|
-
async function initializeLogger(logger) {
|
|
243
|
-
loggerInstance = logger;
|
|
244
|
-
const sendMessagePlugin = await SendMessage.createInstanceAsync();
|
|
245
|
-
const receiver = await sendMessagePlugin.getMessageReceiverAsync("PowerApps.AppMonitorReceiver", (versionInfo) => {
|
|
246
|
-
let isCompatible = false;
|
|
247
|
-
if (versionInfo === "1.0.0") {
|
|
248
|
-
isCompatible = true;
|
|
249
|
-
}
|
|
250
|
-
return { isCompatible };
|
|
251
|
-
});
|
|
252
|
-
if (receiver.isCompatible) {
|
|
253
|
-
await receiver.sendMessage("initialize", (message) => {
|
|
254
|
-
const parsedMessage = JSON.parse(message);
|
|
255
|
-
if (parsedMessage.metrics) {
|
|
256
|
-
for (const metric of parsedMessage.metrics) {
|
|
257
|
-
loggerInstance.logMetric?.(metric);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function getAppLoadedPerformanceData() {
|
|
265
|
-
const performanceApi = new PerformanceApi();
|
|
266
|
-
const perfData = {
|
|
267
|
-
appTimeOrigin: performanceApi.timeOrigin
|
|
268
|
-
};
|
|
269
|
-
const navigationTimingEntries = performanceApi.getEntriesByType("navigation");
|
|
270
|
-
const navigationTiming = navigationTimingEntries[0];
|
|
271
|
-
if (navigationTiming) {
|
|
272
|
-
perfData.appNavigateType = navigationTiming.type;
|
|
273
|
-
perfData.appNavigationStart = navigationTiming.startTime;
|
|
274
|
-
perfData.appNavigationDuration = navigationTiming.duration;
|
|
275
|
-
perfData.appEncodedBodySize = navigationTiming.encodedBodySize;
|
|
276
|
-
perfData.appNextHopProtocol = navigationTiming.nextHopProtocol;
|
|
277
|
-
perfData.appDomainLookupStart = navigationTiming.domainLookupStart;
|
|
278
|
-
perfData.appDomainLookupEnd = navigationTiming.domainLookupEnd;
|
|
279
|
-
perfData.appConnectStart = navigationTiming.connectStart;
|
|
280
|
-
perfData.appConnectEnd = navigationTiming.connectEnd;
|
|
281
|
-
perfData.appSecureConnectionStart = navigationTiming.secureConnectionStart;
|
|
282
|
-
perfData.appFetchStart = navigationTiming.fetchStart;
|
|
283
|
-
perfData.appRequestStart = navigationTiming.requestStart;
|
|
284
|
-
perfData.appResponseStart = navigationTiming.responseStart;
|
|
285
|
-
perfData.appResponseEnd = navigationTiming.responseEnd;
|
|
286
|
-
perfData.appLoadEventEnd = navigationTiming.loadEventEnd;
|
|
287
|
-
perfData.appDomInteractive = navigationTiming.domInteractive;
|
|
288
|
-
perfData.appDomContentLoadedEventStart = navigationTiming.domContentLoadedEventStart;
|
|
289
|
-
}
|
|
290
|
-
return perfData;
|
|
291
|
-
}
|
|
292
|
-
var PerformanceApi = class {
|
|
293
|
-
constructor(targetWindow = window) {
|
|
294
|
-
__publicField(this, "_performance");
|
|
295
|
-
this._performance = targetWindow.performance;
|
|
296
|
-
}
|
|
297
|
-
get timeOrigin() {
|
|
298
|
-
return this._performance?.timeOrigin;
|
|
299
|
-
}
|
|
300
|
-
getEntriesByType(type) {
|
|
301
|
-
if (!this._performance?.getEntriesByType) {
|
|
302
|
-
return [];
|
|
303
|
-
}
|
|
304
|
-
return this._performance.getEntriesByType(type);
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
executePluginAsync("AppLifecycle", "notifyAppSdkLoaded", [getAppLoadedPerformanceData()]);
|
|
309
|
-
|
|
310
|
-
function setConfig(config) {
|
|
311
|
-
if (config.logger) {
|
|
312
|
-
initializeLogger(config.logger);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
var HttpMethod;
|
|
317
|
-
(function(HttpMethod2) {
|
|
318
|
-
HttpMethod2["GET"] = "GET";
|
|
319
|
-
HttpMethod2["POST"] = "POST";
|
|
320
|
-
HttpMethod2["PUT"] = "PUT";
|
|
321
|
-
HttpMethod2["DELETE"] = "DELETE";
|
|
322
|
-
HttpMethod2["PATCH"] = "PATCH";
|
|
323
|
-
})(HttpMethod || (HttpMethod = {}));
|
|
324
|
-
var DataSources;
|
|
325
|
-
(function(DataSources2) {
|
|
326
|
-
DataSources2["Dataverse"] = "Dataverse";
|
|
327
|
-
DataSources2["Connector"] = "Connector";
|
|
328
|
-
})(DataSources || (DataSources = {}));
|
|
329
|
-
|
|
330
|
-
var ErrorCodes;
|
|
331
|
-
(function(ErrorCodes2) {
|
|
332
|
-
ErrorCodes2["InitializationFailed"] = "PDR_INIT_FAILED";
|
|
333
|
-
ErrorCodes2["InvalidXrmInfo"] = "INVALID_XRM_INFO";
|
|
334
|
-
ErrorCodes2["OperationsNotInitialized"] = "OPS_NOT_INITIALIZED";
|
|
335
|
-
ErrorCodes2["InvalidOperationExecutor"] = "INVALID_OPERATION_EXECUTOR";
|
|
336
|
-
ErrorCodes2["DataSourceNotFound"] = "CONNECTION_NOT_FOUND";
|
|
337
|
-
ErrorCodes2["DuplicateDataSource"] = "DUPLICATE_DATA_SOURCE";
|
|
338
|
-
ErrorCodes2["InitializationError"] = "RDSS_INIT_ERROR";
|
|
339
|
-
ErrorCodes2["InvalidDataSource"] = "INVALID_DATA_SOURCE";
|
|
340
|
-
ErrorCodes2["DataSourcesInfoNotFound"] = "DATA_SOURCES_INFO_NOT_FOUND";
|
|
341
|
-
ErrorCodes2["DataClientInitFailed"] = "DATA_CLIENT_INIT_FAILED";
|
|
342
|
-
ErrorCodes2["DataClientNotInitialized"] = "DATA_CLIENT_NOT_INITIALIZED";
|
|
343
|
-
ErrorCodes2["MetadataClientInitFailed"] = "METADATA_CLIENT_INIT_FAILED";
|
|
344
|
-
ErrorCodes2["MetadataClientNotInitialized"] = "METADATA_CLIENT_NOT_INITIALIZED";
|
|
345
|
-
ErrorCodes2["ClientProviderNotAvailable"] = "CLIENT_PROVIDER_NOT_AVAILABLE";
|
|
346
|
-
ErrorCodes2["ConnectionReferenceNotFound"] = "CONNECTION_REFERENCE_NOT_FOUND";
|
|
347
|
-
ErrorCodes2["DataClientNotAvailable"] = "DATA_CLIENT_NOT_AVAILABLE";
|
|
348
|
-
ErrorCodes2["DataSourceServiceNotAvailable"] = "DATA_SOURCE_SERVICE_NOT_AVAILABLE";
|
|
349
|
-
ErrorCodes2["MetadataClientNotAvailable"] = "METADATA_CLIENT_NOT_AVAILABLE";
|
|
350
|
-
ErrorCodes2["ConnectionConfigFetchFailed"] = "CONNECTION_CONFIG_FETCH_FAILED";
|
|
351
|
-
ErrorCodes2["DataSourceConfigFetchFailed"] = "DATA_SOURCE_CONFIG_FETCH_FAILED";
|
|
352
|
-
ErrorCodes2["InvalidMetadataResponse"] = "INVALID_METADATA_RESPONSE";
|
|
353
|
-
ErrorCodes2["TokenAcquisitionFailed"] = "TOKEN_ACQUISITION_FAILED";
|
|
354
|
-
})(ErrorCodes || (ErrorCodes = {}));
|
|
355
|
-
|
|
356
|
-
var UnknownErrorMessage = "An unknown error occurred";
|
|
357
|
-
var ErrorMessages = {
|
|
358
|
-
// PowerDataRuntime specific errors
|
|
359
|
-
[ErrorCodes.InitializationFailed]: "Failed to initialize PowerDataRuntime",
|
|
360
|
-
[ErrorCodes.InvalidXrmInfo]: "Xrm info is required",
|
|
361
|
-
[ErrorCodes.OperationsNotInitialized]: "PowerDataRuntime is not initialized",
|
|
362
|
-
// RuntimeDataSourceService specific errors
|
|
363
|
-
[ErrorCodes.DataSourceNotFound]: "Data source not found",
|
|
364
|
-
[ErrorCodes.DuplicateDataSource]: "Duplicate data source",
|
|
365
|
-
[ErrorCodes.InitializationError]: "Failed to initialize RuntimeDataSourceService",
|
|
366
|
-
[ErrorCodes.InvalidDataSource]: "Invalid data source",
|
|
367
|
-
// PowerDataSourcesInfoProvider specific errors
|
|
368
|
-
[ErrorCodes.DataSourcesInfoNotFound]: "DataSourcesInfo must be provided to initialize the singleton instance.",
|
|
369
|
-
// DataClientProvider specific errors
|
|
370
|
-
[ErrorCodes.DataClientInitFailed]: "Failed to initialize PowerDataClient",
|
|
371
|
-
[ErrorCodes.DataClientNotInitialized]: "PowerDataClient is not initialized",
|
|
372
|
-
[ErrorCodes.MetadataClientInitFailed]: "Failed to initialize PowerMetadataClient",
|
|
373
|
-
[ErrorCodes.MetadataClientNotInitialized]: "PowerMetadataClient is not initialized",
|
|
374
|
-
// DataOperation specific errors
|
|
375
|
-
[ErrorCodes.ClientProviderNotAvailable]: "Client provider is not available",
|
|
376
|
-
[ErrorCodes.ConnectionReferenceNotFound]: "Connection reference not found",
|
|
377
|
-
[ErrorCodes.DataClientNotAvailable]: "PowerDataClient is not available",
|
|
378
|
-
[ErrorCodes.DataSourceServiceNotAvailable]: "Data source service is not available",
|
|
379
|
-
[ErrorCodes.MetadataClientNotAvailable]: "PowerMetadataClient is not available",
|
|
380
|
-
// MetadataClient specific errors
|
|
381
|
-
[ErrorCodes.ConnectionConfigFetchFailed]: "Failed to fetch connection configurations",
|
|
382
|
-
[ErrorCodes.DataSourceConfigFetchFailed]: "Failed to fetch data source configurations",
|
|
383
|
-
[ErrorCodes.InvalidMetadataResponse]: "Invalid metadata response format",
|
|
384
|
-
// RuntimeDataClient specific errors
|
|
385
|
-
[ErrorCodes.TokenAcquisitionFailed]: "Failed to acquire access token"
|
|
386
|
-
};
|
|
387
|
-
var DataOperationErrorMessages;
|
|
388
|
-
(function(DataOperationErrorMessages2) {
|
|
389
|
-
DataOperationErrorMessages2["CreateFailed"] = "Create operation failure";
|
|
390
|
-
DataOperationErrorMessages2["DeleteFailed"] = "Delete operation failure";
|
|
391
|
-
DataOperationErrorMessages2["ExecuteFailed"] = "Execute operation failure";
|
|
392
|
-
DataOperationErrorMessages2["InvalidOperationParameters"] = "Invalid operation parameters";
|
|
393
|
-
DataOperationErrorMessages2["InvalidRequest"] = "Invalid request";
|
|
394
|
-
DataOperationErrorMessages2["InvalidResponse"] = "Invalid response format";
|
|
395
|
-
DataOperationErrorMessages2["MissingConnectorOperation"] = "Connector operation is required";
|
|
396
|
-
DataOperationErrorMessages2["MissingDataverseRequest"] = "Dataverse request is required";
|
|
397
|
-
DataOperationErrorMessages2["MissingOperationName"] = "Operation name is required";
|
|
398
|
-
DataOperationErrorMessages2["MissingRequestBody"] = "Request body is required";
|
|
399
|
-
DataOperationErrorMessages2["RetrieveFailed"] = "Retrieve operation failure";
|
|
400
|
-
DataOperationErrorMessages2["RetrieveMultipleFailed"] = "Retrieve multiple records operation failure";
|
|
401
|
-
DataOperationErrorMessages2["UpdateFailed"] = "Update operation failure";
|
|
402
|
-
})(DataOperationErrorMessages || (DataOperationErrorMessages = {}));
|
|
403
|
-
|
|
404
|
-
function isOperationResult(result) {
|
|
405
|
-
return result?.success !== void 0;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
var ServiceName = "PublishedAppTelemetry";
|
|
409
|
-
var TelemetryActionNames;
|
|
410
|
-
(function(TelemetryActionNames2) {
|
|
411
|
-
TelemetryActionNames2["trackEvent"] = "trackEvent";
|
|
412
|
-
TelemetryActionNames2["trackException"] = "trackException";
|
|
413
|
-
TelemetryActionNames2["trackMetric"] = "trackMetric";
|
|
414
|
-
TelemetryActionNames2["startScenario"] = "startScenario";
|
|
415
|
-
TelemetryActionNames2["endScenario"] = "endScenario";
|
|
416
|
-
TelemetryActionNames2["setDefaultProperties"] = "setDefaultProperties";
|
|
417
|
-
})(TelemetryActionNames || (TelemetryActionNames = {}));
|
|
418
|
-
var _Log = class _Log {
|
|
419
|
-
constructor(_powerOperationExecutor) {
|
|
420
|
-
__publicField(this, "_powerOperationExecutor");
|
|
421
|
-
this._powerOperationExecutor = _powerOperationExecutor;
|
|
422
|
-
}
|
|
423
|
-
static createInstance(powerOperationExecutor) {
|
|
424
|
-
if (!_Log._instance) {
|
|
425
|
-
_Log._instance = new _Log(powerOperationExecutor);
|
|
426
|
-
} else {
|
|
427
|
-
_Log.trackEvent("TelemetryLogger", {
|
|
428
|
-
message: "Attempted to create an instance when instance is already created."
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
return _Log._instance;
|
|
432
|
-
}
|
|
433
|
-
// Since powerDataRuntime can be reset, we need to be able to reset the instance of Log as well.
|
|
434
|
-
static resetInstance() {
|
|
435
|
-
_Log._instance = null;
|
|
436
|
-
}
|
|
437
|
-
static async _sendMessage(actionName, ...args) {
|
|
438
|
-
try {
|
|
439
|
-
const instance = _Log._getInstance();
|
|
440
|
-
const result = await instance._powerOperationExecutor.execute(ServiceName, actionName, args);
|
|
441
|
-
if (!result.success) {
|
|
442
|
-
console.error({
|
|
443
|
-
message: `PowerDataRuntime.TelemetryLogger: Failed to send telemetry message.`,
|
|
444
|
-
error: result.error,
|
|
445
|
-
telemetryArgs: args
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
} catch (error) {
|
|
449
|
-
console.error({
|
|
450
|
-
message: `PowerDataRuntime.TelemetryLogger: Failed to send telemetry message.`,
|
|
451
|
-
error,
|
|
452
|
-
telemetryArgs: args
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
static trackEvent(eventName, eventData) {
|
|
457
|
-
const serializedData = eventData ? _Log._serializeErrors(eventData) : eventData;
|
|
458
|
-
return _Log._sendMessage(TelemetryActionNames.trackEvent, `PowerDataRuntime.${eventName}`, serializedData);
|
|
459
|
-
}
|
|
460
|
-
static trackException(exception) {
|
|
461
|
-
return _Log._sendMessage(TelemetryActionNames.trackException, exception);
|
|
462
|
-
}
|
|
463
|
-
static trackMetric(metricName, value) {
|
|
464
|
-
return _Log._sendMessage(TelemetryActionNames.trackMetric, `PowerDataRuntime.${metricName}`, value);
|
|
465
|
-
}
|
|
466
|
-
static startScenario(scenarioName) {
|
|
467
|
-
return _Log._sendMessage(TelemetryActionNames.startScenario, `PowerDataRuntime.${scenarioName}`);
|
|
468
|
-
}
|
|
469
|
-
static endScenario(scenarioName) {
|
|
470
|
-
return _Log._sendMessage(TelemetryActionNames.endScenario, `PowerDataRuntime.${scenarioName}`);
|
|
471
|
-
}
|
|
472
|
-
static setDefaultProperties(properties) {
|
|
473
|
-
return _Log._sendMessage(TelemetryActionNames.setDefaultProperties, properties);
|
|
474
|
-
}
|
|
475
|
-
static _getInstance() {
|
|
476
|
-
if (!_Log._instance) {
|
|
477
|
-
throw new Error("PowerDataRuntime.TelemetryLogger: Attempted to log telemetry prior to instantiation.");
|
|
478
|
-
}
|
|
479
|
-
return _Log._instance;
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Recursively serializes Error objects in an object to prevent empty object serialization
|
|
483
|
-
* when passed through postMessage's structured clone algorithm.
|
|
484
|
-
* @param obj - The object to process
|
|
485
|
-
* @returns A new object with Error instances replaced by serializable objects
|
|
486
|
-
*/
|
|
487
|
-
static _serializeErrors(obj) {
|
|
488
|
-
if (obj === null || obj === void 0) {
|
|
489
|
-
return obj;
|
|
490
|
-
}
|
|
491
|
-
if (obj instanceof Error) {
|
|
492
|
-
return {
|
|
493
|
-
errorMessage: obj.message,
|
|
494
|
-
errorStack: obj.stack,
|
|
495
|
-
errorType: obj.name
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
if (Array.isArray(obj)) {
|
|
499
|
-
return obj.map((item) => _Log._serializeErrors(item));
|
|
500
|
-
}
|
|
501
|
-
if (typeof obj === "object" && obj !== null && Object.getPrototypeOf(obj) === Object.prototype) {
|
|
502
|
-
const serialized = {};
|
|
503
|
-
for (const key in obj) {
|
|
504
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
505
|
-
serialized[key] = _Log._serializeErrors(obj[key]);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return serialized;
|
|
509
|
-
}
|
|
510
|
-
return obj;
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
__publicField(_Log, "_instance", null);
|
|
514
|
-
var Log = _Log;
|
|
515
|
-
|
|
516
|
-
var PowerDataRuntimeError = class extends Error {
|
|
517
|
-
/**
|
|
518
|
-
* Creates an instance of PowerDataRuntimeError.
|
|
519
|
-
* @param code - The error code associated with the error.
|
|
520
|
-
* @param additionalInfo - Optional additional information to include in the error message.
|
|
521
|
-
* @param messageOverride - Optional override for the default error message.
|
|
522
|
-
*/
|
|
523
|
-
constructor(code, additionalInfo, messageOverride) {
|
|
524
|
-
let message = messageOverride || ErrorMessages[code] || UnknownErrorMessage;
|
|
525
|
-
if (additionalInfo) {
|
|
526
|
-
message += `: ${additionalInfo}`;
|
|
527
|
-
}
|
|
528
|
-
super(message);
|
|
529
|
-
__publicField(this, "code");
|
|
530
|
-
this.code = code;
|
|
531
|
-
this.name = "PowerDataRuntimeError";
|
|
532
|
-
Log.trackException(this);
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
var HeaderNames;
|
|
537
|
-
(function(HeaderNames2) {
|
|
538
|
-
HeaderNames2["RequestId"] = "x-ms-client-request-id";
|
|
539
|
-
})(HeaderNames || (HeaderNames = {}));
|
|
540
|
-
var DataverseOperationName;
|
|
541
|
-
(function(DataverseOperationName2) {
|
|
542
|
-
DataverseOperationName2["CreateRecord"] = "dataverseDataOperation.createRecordAsync";
|
|
543
|
-
DataverseOperationName2["UpdateRecord"] = "dataverseDataOperation.updateRecordAsync";
|
|
544
|
-
DataverseOperationName2["DeleteRecord"] = "dataverseDataOperation.deleteRecordAsync";
|
|
545
|
-
DataverseOperationName2["RetrieveRecord"] = "dataverseDataOperation.retrieveRecordAsync";
|
|
546
|
-
DataverseOperationName2["RetrieveMultipleRecords"] = "dataverseDataOperation.retrieveMultipleRecordsAsync";
|
|
547
|
-
})(DataverseOperationName || (DataverseOperationName = {}));
|
|
548
|
-
var ConnectorOperationName;
|
|
549
|
-
(function(ConnectorOperationName2) {
|
|
550
|
-
ConnectorOperationName2["CreateRecord"] = "connectorDataOperation.createRecordAsync";
|
|
551
|
-
ConnectorOperationName2["UpdateRecord"] = "connectorDataOperation.updateRecordAsync";
|
|
552
|
-
ConnectorOperationName2["DeleteRecord"] = "connectorDataOperation.deleteRecordAsync";
|
|
553
|
-
ConnectorOperationName2["RetrieveRecord"] = "connectorDataOperation.retrieveRecordAsync";
|
|
554
|
-
ConnectorOperationName2["RetrieveMultipleRecords"] = "connectorDataOperation.retrieveMultipleRecordsAsync";
|
|
555
|
-
})(ConnectorOperationName || (ConnectorOperationName = {}));
|
|
556
|
-
|
|
557
|
-
function getErrorMessage(error) {
|
|
558
|
-
if (typeof error === "string") {
|
|
559
|
-
return error;
|
|
560
|
-
}
|
|
561
|
-
if (error instanceof Error || error instanceof PowerDataRuntimeError) {
|
|
562
|
-
return error.message || UnknownErrorMessage;
|
|
563
|
-
}
|
|
564
|
-
if (isOperationResult(error)) {
|
|
565
|
-
return error.error?.message || UnknownErrorMessage;
|
|
566
|
-
}
|
|
567
|
-
if (typeof error === "object") {
|
|
568
|
-
return JSON.stringify(error);
|
|
569
|
-
}
|
|
570
|
-
return UnknownErrorMessage;
|
|
571
|
-
}
|
|
572
|
-
function createErrorResponse(error, friendlyMessage) {
|
|
573
|
-
const message = getErrorMessage(error);
|
|
574
|
-
let data;
|
|
575
|
-
if (isOperationResult(error)) {
|
|
576
|
-
data = error.data;
|
|
577
|
-
}
|
|
578
|
-
const errorData = new Error(`${friendlyMessage}: ${message}`);
|
|
579
|
-
if (error instanceof Error) {
|
|
580
|
-
errorData.stack = error.stack;
|
|
581
|
-
}
|
|
582
|
-
return {
|
|
583
|
-
success: false,
|
|
584
|
-
error: errorData,
|
|
585
|
-
data
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
function parseHttpPluginError(error) {
|
|
589
|
-
let message = UnknownErrorMessage;
|
|
590
|
-
let response;
|
|
591
|
-
if (Array.isArray(error)) {
|
|
592
|
-
if (Array.isArray(error[0])) {
|
|
593
|
-
message = error[0][0] || UnknownErrorMessage;
|
|
594
|
-
response = error[0][2];
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
const status = response?.status;
|
|
598
|
-
const requestId = response?.headers?.[HeaderNames.RequestId];
|
|
599
|
-
return {
|
|
600
|
-
message,
|
|
601
|
-
status,
|
|
602
|
-
requestId
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
var DefaultDataOperationOrchestrator = class {
|
|
607
|
-
// Static identifiers for services and actions
|
|
608
|
-
// Used to identify specific services and actions within the PowerApps environment
|
|
609
|
-
constructor(_dataverseOperation, _connectorOperation, _connectionsService) {
|
|
610
|
-
__publicField(this, "_dataverseOperation");
|
|
611
|
-
__publicField(this, "_connectorOperation");
|
|
612
|
-
__publicField(this, "_connectionsService");
|
|
613
|
-
this._dataverseOperation = _dataverseOperation;
|
|
614
|
-
this._connectorOperation = _connectorOperation;
|
|
615
|
-
this._connectionsService = _connectionsService;
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Creates a new record in the specified data source.
|
|
619
|
-
* @param tableName - The name of the table.
|
|
620
|
-
* @param data - The record data to create.
|
|
621
|
-
* @returns A promise that resolves to the operation result.
|
|
622
|
-
* @throws DataOperationError if the operation fails.
|
|
623
|
-
*/
|
|
624
|
-
async createRecordAsync(tableName, data) {
|
|
625
|
-
try {
|
|
626
|
-
this._validateParams({ tableName, data });
|
|
627
|
-
const executor = await this._getExecutor(tableName);
|
|
628
|
-
return await executor.createRecordAsync(tableName, data);
|
|
629
|
-
} catch (error) {
|
|
630
|
-
return createErrorResponse(error, "Create record operation failed");
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Updates an existing record in the specified data source.
|
|
635
|
-
* @param tableName - The name of the table.
|
|
636
|
-
* @param id - The ID of the record to update.
|
|
637
|
-
* @param data - The updated record data.
|
|
638
|
-
* @returns A promise that resolves to the operation result.
|
|
639
|
-
* @throws DataOperationError if the operation fails.
|
|
640
|
-
*/
|
|
641
|
-
async updateRecordAsync(tableName, id, data) {
|
|
642
|
-
try {
|
|
643
|
-
this._validateParams({ tableName, id, data });
|
|
644
|
-
const executor = await this._getExecutor(tableName);
|
|
645
|
-
return await executor.updateRecordAsync(tableName, id, data);
|
|
646
|
-
} catch (error) {
|
|
647
|
-
return createErrorResponse(error, "Update record operation failed");
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Deletes a record from the specified data source.
|
|
652
|
-
* @param tableName - The name of the table.
|
|
653
|
-
* @param id - The ID of the record to delete.
|
|
654
|
-
* @returns A promise that resolves to the operation result.
|
|
655
|
-
* @throws DataOperationError if the operation fails.
|
|
656
|
-
*/
|
|
657
|
-
async deleteRecordAsync(tableName, id) {
|
|
658
|
-
try {
|
|
659
|
-
this._validateParams({ tableName, id });
|
|
660
|
-
const executor = await this._getExecutor(tableName);
|
|
661
|
-
return await executor.deleteRecordAsync(tableName, id);
|
|
662
|
-
} catch (error) {
|
|
663
|
-
return createErrorResponse(error, "Delete record operation failed");
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Retrieves a record from the specified data source.
|
|
668
|
-
* @param tableName - The name of the table.
|
|
669
|
-
* @param id - The ID of the record to retrieve.
|
|
670
|
-
* @param options - Optional operation options.
|
|
671
|
-
* @returns A promise that resolves to the operation result.
|
|
672
|
-
* @throws DataOperationError if the operation fails.
|
|
673
|
-
*/
|
|
674
|
-
async retrieveRecordAsync(tableName, id, options) {
|
|
675
|
-
try {
|
|
676
|
-
this._validateParams({ tableName, id });
|
|
677
|
-
const executor = await this._getExecutor(tableName);
|
|
678
|
-
this._validateOptions(options);
|
|
679
|
-
return await executor.retrieveRecordAsync(tableName, id, options);
|
|
680
|
-
} catch (error) {
|
|
681
|
-
return createErrorResponse(error, "Retrieve record operation failed");
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* Retrieves multiple records from the specified data source.
|
|
686
|
-
* @param tableName - The name of the table.
|
|
687
|
-
* @param options - Optional operation options.
|
|
688
|
-
* @returns A promise that resolves to the operation result.
|
|
689
|
-
* @throws DataOperationError if the operation fails.
|
|
690
|
-
*/
|
|
691
|
-
async retrieveMultipleRecordsAsync(tableName, options) {
|
|
692
|
-
try {
|
|
693
|
-
this._validateParams({ tableName });
|
|
694
|
-
const executor = await this._getExecutor(tableName);
|
|
695
|
-
this._validateOptions(options);
|
|
696
|
-
return await executor.retrieveMultipleRecordsAsync(tableName, options);
|
|
697
|
-
} catch (error) {
|
|
698
|
-
return createErrorResponse(error, "Retrieve multiple records operation failed");
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Executes a data operation on the specified data source.
|
|
703
|
-
* @param operation - The operation to execute
|
|
704
|
-
* @returns A promise that resolves to the operation result.
|
|
705
|
-
* @throws DataOperationError if the operation fails.
|
|
706
|
-
*/
|
|
707
|
-
async executeAsync(operation) {
|
|
708
|
-
try {
|
|
709
|
-
this._validateParams({ operation });
|
|
710
|
-
const executor = await this._getExecutor("", operation.connectorOperation ? DataSources.Connector : DataSources.Dataverse);
|
|
711
|
-
return await executor.executeAsync(operation);
|
|
712
|
-
} catch (error) {
|
|
713
|
-
return createErrorResponse(error, "Execute operation failed");
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
/**
|
|
717
|
-
* Retrieves the appropriate executor based on the data source.
|
|
718
|
-
* @param dataSource - The data source to retrieve the executor for.
|
|
719
|
-
* @returns The corresponding executor instance.
|
|
720
|
-
* @throws DataOperationError if the data source is invalid.
|
|
721
|
-
* // TODO: Add Dataverse support
|
|
722
|
-
*/
|
|
723
|
-
async _getExecutor(tableName, dataSource) {
|
|
724
|
-
const dataOperationExecutorOverride = getDataOperationExecutor();
|
|
725
|
-
if (dataOperationExecutorOverride) {
|
|
726
|
-
return dataOperationExecutorOverride;
|
|
727
|
-
}
|
|
728
|
-
const dataSourceType = dataSource || (await this._connectionsService.getDataSource(tableName)).dataSourceType;
|
|
729
|
-
switch (dataSourceType) {
|
|
730
|
-
case DataSources.Dataverse:
|
|
731
|
-
return this._dataverseOperation;
|
|
732
|
-
case DataSources.Connector:
|
|
733
|
-
return this._connectorOperation;
|
|
734
|
-
default:
|
|
735
|
-
return this._connectorOperation;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Validates the input parameters for data operations.
|
|
740
|
-
* @param params - The parameters to validate.
|
|
741
|
-
* @throws DataOperationError if validation fails.
|
|
742
|
-
*/
|
|
743
|
-
_validateParams(params) {
|
|
744
|
-
for (const [key, value] of Object.entries(params)) {
|
|
745
|
-
if (!value) {
|
|
746
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: ${key} is required`);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* Validates the operation options.
|
|
752
|
-
* @param options - The operation options to validate.
|
|
753
|
-
* @throws Error if validation fails.
|
|
754
|
-
*/
|
|
755
|
-
_validateOptions(options) {
|
|
756
|
-
if (!options) {
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
if (options.maxPageSize && typeof options.maxPageSize !== "number") {
|
|
760
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: maxPageSize must be a number`);
|
|
761
|
-
}
|
|
762
|
-
if (options.select) {
|
|
763
|
-
if (!Array.isArray(options.select)) {
|
|
764
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: select must be an array of strings`);
|
|
765
|
-
}
|
|
766
|
-
if (options.select.some((s) => typeof s !== "string" || s.trim() === "")) {
|
|
767
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: select must contain only non-empty strings`);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
if (options.filter && typeof options.filter !== "string") {
|
|
771
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: filter must be a string`);
|
|
772
|
-
}
|
|
773
|
-
if (options.orderBy) {
|
|
774
|
-
if (!Array.isArray(options.orderBy)) {
|
|
775
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: orderBy must be an array of strings`);
|
|
776
|
-
}
|
|
777
|
-
if (options.orderBy.some((s) => typeof s !== "string" || s.trim() === "")) {
|
|
778
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: orderBy must contain only non-empty strings`);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
if (options.top && typeof options.top !== "number") {
|
|
782
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: top must be a number`);
|
|
783
|
-
}
|
|
784
|
-
if (options.skip && typeof options.skip !== "number") {
|
|
785
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: skip must be a number`);
|
|
786
|
-
}
|
|
787
|
-
if (options.count && typeof options.count !== "boolean") {
|
|
788
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: count must be a boolean`);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
|
|
793
|
-
var RuntimeMetadataOperations = class {
|
|
794
|
-
// Static identifiers for services and actions
|
|
795
|
-
// Used to identify specific services and actions within the PowerApps environment
|
|
796
|
-
constructor(_clientProvider) {
|
|
797
|
-
__publicField(this, "_clientProvider");
|
|
798
|
-
this._clientProvider = _clientProvider;
|
|
799
|
-
}
|
|
800
|
-
async getConnections(context2) {
|
|
801
|
-
const client = await this._clientProvider.getMetadataClientAsync();
|
|
802
|
-
const response = await client.getAppConnectionConfigsAsync(context2);
|
|
803
|
-
return {
|
|
804
|
-
success: response.success,
|
|
805
|
-
data: response.data ? [response.data] : [],
|
|
806
|
-
error: response.error
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
async getConnectionApis(_connectionId, context2) {
|
|
810
|
-
const client = await this._clientProvider.getMetadataClientAsync();
|
|
811
|
-
const response = await client.getAppDataSourceConfigsAsync(context2);
|
|
812
|
-
return {
|
|
813
|
-
success: response.success,
|
|
814
|
-
data: response.data ? [response.data] : [],
|
|
815
|
-
error: response.error
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
function arrayBufferToBase64(buffer) {
|
|
821
|
-
return window.btoa(convertArrayBufferToString(buffer));
|
|
822
|
-
}
|
|
823
|
-
function convertArrayBufferToString(buf) {
|
|
824
|
-
if (buf.byteLength <= 65535) {
|
|
825
|
-
return String.fromCharCode(...new Uint8Array(buf));
|
|
826
|
-
}
|
|
827
|
-
let binary = "";
|
|
828
|
-
for (let i = 0, bytes = new Uint8Array(buf); i < bytes.byteLength; i++) {
|
|
829
|
-
binary += String.fromCharCode(bytes[i]);
|
|
830
|
-
}
|
|
831
|
-
return binary;
|
|
832
|
-
}
|
|
833
|
-
function strictEncode(str) {
|
|
834
|
-
return encodeURIComponent(str).replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
835
|
-
}
|
|
836
|
-
function extractDataverseUrlParts(url) {
|
|
837
|
-
const baseUrlMatch = url.match(/^(https?:\/\/[^/]+\/api\/data\/v9\.0)/);
|
|
838
|
-
const baseUrl = baseUrlMatch ? baseUrlMatch[1] : "";
|
|
839
|
-
const pathMatch = url.match(/\/api\/data\/v9\.0\/(.+)$/);
|
|
840
|
-
const encodedPath = pathMatch ? strictEncode(pathMatch[1]) : "";
|
|
841
|
-
return { baseUrl, encodedPath };
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
var _RuntimeDataClient = class _RuntimeDataClient {
|
|
845
|
-
// Constructor for RuntimeDataClient
|
|
846
|
-
// Accepts an IPowerOperationExecutor instance for executing operations
|
|
847
|
-
constructor(_powerOperationExecutor) {
|
|
848
|
-
__publicField(this, "_powerOperationExecutor");
|
|
849
|
-
this._powerOperationExecutor = _powerOperationExecutor;
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Creates a new instance of RuntimeDataClient
|
|
853
|
-
*/
|
|
854
|
-
static createInstanceAsync(powerOperationExecutor) {
|
|
855
|
-
return Promise.resolve(new _RuntimeDataClient(powerOperationExecutor));
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Creates data using POST method
|
|
859
|
-
* @param url - The URL for the request
|
|
860
|
-
* @param apiId - The API ID for authentication
|
|
861
|
-
* @param tableName - The name of the table to access
|
|
862
|
-
* @param body - The request body for the POST method
|
|
863
|
-
* @param operationName - Optional operation name for telemetry
|
|
864
|
-
* @return Promise resolving to the response data
|
|
865
|
-
* @throws Error if the request fails or the response is invalid
|
|
866
|
-
* @throws Error if the request body is invalid
|
|
867
|
-
*/
|
|
868
|
-
async createDataAsync(url, apiId, tableName, body, context2) {
|
|
869
|
-
try {
|
|
870
|
-
if (!body) {
|
|
871
|
-
throw new Error(`${DataOperationErrorMessages.InvalidRequest}: ${DataOperationErrorMessages.MissingRequestBody}`);
|
|
872
|
-
}
|
|
873
|
-
const config = {
|
|
874
|
-
url,
|
|
875
|
-
method: HttpMethod.POST,
|
|
876
|
-
apiId,
|
|
877
|
-
tableName,
|
|
878
|
-
body: JSON.stringify(body)
|
|
879
|
-
};
|
|
880
|
-
context2 = this._ensureContext(context2, "runtimeDataClient.createDataAsync");
|
|
881
|
-
return await this._executeRequest(config, context2);
|
|
882
|
-
} catch (error) {
|
|
883
|
-
if (isOperationResult(error)) {
|
|
884
|
-
return error;
|
|
885
|
-
} else {
|
|
886
|
-
return createErrorResponse(error, DataOperationErrorMessages.CreateFailed);
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* Updates data using PATCH method
|
|
892
|
-
* @param url - The URL for the request
|
|
893
|
-
* @param apiId - The API ID for authentication
|
|
894
|
-
* @param tableName - The name of the table to access
|
|
895
|
-
* @param body - The request body for the PATCH method
|
|
896
|
-
* @param operationName - Optional operation name for telemetry
|
|
897
|
-
* @return Promise resolving to the response data
|
|
898
|
-
* @throws Error if the request fails or the response is invalid
|
|
899
|
-
* @throws Error if the request body is invalid
|
|
900
|
-
*/
|
|
901
|
-
async updateDataAsync(url, apiId, tableName, body, context2) {
|
|
902
|
-
try {
|
|
903
|
-
if (!body) {
|
|
904
|
-
throw new Error(`${DataOperationErrorMessages.InvalidRequest}: ${DataOperationErrorMessages.MissingRequestBody}`);
|
|
905
|
-
}
|
|
906
|
-
const config = {
|
|
907
|
-
url,
|
|
908
|
-
method: HttpMethod.PATCH,
|
|
909
|
-
apiId,
|
|
910
|
-
tableName,
|
|
911
|
-
body: JSON.stringify(body)
|
|
912
|
-
};
|
|
913
|
-
context2 = this._ensureContext(context2, "runtimeDataClient.updateDataAsync");
|
|
914
|
-
return await this._executeRequest(config, context2);
|
|
915
|
-
} catch (error) {
|
|
916
|
-
if (isOperationResult(error)) {
|
|
917
|
-
return error;
|
|
918
|
-
} else {
|
|
919
|
-
return createErrorResponse(error, DataOperationErrorMessages.UpdateFailed);
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Deletes data using DELETE method
|
|
925
|
-
* @param url - The URL for the request
|
|
926
|
-
* @param connectionApi - The API ID for authentication
|
|
927
|
-
* @param serviceNamespace - The name of the service namespace
|
|
928
|
-
* @param operationName - Optional operation name for telemetry
|
|
929
|
-
* @return Promise resolving to the response data
|
|
930
|
-
* @throws Error if the request fails or the response is invalid
|
|
931
|
-
*/
|
|
932
|
-
async deleteDataAsync(url, connectionApi, serviceNamespace, context2) {
|
|
933
|
-
try {
|
|
934
|
-
const config = {
|
|
935
|
-
url,
|
|
936
|
-
method: HttpMethod.DELETE,
|
|
937
|
-
apiId: connectionApi,
|
|
938
|
-
tableName: serviceNamespace
|
|
939
|
-
};
|
|
940
|
-
context2 = this._ensureContext(context2, "runtimeDataClient.deleteDataAsync");
|
|
941
|
-
return await this._executeRequest(config, context2);
|
|
942
|
-
} catch (error) {
|
|
943
|
-
if (isOperationResult(error)) {
|
|
944
|
-
return error;
|
|
945
|
-
} else {
|
|
946
|
-
return createErrorResponse(error, DataOperationErrorMessages.DeleteFailed);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
/**
|
|
951
|
-
* Retrieves data using GET or POST method
|
|
952
|
-
* @param url - The URL for the request
|
|
953
|
-
* @param apiId - The API ID for authentication
|
|
954
|
-
* @param tableName - The name of the table to access
|
|
955
|
-
* @param method - The HTTP method
|
|
956
|
-
* @param body - Optional request body for POST method
|
|
957
|
-
* @param context - Optional operation context
|
|
958
|
-
* @param operationName - Optional operation name for telemetry
|
|
959
|
-
* @return Promise resolving to the response data
|
|
960
|
-
* @throws Error if the request fails or the response is invalid
|
|
961
|
-
*/
|
|
962
|
-
async retrieveDataAsync(url, apiId, tableName, method, headers, body, context2) {
|
|
963
|
-
try {
|
|
964
|
-
const config = {
|
|
965
|
-
url,
|
|
966
|
-
method,
|
|
967
|
-
apiId,
|
|
968
|
-
tableName,
|
|
969
|
-
headers,
|
|
970
|
-
body: body ? typeof body === "string" ? body : JSON.stringify(body) : void 0
|
|
971
|
-
};
|
|
972
|
-
context2 = this._ensureContext(context2, "runtimeDataClient.retrieveDataAsync");
|
|
973
|
-
return await this._executeRequest(config, context2);
|
|
974
|
-
} catch (error) {
|
|
975
|
-
if (isOperationResult(error)) {
|
|
976
|
-
return error;
|
|
977
|
-
} else {
|
|
978
|
-
return createErrorResponse(error, DataOperationErrorMessages.RetrieveFailed);
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
/**
|
|
983
|
-
* Gets an access token for the specified API.
|
|
984
|
-
* If the API is Dataverse, retrieves a dynamic resource token; otherwise, retrieves a standard appservice API token.
|
|
985
|
-
* @param apiId - The API ID for authentication
|
|
986
|
-
* @param datasetName - Optional dataset name for Dataverse
|
|
987
|
-
* @returns Promise resolving to the access token
|
|
988
|
-
* @throws Error if token acquisition fails
|
|
989
|
-
*/
|
|
990
|
-
async _getAccessToken(apiId, datasetName) {
|
|
991
|
-
try {
|
|
992
|
-
let result;
|
|
993
|
-
if (apiId === DataSources.Dataverse) {
|
|
994
|
-
result = await this._powerOperationExecutor.execute(_RuntimeDataClient.SERVICES.identityService, _RuntimeDataClient.ACTIONS.getDynamicToken, [datasetName]);
|
|
995
|
-
} else {
|
|
996
|
-
result = await this._powerOperationExecutor.execute(_RuntimeDataClient.SERVICES.identityService, _RuntimeDataClient.ACTIONS.getToken, [apiId]);
|
|
997
|
-
}
|
|
998
|
-
return result.data;
|
|
999
|
-
} catch (error) {
|
|
1000
|
-
throw new PowerDataRuntimeError(ErrorCodes.TokenAcquisitionFailed, getErrorMessage(error));
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
// Merge Prefer headers for Dataverse batch payloads
|
|
1004
|
-
_mergePreferHeaders(configHeaders, method) {
|
|
1005
|
-
let preferHeader = "";
|
|
1006
|
-
if (configHeaders?.Prefer) {
|
|
1007
|
-
preferHeader += configHeaders.Prefer;
|
|
1008
|
-
}
|
|
1009
|
-
if (method === HttpMethod.POST || method === HttpMethod.PATCH) {
|
|
1010
|
-
const defaultPrefer = "return=representation,odata.include-annotations=*";
|
|
1011
|
-
if (preferHeader) {
|
|
1012
|
-
if (!preferHeader.includes("return=representation")) {
|
|
1013
|
-
preferHeader += (preferHeader ? "," : "") + defaultPrefer;
|
|
1014
|
-
}
|
|
1015
|
-
} else {
|
|
1016
|
-
preferHeader = defaultPrefer;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
return preferHeader;
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Creates headers for the HTTP request.
|
|
1023
|
-
* Combines default headers with any custom headers provided in the config.
|
|
1024
|
-
* Custom headers are optional and take precedence over default headers.
|
|
1025
|
-
* @param token - The access token for authentication
|
|
1026
|
-
* @param config - The HTTP request configuration
|
|
1027
|
-
* @return The headers for the request
|
|
1028
|
-
* @throws Error if header creation fails
|
|
1029
|
-
*/
|
|
1030
|
-
_createHeaders(token, config, context2) {
|
|
1031
|
-
const baseHeaders = {
|
|
1032
|
-
Accept: "application/json",
|
|
1033
|
-
"x-ms-protocol-semantics": "cdp",
|
|
1034
|
-
ServiceNamespace: config.tableName,
|
|
1035
|
-
Authorization: `paauth ${token}`,
|
|
1036
|
-
"x-ms-pa-client-custom-headers-options": '{"addCustomHeaders":true}',
|
|
1037
|
-
"x-ms-enable-selects": "true",
|
|
1038
|
-
"x-ms-pa-client-telemetry-options": `paclient-telemetry {"operationName":"${context2?.operationName ?? "runtimeDataClient.executeRequest"}"}`,
|
|
1039
|
-
"x-ms-pa-client-telemetry-additional-data": `{"apiId":"${config.apiId}"}`
|
|
1040
|
-
};
|
|
1041
|
-
if (config.apiId === DataSources.Dataverse) {
|
|
1042
|
-
baseHeaders["x-ms-protocol-semantics"] = DataSources.Dataverse;
|
|
1043
|
-
baseHeaders.Authorization = `dynamicauth ${token}`;
|
|
1044
|
-
const { baseUrl, encodedPath } = extractDataverseUrlParts(config.url);
|
|
1045
|
-
const batchId = context2?.batchId || "";
|
|
1046
|
-
const preferHeader = this._mergePreferHeaders(config.headers, config.method);
|
|
1047
|
-
baseHeaders.BatchInfo = JSON.stringify({
|
|
1048
|
-
baseUrl,
|
|
1049
|
-
encodedPath,
|
|
1050
|
-
headers: {
|
|
1051
|
-
Accept: "application/json",
|
|
1052
|
-
...preferHeader ? { Prefer: preferHeader } : {},
|
|
1053
|
-
...config.method === HttpMethod.POST || config.method === HttpMethod.PATCH ? { "Content-Type": "application/json" } : {}
|
|
1054
|
-
},
|
|
1055
|
-
batchId
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
if (config.headers) {
|
|
1059
|
-
return { ...baseHeaders, ...config.headers };
|
|
1060
|
-
}
|
|
1061
|
-
return baseHeaders;
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Executes an HTTP request with the given configuration
|
|
1065
|
-
* @param config - The HTTP request configuration
|
|
1066
|
-
* @param context - Optional operation context
|
|
1067
|
-
* @return Promise resolving to the response data
|
|
1068
|
-
* @throws Error if the request fails or the response is invalid
|
|
1069
|
-
* @throws Error if the response content type is invalid
|
|
1070
|
-
*/
|
|
1071
|
-
async _executeRequest(config, context2) {
|
|
1072
|
-
const token = await this._getAccessToken(config.apiId, context2?.datasetName);
|
|
1073
|
-
const headers = this._createHeaders(token, config, context2);
|
|
1074
|
-
const requestBody = config.body ? new Blob([config.body], { type: "application/json" }) : "";
|
|
1075
|
-
let result;
|
|
1076
|
-
try {
|
|
1077
|
-
result = await this._powerOperationExecutor.execute(_RuntimeDataClient.SERVICES.dataClient, _RuntimeDataClient.ACTIONS.sendHttp, [
|
|
1078
|
-
{
|
|
1079
|
-
url: config.url,
|
|
1080
|
-
method: config.method,
|
|
1081
|
-
requestSource: _RuntimeDataClient.REQUEST_SOURCE,
|
|
1082
|
-
allowSessionStorage: true,
|
|
1083
|
-
returnDirectResponse: true,
|
|
1084
|
-
headers
|
|
1085
|
-
},
|
|
1086
|
-
requestBody,
|
|
1087
|
-
"arraybuffer"
|
|
1088
|
-
]);
|
|
1089
|
-
} catch (error) {
|
|
1090
|
-
return {
|
|
1091
|
-
success: false,
|
|
1092
|
-
error: parseHttpPluginError(error),
|
|
1093
|
-
data: void 0
|
|
1094
|
-
};
|
|
1095
|
-
}
|
|
1096
|
-
const responseData = result.data;
|
|
1097
|
-
const responseHeaders = responseData[0].headers;
|
|
1098
|
-
const contentType = responseHeaders["Content-Type"];
|
|
1099
|
-
if (!contentType) {
|
|
1100
|
-
return {
|
|
1101
|
-
success: true,
|
|
1102
|
-
data: void 0
|
|
1103
|
-
};
|
|
1104
|
-
} else if (contentType.indexOf("application/json") !== -1) {
|
|
1105
|
-
const data = result.data[1];
|
|
1106
|
-
let text = this._decodeArrayBuffer(data);
|
|
1107
|
-
if (!text) {
|
|
1108
|
-
text = "{}";
|
|
1109
|
-
}
|
|
1110
|
-
const parsedResult = JSON.parse(text);
|
|
1111
|
-
if (context2?.isDataVerseOperation || this._isDataverseCall(config.url)) {
|
|
1112
|
-
return {
|
|
1113
|
-
success: true,
|
|
1114
|
-
data: parsedResult
|
|
1115
|
-
};
|
|
1116
|
-
} else if (!context2?.isExecuteAsync && "value" in parsedResult && Array.isArray(parsedResult.value)) {
|
|
1117
|
-
return {
|
|
1118
|
-
success: true,
|
|
1119
|
-
data: parsedResult.value,
|
|
1120
|
-
count: parsedResult["@odata.count"]
|
|
1121
|
-
};
|
|
1122
|
-
} else {
|
|
1123
|
-
return {
|
|
1124
|
-
success: true,
|
|
1125
|
-
data: parsedResult
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
} else if (contentType.indexOf("image/") !== -1) {
|
|
1129
|
-
const buffer = result.data[1];
|
|
1130
|
-
if (buffer instanceof ArrayBuffer) {
|
|
1131
|
-
const value = arrayBufferToBase64(buffer);
|
|
1132
|
-
return {
|
|
1133
|
-
success: true,
|
|
1134
|
-
data: value
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
return {
|
|
1138
|
-
success: true,
|
|
1139
|
-
data: buffer
|
|
1140
|
-
};
|
|
1141
|
-
} else {
|
|
1142
|
-
const buffer = result.data[1];
|
|
1143
|
-
if (buffer instanceof ArrayBuffer) {
|
|
1144
|
-
const value = convertArrayBufferToString(buffer);
|
|
1145
|
-
const status = responseData[0].status;
|
|
1146
|
-
const responseType = context2?.responseInfo?.[status];
|
|
1147
|
-
if (responseType) {
|
|
1148
|
-
let parsedValue;
|
|
1149
|
-
try {
|
|
1150
|
-
parsedValue = JSON.parse(value);
|
|
1151
|
-
} catch (err) {
|
|
1152
|
-
return {
|
|
1153
|
-
success: false,
|
|
1154
|
-
data: void 0,
|
|
1155
|
-
error: new Error(DataOperationErrorMessages.InvalidResponse)
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
if (responseType.type === "array" && !Array.isArray(parsedValue)) {
|
|
1159
|
-
return {
|
|
1160
|
-
success: false,
|
|
1161
|
-
data: void 0,
|
|
1162
|
-
error: new Error(DataOperationErrorMessages.InvalidResponse)
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
if (responseType.type === "object" && (typeof parsedValue !== "object" || Array.isArray(parsedValue) || parsedValue === null)) {
|
|
1166
|
-
return {
|
|
1167
|
-
success: false,
|
|
1168
|
-
data: void 0,
|
|
1169
|
-
error: new Error(DataOperationErrorMessages.InvalidResponse)
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
return {
|
|
1173
|
-
success: true,
|
|
1174
|
-
data: parsedValue
|
|
1175
|
-
};
|
|
1176
|
-
} else {
|
|
1177
|
-
return {
|
|
1178
|
-
success: true,
|
|
1179
|
-
data: value
|
|
1180
|
-
};
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
return {
|
|
1184
|
-
success: false,
|
|
1185
|
-
data: responseData,
|
|
1186
|
-
error: new Error(DataOperationErrorMessages.InvalidResponse)
|
|
1187
|
-
};
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
_ensureContext(context2, defaultOperationName) {
|
|
1191
|
-
if (!context2) {
|
|
1192
|
-
context2 = {};
|
|
1193
|
-
}
|
|
1194
|
-
if (!context2.operationName) {
|
|
1195
|
-
context2.operationName = defaultOperationName;
|
|
1196
|
-
}
|
|
1197
|
-
return context2;
|
|
1198
|
-
}
|
|
1199
|
-
/**
|
|
1200
|
-
* Checks if the given URL is a Dataverse API call
|
|
1201
|
-
* @param url - The URL to check
|
|
1202
|
-
* @returns True if the URL is a Dataverse API call, false otherwise
|
|
1203
|
-
*/
|
|
1204
|
-
_isDataverseCall(url) {
|
|
1205
|
-
if (!url) {
|
|
1206
|
-
return false;
|
|
1207
|
-
}
|
|
1208
|
-
const urlLower = decodeURIComponent(url).toLowerCase();
|
|
1209
|
-
return urlLower.includes("/api/data/") && !urlLower.includes("/apim");
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* Decodes ArrayBuffer to string, handling both browser and Node.js environments
|
|
1213
|
-
* @param buffer - The ArrayBuffer to decode
|
|
1214
|
-
* @returns The decoded string
|
|
1215
|
-
*/
|
|
1216
|
-
_decodeArrayBuffer(buffer) {
|
|
1217
|
-
if (typeof TextDecoder !== "undefined") {
|
|
1218
|
-
return new TextDecoder().decode(buffer);
|
|
1219
|
-
}
|
|
1220
|
-
const uint8Array = new Uint8Array(buffer);
|
|
1221
|
-
const results = [];
|
|
1222
|
-
const chunkSize = 8192;
|
|
1223
|
-
for (let i = 0; i < uint8Array.length; i += chunkSize) {
|
|
1224
|
-
const chunk = uint8Array.subarray(i, Math.min(i + chunkSize, uint8Array.length));
|
|
1225
|
-
results.push(String.fromCharCode.apply(null, Array.from(chunk)));
|
|
1226
|
-
}
|
|
1227
|
-
try {
|
|
1228
|
-
return results.join("");
|
|
1229
|
-
} catch {
|
|
1230
|
-
return results.join("");
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
// Static identifiers for services
|
|
1235
|
-
// Used to identify specific services within the PowerApps environment
|
|
1236
|
-
__publicField(_RuntimeDataClient, "SERVICES", {
|
|
1237
|
-
dataClient: "AppHttpClientPlugin",
|
|
1238
|
-
identityService: "AppIdentityServicePlugin"
|
|
1239
|
-
});
|
|
1240
|
-
// Static identifiers for service actions
|
|
1241
|
-
// Used to identify specific actions within the service
|
|
1242
|
-
// These actions are used to send HTTP requests and get access tokens
|
|
1243
|
-
__publicField(_RuntimeDataClient, "ACTIONS", {
|
|
1244
|
-
sendHttp: "sendHttpAsync",
|
|
1245
|
-
getToken: "getAppAccessTokenAsync",
|
|
1246
|
-
getDynamicToken: "getAppDynamicResourceAccessTokenAsync"
|
|
1247
|
-
});
|
|
1248
|
-
// Request source identifier for telemetry
|
|
1249
|
-
// Used to identify the source of the request in telemetry data
|
|
1250
|
-
__publicField(_RuntimeDataClient, "REQUEST_SOURCE", "PublishedApp");
|
|
1251
|
-
var RuntimeDataClient = _RuntimeDataClient;
|
|
1252
|
-
|
|
1253
|
-
var _RuntimeMetadataClient = class _RuntimeMetadataClient {
|
|
1254
|
-
// Private member for the PowerOperationExecutor
|
|
1255
|
-
// The PowerOperationExecutor is used to execute operations on the clients
|
|
1256
|
-
constructor(_powerOperationExecutor) {
|
|
1257
|
-
__publicField(this, "_powerOperationExecutor");
|
|
1258
|
-
this._powerOperationExecutor = _powerOperationExecutor;
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Creates a new instance of RuntimeMetadataClient
|
|
1262
|
-
* @param powerOperationExecutor - The powerOperationExecutor instance
|
|
1263
|
-
* @returns Promise resolving to IRuntimeMetadataClient
|
|
1264
|
-
*/
|
|
1265
|
-
static createInstanceAsync(powerOperationExecutor) {
|
|
1266
|
-
return Promise.resolve(new _RuntimeMetadataClient(powerOperationExecutor));
|
|
1267
|
-
}
|
|
1268
|
-
/**
|
|
1269
|
-
* Fetches app connection configurations
|
|
1270
|
-
* @returns Promise resolving to connection reference details
|
|
1271
|
-
* @throws Error if the operation fails
|
|
1272
|
-
*/
|
|
1273
|
-
async getAppConnectionConfigsAsync() {
|
|
1274
|
-
try {
|
|
1275
|
-
const config = {
|
|
1276
|
-
service: _RuntimeMetadataClient.SERVICES.powerAppsClient,
|
|
1277
|
-
action: _RuntimeMetadataClient.ACTIONS.getConnectionConfigs,
|
|
1278
|
-
params: []
|
|
1279
|
-
};
|
|
1280
|
-
const result = await this._executeOperation(config);
|
|
1281
|
-
return { success: true, data: result };
|
|
1282
|
-
} catch (error) {
|
|
1283
|
-
throw new PowerDataRuntimeError(ErrorCodes.ConnectionConfigFetchFailed, getErrorMessage(error));
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
/**
|
|
1287
|
-
* Fetches app data source configurations
|
|
1288
|
-
* @returns Promise resolving to connection reference details
|
|
1289
|
-
* @throws Error if the operation fails
|
|
1290
|
-
*/
|
|
1291
|
-
async getAppDataSourceConfigsAsync() {
|
|
1292
|
-
try {
|
|
1293
|
-
const config = {
|
|
1294
|
-
service: _RuntimeMetadataClient.SERVICES.powerAppsClient,
|
|
1295
|
-
action: _RuntimeMetadataClient.ACTIONS.getDataSourceConfigs,
|
|
1296
|
-
params: []
|
|
1297
|
-
};
|
|
1298
|
-
const result = await this._executeOperation(config);
|
|
1299
|
-
return { success: true, data: result };
|
|
1300
|
-
} catch (error) {
|
|
1301
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceConfigFetchFailed, getErrorMessage(error));
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Executes a metadata operation with the given configuration
|
|
1306
|
-
* @param config - The operation configuration
|
|
1307
|
-
* @returns Promise resolving to the operation result
|
|
1308
|
-
* @throws Error if the operation fails
|
|
1309
|
-
*/
|
|
1310
|
-
async _executeOperation(config) {
|
|
1311
|
-
try {
|
|
1312
|
-
const result = await this._powerOperationExecutor.execute(config.service, config.action, config.params || []);
|
|
1313
|
-
const lowerCaseResult = Object.keys(result.data).reduce((acc, key) => {
|
|
1314
|
-
acc[key.toLowerCase()] = (result.data ?? {})[key];
|
|
1315
|
-
return acc;
|
|
1316
|
-
}, {});
|
|
1317
|
-
return lowerCaseResult;
|
|
1318
|
-
} catch {
|
|
1319
|
-
throw new PowerDataRuntimeError(ErrorCodes.InvalidMetadataResponse);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
};
|
|
1323
|
-
// Static identifiers for services and actions
|
|
1324
|
-
// Used to identify specific services and actions within the PowerApps environment
|
|
1325
|
-
// These identifiers are used to execute operations through the PowerOperationExecutor
|
|
1326
|
-
// The services provide the functionality for the operations
|
|
1327
|
-
__publicField(_RuntimeMetadataClient, "SERVICES", {
|
|
1328
|
-
powerAppsClient: "AppPowerAppsClientPlugin"
|
|
1329
|
-
});
|
|
1330
|
-
// The actions define the specific operations to be performed
|
|
1331
|
-
__publicField(_RuntimeMetadataClient, "ACTIONS", {
|
|
1332
|
-
getConnectionConfigs: "loadAppConnectionsAsync_v2",
|
|
1333
|
-
getDataSourceConfigs: "getAppCdsDataSourceConfigsAsync"
|
|
1334
|
-
});
|
|
1335
|
-
var RuntimeMetadataClient = _RuntimeMetadataClient;
|
|
1336
|
-
|
|
1337
|
-
var RuntimeClientProvider = class {
|
|
1338
|
-
// Constructor for RuntimeClientProvider
|
|
1339
|
-
// Accepts an optional IPowerOperationExecutor instance for executing operations
|
|
1340
|
-
// If not provided, uses the default PowerOperationExecutor instance
|
|
1341
|
-
constructor(powerOperationExecutor) {
|
|
1342
|
-
// Private members for data and metadata clients
|
|
1343
|
-
// The data client is responsible for handling data operations
|
|
1344
|
-
__publicField(this, "_dataClient");
|
|
1345
|
-
// The metadata client is responsible for handling metadata operations
|
|
1346
|
-
__publicField(this, "_metadataClient");
|
|
1347
|
-
// The operation executor is used to execute operations on the clients
|
|
1348
|
-
// It is an instance of IPowerOperationExecutor, which provides the necessary methods for executing operations
|
|
1349
|
-
__publicField(this, "_operationExecutor");
|
|
1350
|
-
this._operationExecutor = powerOperationExecutor;
|
|
1351
|
-
}
|
|
1352
|
-
/**
|
|
1353
|
-
* Gets or initializes the data client
|
|
1354
|
-
* @throws Error if client initialization fails
|
|
1355
|
-
* @returns Promise resolving to IRuntimeDataClient
|
|
1356
|
-
*/
|
|
1357
|
-
async getDataClientAsync() {
|
|
1358
|
-
try {
|
|
1359
|
-
if (!this._dataClient) {
|
|
1360
|
-
this._dataClient = await this._initializeDataClient();
|
|
1361
|
-
}
|
|
1362
|
-
if (!this._dataClient) {
|
|
1363
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientNotInitialized);
|
|
1364
|
-
}
|
|
1365
|
-
return this._dataClient;
|
|
1366
|
-
} catch (error) {
|
|
1367
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientInitFailed, getErrorMessage(error));
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
/**
|
|
1371
|
-
* Gets or initializes the metadata client
|
|
1372
|
-
* @throws Error if client initialization fails
|
|
1373
|
-
* @returns Promise resolving to IRuntimeMetadataClient
|
|
1374
|
-
*/
|
|
1375
|
-
async getMetadataClientAsync() {
|
|
1376
|
-
try {
|
|
1377
|
-
if (!this._metadataClient) {
|
|
1378
|
-
this._metadataClient = await this._initializeMetadataClient();
|
|
1379
|
-
}
|
|
1380
|
-
if (!this._metadataClient) {
|
|
1381
|
-
throw new PowerDataRuntimeError(ErrorCodes.MetadataClientNotInitialized);
|
|
1382
|
-
}
|
|
1383
|
-
return this._metadataClient;
|
|
1384
|
-
} catch (error) {
|
|
1385
|
-
throw new PowerDataRuntimeError(ErrorCodes.MetadataClientInitFailed, getErrorMessage(error));
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* Initializes the data client
|
|
1390
|
-
* @returns Promise resolving to IRuntimeDataClient
|
|
1391
|
-
*/
|
|
1392
|
-
async _initializeDataClient() {
|
|
1393
|
-
return RuntimeDataClient.createInstanceAsync(this._operationExecutor);
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* Initializes the metadata client
|
|
1397
|
-
* @returns Promise resolving to IRuntimeMetadataClient
|
|
1398
|
-
*/
|
|
1399
|
-
async _initializeMetadataClient() {
|
|
1400
|
-
return RuntimeMetadataClient.createInstanceAsync(this._operationExecutor);
|
|
1401
|
-
}
|
|
1402
|
-
/**
|
|
1403
|
-
* Resets both clients, forcing re-initialization on next use
|
|
1404
|
-
* Useful for testing or recovering from error states
|
|
1405
|
-
*/
|
|
1406
|
-
reset() {
|
|
1407
|
-
this._dataClient = void 0;
|
|
1408
|
-
this._metadataClient = void 0;
|
|
1409
|
-
}
|
|
1410
|
-
};
|
|
1411
|
-
|
|
1412
|
-
function convertOptionsToQueryString(options) {
|
|
1413
|
-
if (!options) {
|
|
1414
|
-
return "";
|
|
1415
|
-
}
|
|
1416
|
-
const parts = [];
|
|
1417
|
-
if (options.select && options.select.length > 0) {
|
|
1418
|
-
parts.push(`$select=${encodeURIComponent(options.select.map((s) => s.trim().replace(/%20/g, "+").replace(/'/g, "%27")).join(","))}`);
|
|
1419
|
-
}
|
|
1420
|
-
if (options.filter) {
|
|
1421
|
-
const encodedFilter = encodeURIComponent(options.filter.trim()).replace(/%20/g, "+").replace(/'/g, "%27");
|
|
1422
|
-
parts.push(`$filter=${encodedFilter}`);
|
|
1423
|
-
}
|
|
1424
|
-
if (options.orderBy && options.orderBy.length > 0) {
|
|
1425
|
-
parts.push(`$orderby=${encodeURIComponent(options.orderBy.map((s) => s.trim().replace(/%20/g, "+").replace(/'/g, "%27")).join(","))}`);
|
|
1426
|
-
}
|
|
1427
|
-
if (options.top !== void 0 && options.top !== null) {
|
|
1428
|
-
parts.push(`$top=${options.top}`);
|
|
1429
|
-
}
|
|
1430
|
-
if (options.skip !== void 0 && options.skip !== null) {
|
|
1431
|
-
parts.push(`$skip=${options.skip}`);
|
|
1432
|
-
}
|
|
1433
|
-
if (options.count !== void 0 && options.count !== null) {
|
|
1434
|
-
parts.push(`$count=${options.count}`);
|
|
1435
|
-
}
|
|
1436
|
-
if (options.skipToken && options.skipToken.trim() !== "") {
|
|
1437
|
-
parts.push(`$skiptoken=${encodeURIComponent(options.skipToken.trim())}`);
|
|
1438
|
-
}
|
|
1439
|
-
return parts.length ? `?${parts.join("&")}` : "";
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
var ODATA_NEXT_LINK = "@odata.nextLink";
|
|
1443
|
-
var DataverseDataOperationExecutor = class {
|
|
1444
|
-
constructor(clientProvider) {
|
|
1445
|
-
// Static identifiers for services and actions
|
|
1446
|
-
// Used to identify specific services and actions within the PowerApps environment
|
|
1447
|
-
__publicField(this, "_clientProvider");
|
|
1448
|
-
__publicField(this, "_databaseReferences");
|
|
1449
|
-
this._clientProvider = clientProvider;
|
|
1450
|
-
}
|
|
1451
|
-
/**
|
|
1452
|
-
* Creates a new record in Dataverse
|
|
1453
|
-
* @param tableName - The name of the table
|
|
1454
|
-
* @param data - The record data to create
|
|
1455
|
-
* @returns Promise resolving to operation result
|
|
1456
|
-
*/
|
|
1457
|
-
async createRecordAsync(tableName, data) {
|
|
1458
|
-
return this._executeNativeDataverseOperation(tableName, (dataSourceInfo, tblName) => this._getDataverseRequestUrl(dataSourceInfo, tblName), async (dataClient, requestUrl, dataSourceInfo) => {
|
|
1459
|
-
const dataverseResponse = await dataClient.createDataAsync(
|
|
1460
|
-
requestUrl,
|
|
1461
|
-
DataSources.Dataverse,
|
|
1462
|
-
// Use environment name for Dataverse authentication
|
|
1463
|
-
tableName,
|
|
1464
|
-
data,
|
|
1465
|
-
{
|
|
1466
|
-
operationName: DataverseOperationName.CreateRecord,
|
|
1467
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1468
|
-
isDataVerseOperation: true
|
|
1469
|
-
}
|
|
1470
|
-
);
|
|
1471
|
-
const returnValue = {
|
|
1472
|
-
success: dataverseResponse.success,
|
|
1473
|
-
data: dataverseResponse.data,
|
|
1474
|
-
error: dataverseResponse.error
|
|
1475
|
-
};
|
|
1476
|
-
return returnValue;
|
|
1477
|
-
}, DataOperationErrorMessages.CreateFailed);
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* Updates an existing record in Dataverse
|
|
1481
|
-
* @param tableName - The name of the table
|
|
1482
|
-
* @param id - The record identifier
|
|
1483
|
-
* @param data - The updated record data
|
|
1484
|
-
* @returns Promise resolving to operation result
|
|
1485
|
-
*/
|
|
1486
|
-
async updateRecordAsync(tableName, id, data) {
|
|
1487
|
-
return this._executeNativeDataverseOperation(tableName, (dataSourceInfo, tblName) => this._getDataverseRequestUrl(dataSourceInfo, tblName, `(${id})`), async (dataClient, requestUrl, dataSourceInfo) => {
|
|
1488
|
-
const dataverseResponse = await dataClient.updateDataAsync(requestUrl, DataSources.Dataverse, tableName, data, {
|
|
1489
|
-
operationName: DataverseOperationName.UpdateRecord,
|
|
1490
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1491
|
-
isDataVerseOperation: true
|
|
1492
|
-
});
|
|
1493
|
-
const returnValue = {
|
|
1494
|
-
success: dataverseResponse.success,
|
|
1495
|
-
data: dataverseResponse.data,
|
|
1496
|
-
error: dataverseResponse.error
|
|
1497
|
-
};
|
|
1498
|
-
return returnValue;
|
|
1499
|
-
}, DataOperationErrorMessages.UpdateFailed);
|
|
1500
|
-
}
|
|
1501
|
-
/**
|
|
1502
|
-
* Deletes a record from Dataverse
|
|
1503
|
-
* @param tableName - The name of the table
|
|
1504
|
-
* @param id - The record identifier
|
|
1505
|
-
* @returns Promise resolving to operation result
|
|
1506
|
-
*/
|
|
1507
|
-
async deleteRecordAsync(tableName, id) {
|
|
1508
|
-
return this._executeNativeDataverseOperation(tableName, (dataSourceInfo, tblName) => this._getDataverseRequestUrl(dataSourceInfo, tblName, `(${id})`), async (dataClient, requestUrl, dataSourceInfo) => {
|
|
1509
|
-
const dataverseResponse = await dataClient.deleteDataAsync(requestUrl, DataSources.Dataverse, tableName, {
|
|
1510
|
-
operationName: DataverseOperationName.DeleteRecord,
|
|
1511
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1512
|
-
isDataVerseOperation: true
|
|
1513
|
-
});
|
|
1514
|
-
const returnValue = {
|
|
1515
|
-
success: dataverseResponse.success,
|
|
1516
|
-
data: dataverseResponse.data,
|
|
1517
|
-
error: dataverseResponse.error
|
|
1518
|
-
};
|
|
1519
|
-
return returnValue;
|
|
1520
|
-
}, DataOperationErrorMessages.DeleteFailed);
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Retrieves a single record from Dataverse
|
|
1524
|
-
* @param tableName - The name of the table
|
|
1525
|
-
* @param id - The record identifier
|
|
1526
|
-
* @param options - The retrieval options
|
|
1527
|
-
* @returns Promise resolving to operation result
|
|
1528
|
-
*/
|
|
1529
|
-
async retrieveRecordAsync(tableName, id, options) {
|
|
1530
|
-
const { maxPageSize = 500, ...rest } = options || {};
|
|
1531
|
-
const optionsString = convertOptionsToQueryString(rest);
|
|
1532
|
-
const headers = { Prefer: `odata.maxpagesize=${maxPageSize},odata.include-annotations=*` };
|
|
1533
|
-
return this._executeNativeDataverseOperation(tableName, (dataSourceInfo, tblName) => this._getDataverseRequestUrl(dataSourceInfo, tblName, `(${id})${optionsString}`), async (dataClient, requestUrl, dataSourceInfo) => {
|
|
1534
|
-
const dataverseResponse = await dataClient.retrieveDataAsync(
|
|
1535
|
-
requestUrl,
|
|
1536
|
-
DataSources.Dataverse,
|
|
1537
|
-
tableName,
|
|
1538
|
-
HttpMethod.GET,
|
|
1539
|
-
headers,
|
|
1540
|
-
void 0,
|
|
1541
|
-
// No body for GET requests
|
|
1542
|
-
{
|
|
1543
|
-
operationName: DataverseOperationName.RetrieveRecord,
|
|
1544
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1545
|
-
isDataVerseOperation: true
|
|
1546
|
-
}
|
|
1547
|
-
);
|
|
1548
|
-
const returnValue = {
|
|
1549
|
-
success: dataverseResponse.success,
|
|
1550
|
-
data: dataverseResponse.data,
|
|
1551
|
-
error: dataverseResponse.error
|
|
1552
|
-
};
|
|
1553
|
-
return returnValue;
|
|
1554
|
-
}, DataOperationErrorMessages.RetrieveFailed);
|
|
1555
|
-
}
|
|
1556
|
-
/**
|
|
1557
|
-
* Retrieves multiple records from Dataverse
|
|
1558
|
-
* @param tableName - The name of the table
|
|
1559
|
-
* @param options - The retrieval options
|
|
1560
|
-
* @param maxPageSize - Optional maximum page size
|
|
1561
|
-
* @returns Promise resolving to operation result
|
|
1562
|
-
*/
|
|
1563
|
-
async retrieveMultipleRecordsAsync(tableName, options) {
|
|
1564
|
-
const { maxPageSize = 500, ...rest } = options || {};
|
|
1565
|
-
const optionsString = convertOptionsToQueryString(rest);
|
|
1566
|
-
const headers = { Prefer: `odata.maxpagesize=${maxPageSize},odata.include-annotations=*` };
|
|
1567
|
-
return this._executeNativeDataverseOperation(tableName, (dataSourceInfo, tblName) => this._getDataverseRequestUrl(dataSourceInfo, tblName, optionsString), async (dataClient, requestUrl, dataSourceInfo) => {
|
|
1568
|
-
const dataverseResponse = await dataClient.retrieveDataAsync(
|
|
1569
|
-
requestUrl,
|
|
1570
|
-
DataSources.Dataverse,
|
|
1571
|
-
tableName,
|
|
1572
|
-
HttpMethod.GET,
|
|
1573
|
-
headers,
|
|
1574
|
-
void 0,
|
|
1575
|
-
// No body for GET requests
|
|
1576
|
-
{
|
|
1577
|
-
operationName: DataverseOperationName.RetrieveMultipleRecords,
|
|
1578
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1579
|
-
isDataVerseOperation: true
|
|
1580
|
-
}
|
|
1581
|
-
);
|
|
1582
|
-
const returnValue = {
|
|
1583
|
-
success: dataverseResponse.success,
|
|
1584
|
-
data: dataverseResponse?.data?.value || [],
|
|
1585
|
-
skipToken: extractSkipToken(dataverseResponse?.data?.[ODATA_NEXT_LINK]),
|
|
1586
|
-
error: dataverseResponse.error
|
|
1587
|
-
};
|
|
1588
|
-
return returnValue;
|
|
1589
|
-
}, DataOperationErrorMessages.RetrieveMultipleFailed);
|
|
1590
|
-
}
|
|
1591
|
-
/**
|
|
1592
|
-
* Executes a custom Dataverse operation
|
|
1593
|
-
* @param operation - The operation to execute
|
|
1594
|
-
* @returns Promise resolving to operation result
|
|
1595
|
-
*/
|
|
1596
|
-
async executeAsync(operation) {
|
|
1597
|
-
const { dataverseRequest } = operation;
|
|
1598
|
-
if (!dataverseRequest) {
|
|
1599
|
-
return {
|
|
1600
|
-
success: false,
|
|
1601
|
-
data: null,
|
|
1602
|
-
error: { message: "Dataverse request details are required for Dataverse operations." }
|
|
1603
|
-
};
|
|
1604
|
-
}
|
|
1605
|
-
const { action, parameters } = dataverseRequest;
|
|
1606
|
-
switch (action) {
|
|
1607
|
-
// Future custom actions can be handled here
|
|
1608
|
-
case "getEntityMetadata":
|
|
1609
|
-
const { tableName, options } = parameters;
|
|
1610
|
-
if (!tableName) {
|
|
1611
|
-
return {
|
|
1612
|
-
success: false,
|
|
1613
|
-
data: null,
|
|
1614
|
-
error: { message: "Table name is required for getEntityMetadata action." }
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
|
-
return this._getEntityMetadata(tableName, options ?? {});
|
|
1618
|
-
default:
|
|
1619
|
-
Log.trackEvent("DataverseDataOperation.UnsupportedAction", {
|
|
1620
|
-
message: `Unsupported Dataverse action: ${action}`
|
|
1621
|
-
});
|
|
1622
|
-
return {
|
|
1623
|
-
success: false,
|
|
1624
|
-
data: null,
|
|
1625
|
-
error: { message: `Unsupported Dataverse action: "${action}"` }
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
async _getEntityMetadata(tableName, options) {
|
|
1630
|
-
const client = await this._getDataClient();
|
|
1631
|
-
const dataSourceInfo = await this._getDataverseDataSourceInfo(tableName);
|
|
1632
|
-
const url = this._generateMetadataRequestUrl(dataSourceInfo, options);
|
|
1633
|
-
return client.retrieveDataAsync(url, DataSources.Dataverse, "EntityDefinitions", HttpMethod.GET, {
|
|
1634
|
-
Consistency: "Strong"
|
|
1635
|
-
// Force CDS to return latest metadata
|
|
1636
|
-
}, void 0, {
|
|
1637
|
-
operationName: DataverseOperationName.RetrieveRecord,
|
|
1638
|
-
datasetName: dataSourceInfo.datasetName,
|
|
1639
|
-
isDataVerseOperation: true
|
|
1640
|
-
});
|
|
1641
|
-
}
|
|
1642
|
-
/**
|
|
1643
|
-
* Returns the database references for Dataverse, grouped by environment/database.
|
|
1644
|
-
* These come from the launch app response via runtime metadata client.
|
|
1645
|
-
*/
|
|
1646
|
-
async getDatabaseReferences() {
|
|
1647
|
-
if (this._databaseReferences) {
|
|
1648
|
-
return this._databaseReferences;
|
|
1649
|
-
}
|
|
1650
|
-
const runtimeDatabaseReferences = await this._loadDatabaseReferencesFromRuntime();
|
|
1651
|
-
if (runtimeDatabaseReferences && Object.keys(runtimeDatabaseReferences).length > 0) {
|
|
1652
|
-
this._databaseReferences = runtimeDatabaseReferences;
|
|
1653
|
-
return this._databaseReferences;
|
|
1654
|
-
}
|
|
1655
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceNotFound, "Failed to load Dataverse database references from runtime.");
|
|
1656
|
-
}
|
|
1657
|
-
/**
|
|
1658
|
-
* Loads database references from runtime metadata client (launch app response).
|
|
1659
|
-
*/
|
|
1660
|
-
async _loadDatabaseReferencesFromRuntime() {
|
|
1661
|
-
try {
|
|
1662
|
-
const metadataClient = await this._getMetadataClient();
|
|
1663
|
-
const response = await metadataClient.getAppDataSourceConfigsAsync();
|
|
1664
|
-
if (!response.success || !response.data) {
|
|
1665
|
-
return void 0;
|
|
1666
|
-
}
|
|
1667
|
-
const cdsDataSources = Object.values(response.data);
|
|
1668
|
-
if (cdsDataSources.length === 0) {
|
|
1669
|
-
return void 0;
|
|
1670
|
-
}
|
|
1671
|
-
const databaseReferences = {};
|
|
1672
|
-
for (const cdsDataSource of cdsDataSources) {
|
|
1673
|
-
const cdsConfig = cdsDataSource;
|
|
1674
|
-
const instanceUrl = this._extractInstanceUrlFromRuntimeUrl(cdsConfig.runtimeUrl);
|
|
1675
|
-
const envName = "default.cds";
|
|
1676
|
-
if (!databaseReferences[envName]) {
|
|
1677
|
-
databaseReferences[envName] = {
|
|
1678
|
-
databaseDetails: {
|
|
1679
|
-
referenceType: "Environmental",
|
|
1680
|
-
environmentName: envName,
|
|
1681
|
-
overrideValues: {
|
|
1682
|
-
status: "NotSpecified",
|
|
1683
|
-
environmentVariableName: ""
|
|
1684
|
-
},
|
|
1685
|
-
linkedEnvironmentMetadata: {
|
|
1686
|
-
resourceId: "",
|
|
1687
|
-
friendlyName: "",
|
|
1688
|
-
uniqueName: "",
|
|
1689
|
-
domainName: "",
|
|
1690
|
-
version: cdsConfig.version || "9.2",
|
|
1691
|
-
instanceUrl,
|
|
1692
|
-
instanceApiUrl: cdsConfig.runtimeUrl,
|
|
1693
|
-
baseLanguage: 1033,
|
|
1694
|
-
instanceState: "Ready",
|
|
1695
|
-
createdTime: "",
|
|
1696
|
-
platformSku: ""
|
|
1697
|
-
}
|
|
1698
|
-
},
|
|
1699
|
-
dataSources: {}
|
|
1700
|
-
};
|
|
1701
|
-
}
|
|
1702
|
-
const dataSourceName = cdsConfig.entitySetName || cdsConfig.logicalName;
|
|
1703
|
-
databaseReferences[envName].dataSources[dataSourceName] = {
|
|
1704
|
-
entitySetName: cdsConfig.entitySetName,
|
|
1705
|
-
logicalName: cdsConfig.logicalName,
|
|
1706
|
-
isHidden: false
|
|
1707
|
-
};
|
|
1708
|
-
}
|
|
1709
|
-
return databaseReferences;
|
|
1710
|
-
} catch (error) {
|
|
1711
|
-
Log.trackEvent("DataverseDataOperation.FailedToLoadDatabaseReferences", {
|
|
1712
|
-
message: "[DataverseDataOperation] Failed to load database references from runtime",
|
|
1713
|
-
error
|
|
1714
|
-
});
|
|
1715
|
-
return void 0;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
_extractInstanceUrlFromRuntimeUrl(runtimeUrl) {
|
|
1719
|
-
try {
|
|
1720
|
-
const matches = runtimeUrl.match(/^(https?:\/\/[^\/]+)/);
|
|
1721
|
-
return matches ? matches[1] : runtimeUrl;
|
|
1722
|
-
} catch (error) {
|
|
1723
|
-
Log.trackEvent("DataverseDataOperation.FailedToExtractInstanceUrl", {
|
|
1724
|
-
message: "[DataverseDataOperation] Failed to extract instance URL from runtime URL",
|
|
1725
|
-
error
|
|
1726
|
-
});
|
|
1727
|
-
return runtimeUrl;
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
/**
|
|
1731
|
-
* Helper to get a native data client and database reference
|
|
1732
|
-
*/
|
|
1733
|
-
async _getDataClient() {
|
|
1734
|
-
const dataClient = await this._clientProvider.getDataClientAsync();
|
|
1735
|
-
if (!dataClient) {
|
|
1736
|
-
Log.trackEvent("DataverseDataOperation.DataClientNotAvailable", {
|
|
1737
|
-
message: "[DataverseDataOperation] Data client is not available"
|
|
1738
|
-
});
|
|
1739
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientNotAvailable, "Data client is not available.");
|
|
1740
|
-
}
|
|
1741
|
-
return dataClient;
|
|
1742
|
-
}
|
|
1743
|
-
/**
|
|
1744
|
-
* Gets the metadata client instance
|
|
1745
|
-
*/
|
|
1746
|
-
async _getMetadataClient() {
|
|
1747
|
-
const metadataClient = await this._clientProvider.getMetadataClientAsync();
|
|
1748
|
-
if (!metadataClient) {
|
|
1749
|
-
Log.trackEvent("DataverseDataOperation.MetadataClientNotAvailable", {
|
|
1750
|
-
message: "[DataverseDataOperation] Metadata client is not available"
|
|
1751
|
-
});
|
|
1752
|
-
throw new PowerDataRuntimeError(ErrorCodes.MetadataClientNotAvailable);
|
|
1753
|
-
}
|
|
1754
|
-
return metadataClient;
|
|
1755
|
-
}
|
|
1756
|
-
/**
|
|
1757
|
-
* Template method for connector-style CRUD operations to reduce duplication.
|
|
1758
|
-
* Handles client, dataSourceInfo, requestUrl, and error handling.
|
|
1759
|
-
*/
|
|
1760
|
-
async _executeNativeDataverseOperation(tableName, buildUrl, operation, errorMessage) {
|
|
1761
|
-
try {
|
|
1762
|
-
const dataClient = await this._getDataClient();
|
|
1763
|
-
const dataSourceInfo = await this._getDataverseDataSourceInfo(tableName);
|
|
1764
|
-
const requestUrl = buildUrl(dataSourceInfo, tableName);
|
|
1765
|
-
return operation(dataClient, requestUrl, dataSourceInfo);
|
|
1766
|
-
} catch (error) {
|
|
1767
|
-
return createErrorResponse(error, errorMessage);
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Helper to get the Dataverse datasourceinfo from databaseReferences
|
|
1772
|
-
*/
|
|
1773
|
-
async _getDataverseDataSourceInfo(tableName) {
|
|
1774
|
-
let dbRefs;
|
|
1775
|
-
try {
|
|
1776
|
-
dbRefs = await this.getDatabaseReferences();
|
|
1777
|
-
} catch (error) {
|
|
1778
|
-
Log.trackEvent("DataverseDataOperation.GetDataSourceInfoFailed", {
|
|
1779
|
-
message: "[DataverseDataOperation] Failed to get database references",
|
|
1780
|
-
tableName,
|
|
1781
|
-
error
|
|
1782
|
-
});
|
|
1783
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1784
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceNotFound, `Failed to get Dataverse data source info for table '${tableName}': ${errorMessage}`);
|
|
1785
|
-
}
|
|
1786
|
-
for (const dbKey of Object.keys(dbRefs)) {
|
|
1787
|
-
const db = dbRefs[dbKey];
|
|
1788
|
-
if (db.dataSources[tableName]) {
|
|
1789
|
-
const ds = db.dataSources[tableName];
|
|
1790
|
-
return {
|
|
1791
|
-
datasetName: db.databaseDetails?.environmentName,
|
|
1792
|
-
referenceType: db.databaseDetails?.referenceType,
|
|
1793
|
-
linkedEnvironmentMetadata: db.databaseDetails?.linkedEnvironmentMetadata,
|
|
1794
|
-
entitySetName: ds?.entitySetName,
|
|
1795
|
-
logicalName: ds?.logicalName,
|
|
1796
|
-
isHidden: ds?.isHidden,
|
|
1797
|
-
tableId: ds?.logicalName,
|
|
1798
|
-
apis: {}
|
|
1799
|
-
};
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
const notFoundMsg = `No Dataverse data source found for table: ${tableName}`;
|
|
1803
|
-
Log.trackEvent("DataverseDataOperation.DataSourceNotFound", {
|
|
1804
|
-
message: notFoundMsg,
|
|
1805
|
-
tableName
|
|
1806
|
-
});
|
|
1807
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceNotFound, notFoundMsg);
|
|
1808
|
-
}
|
|
1809
|
-
/**
|
|
1810
|
-
* Helper to construct the Dataverse API URL using instanceUrl if available, otherwise fallback to runtimeUrl.
|
|
1811
|
-
*/
|
|
1812
|
-
_getInstanceUrl(dataSourceInfo) {
|
|
1813
|
-
const instanceUrl = dataSourceInfo.linkedEnvironmentMetadata?.instanceUrl;
|
|
1814
|
-
if (!instanceUrl) {
|
|
1815
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientInitFailed, "No instanceUrl found for Dataverse table.");
|
|
1816
|
-
}
|
|
1817
|
-
const baseUrl = instanceUrl.endsWith("/") ? instanceUrl : `${instanceUrl}/`;
|
|
1818
|
-
return baseUrl;
|
|
1819
|
-
}
|
|
1820
|
-
/**
|
|
1821
|
-
* Helper to construct the Dataverse API URL using instanceUrl if available, otherwise fallback to runtimeUrl.
|
|
1822
|
-
*/
|
|
1823
|
-
_getDataverseRequestUrl(dataSourceInfo, tableName, urlPath = "") {
|
|
1824
|
-
const baseUrl = this._getInstanceUrl(dataSourceInfo);
|
|
1825
|
-
return `${baseUrl}api/data/v9.0/${tableName}${urlPath}`;
|
|
1826
|
-
}
|
|
1827
|
-
/**
|
|
1828
|
-
* Constructs GET request URL for fetching metadata using options object.
|
|
1829
|
-
* @param dataSourceInfo - The data source information for the Dataverse table.
|
|
1830
|
-
* @param options - The options for the metadata request.
|
|
1831
|
-
* @returns The constructed metadata request URL.
|
|
1832
|
-
*/
|
|
1833
|
-
_generateMetadataRequestUrl(dataSourceInfo, options) {
|
|
1834
|
-
const { logicalName } = dataSourceInfo;
|
|
1835
|
-
if (!logicalName) {
|
|
1836
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientInitFailed, "No logicalName found for Dataverse table.");
|
|
1837
|
-
}
|
|
1838
|
-
const url = new URL(`${this._getInstanceUrl(dataSourceInfo)}api/data/v9.0/EntityDefinitions(LogicalName='${logicalName}')`);
|
|
1839
|
-
const { metadata, schema } = options;
|
|
1840
|
-
const selects = new Set(Array.isArray(metadata) ? metadata : []);
|
|
1841
|
-
selects.add("LogicalName");
|
|
1842
|
-
const expands = [];
|
|
1843
|
-
if (schema?.manyToOne) {
|
|
1844
|
-
expands.push("ManyToOneRelationships");
|
|
1845
|
-
}
|
|
1846
|
-
if (schema?.oneToMany) {
|
|
1847
|
-
expands.push("OneToManyRelationships");
|
|
1848
|
-
}
|
|
1849
|
-
if (schema?.manyToMany) {
|
|
1850
|
-
expands.push("ManyToManyRelationships");
|
|
1851
|
-
}
|
|
1852
|
-
if (schema?.columns === "all") {
|
|
1853
|
-
expands.push("Attributes");
|
|
1854
|
-
} else if (schema && Array.isArray(schema.columns) && schema.columns.length > 0) {
|
|
1855
|
-
const attributesCollection = schema.columns.map((a) => `'${a}'`).join(",");
|
|
1856
|
-
expands.push(`Attributes($filter=Microsoft.Dynamics.CRM.In(PropertyName='LogicalName',PropertyValues=[${attributesCollection}]))`);
|
|
1857
|
-
}
|
|
1858
|
-
url.search = new URLSearchParams({
|
|
1859
|
-
$select: [...selects].join(","),
|
|
1860
|
-
$expand: expands.join(",")
|
|
1861
|
-
}).toString();
|
|
1862
|
-
return url.toString();
|
|
1863
|
-
}
|
|
1864
|
-
};
|
|
1865
|
-
function extractSkipToken(nextLink) {
|
|
1866
|
-
if (!nextLink?.trim()) {
|
|
1867
|
-
return void 0;
|
|
1868
|
-
}
|
|
1869
|
-
const match = nextLink.match(/[\?&]\$?skiptoken=([^&#]+)/i);
|
|
1870
|
-
return match ? decodeURIComponent(match[1]) : void 0;
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
var ConnectorDataOperationExecutor = class {
|
|
1874
|
-
// =====================================
|
|
1875
|
-
// Constructor
|
|
1876
|
-
// =====================================
|
|
1877
|
-
constructor(clientProvider, connectionsService) {
|
|
1878
|
-
// =====================================
|
|
1879
|
-
// Private Members
|
|
1880
|
-
// =====================================
|
|
1881
|
-
__publicField(this, "_clientProvider");
|
|
1882
|
-
__publicField(this, "_connectionsService");
|
|
1883
|
-
__publicField(this, "_databaseReferences");
|
|
1884
|
-
__publicField(this, "_connectionReferences");
|
|
1885
|
-
this._validateConstructorParams(clientProvider, connectionsService);
|
|
1886
|
-
this._clientProvider = clientProvider;
|
|
1887
|
-
this._connectionsService = connectionsService;
|
|
1888
|
-
}
|
|
1889
|
-
// =====================================
|
|
1890
|
-
// Public Methods
|
|
1891
|
-
// =====================================
|
|
1892
|
-
/**
|
|
1893
|
-
* Creates a new record in the specified table
|
|
1894
|
-
*/
|
|
1895
|
-
async createRecordAsync(tableName, data) {
|
|
1896
|
-
try {
|
|
1897
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1898
|
-
const requestUrl = await this._buildTableUrl(tableName, connectionReference);
|
|
1899
|
-
const result = await dataClient.createDataAsync(requestUrl, connectionReference.apiId, tableName, data, { operationName: ConnectorOperationName.CreateRecord });
|
|
1900
|
-
return result;
|
|
1901
|
-
} catch (error) {
|
|
1902
|
-
return createErrorResponse(error, DataOperationErrorMessages.CreateFailed);
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
/**
|
|
1906
|
-
* Updates an existing record in the specified table
|
|
1907
|
-
*/
|
|
1908
|
-
async updateRecordAsync(tableName, id, data) {
|
|
1909
|
-
try {
|
|
1910
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1911
|
-
const requestUrl = await this._buildTableUrl(tableName, connectionReference, `/${id}`);
|
|
1912
|
-
const result = await dataClient.updateDataAsync(requestUrl, connectionReference.apiId, tableName, data, { operationName: ConnectorOperationName.UpdateRecord });
|
|
1913
|
-
return result;
|
|
1914
|
-
} catch (error) {
|
|
1915
|
-
return createErrorResponse(error, DataOperationErrorMessages.UpdateFailed);
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
/**
|
|
1919
|
-
* Deletes a record from the specified table
|
|
1920
|
-
*/
|
|
1921
|
-
async deleteRecordAsync(tableName, id) {
|
|
1922
|
-
try {
|
|
1923
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1924
|
-
const requestUrl = await this._buildTableUrl(tableName, connectionReference, `/${id}`);
|
|
1925
|
-
const result = await dataClient.deleteDataAsync(requestUrl, connectionReference.apiId, tableName, { operationName: ConnectorOperationName.DeleteRecord });
|
|
1926
|
-
return result;
|
|
1927
|
-
} catch (error) {
|
|
1928
|
-
return createErrorResponse(error, DataOperationErrorMessages.DeleteFailed);
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
/**
|
|
1932
|
-
* Retrieves a single record from the specified table
|
|
1933
|
-
*/
|
|
1934
|
-
async retrieveRecordAsync(tableName, id, options) {
|
|
1935
|
-
try {
|
|
1936
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1937
|
-
const requestUrl = await this._buildTableUrl(tableName, connectionReference, `/${id}${convertOptionsToQueryString(options)}`);
|
|
1938
|
-
const result = await dataClient.retrieveDataAsync(
|
|
1939
|
-
requestUrl,
|
|
1940
|
-
connectionReference.apiId,
|
|
1941
|
-
tableName,
|
|
1942
|
-
HttpMethod.GET,
|
|
1943
|
-
void 0,
|
|
1944
|
-
// body
|
|
1945
|
-
{ operationName: ConnectorOperationName.RetrieveRecord }
|
|
1946
|
-
);
|
|
1947
|
-
return result;
|
|
1948
|
-
} catch (error) {
|
|
1949
|
-
return createErrorResponse(error, DataOperationErrorMessages.RetrieveFailed);
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
/**
|
|
1953
|
-
* Retrieves multiple records from the specified table
|
|
1954
|
-
*/
|
|
1955
|
-
async retrieveMultipleRecordsAsync(tableName, options) {
|
|
1956
|
-
try {
|
|
1957
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1958
|
-
const requestUrl = await this._buildTableUrl(tableName, connectionReference, convertOptionsToQueryString(options), false);
|
|
1959
|
-
const result = await dataClient.retrieveDataAsync(
|
|
1960
|
-
requestUrl,
|
|
1961
|
-
connectionReference.apiId,
|
|
1962
|
-
tableName,
|
|
1963
|
-
HttpMethod.GET,
|
|
1964
|
-
void 0,
|
|
1965
|
-
// body
|
|
1966
|
-
{ operationName: ConnectorOperationName.RetrieveMultipleRecords }
|
|
1967
|
-
);
|
|
1968
|
-
return result;
|
|
1969
|
-
} catch (error) {
|
|
1970
|
-
return createErrorResponse(error, DataOperationErrorMessages.RetrieveMultipleFailed);
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
/**
|
|
1974
|
-
* Executes a custom operation on the data source
|
|
1975
|
-
*/
|
|
1976
|
-
async executeAsync(operation) {
|
|
1977
|
-
try {
|
|
1978
|
-
if (!operation?.connectorOperation) {
|
|
1979
|
-
throw new Error(`${DataOperationErrorMessages.InvalidRequest}: ${DataOperationErrorMessages.MissingConnectorOperation}`);
|
|
1980
|
-
}
|
|
1981
|
-
const tableName = operation.connectorOperation.tableName;
|
|
1982
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
1983
|
-
const { dataClient, connectionReference } = await this._getClientsAndConnection(tableName);
|
|
1984
|
-
const config = await this._getOperationConfig(operation, connectionReference, tableName);
|
|
1985
|
-
const requestUrl = await this._buildOperationUrl(operation, config);
|
|
1986
|
-
const bodyParam = await this._buildOperationBody(operation, tableName);
|
|
1987
|
-
const headers = await this._buildOperationHeader(operation, tableName);
|
|
1988
|
-
const httpMethod = this._getHttpMethod(requestUrl, dataSourceInfo, operation.connectorOperation.operationName);
|
|
1989
|
-
const responseInfo = dataSourceInfo.apis[operation.connectorOperation.operationName]?.responseInfo;
|
|
1990
|
-
const result = await dataClient.retrieveDataAsync(requestUrl, config.apiId, tableName, httpMethod, headers, bodyParam, {
|
|
1991
|
-
isExecuteAsync: true,
|
|
1992
|
-
// Use the connector operation name for telemetry, may be a better idea to use executeAsync
|
|
1993
|
-
// here and just log the connector operation name in the custom dimensions leaving comment for PR.
|
|
1994
|
-
operationName: `connectorDataOperation.${operation.connectorOperation.operationName}`,
|
|
1995
|
-
responseInfo
|
|
1996
|
-
});
|
|
1997
|
-
return result;
|
|
1998
|
-
} catch (error) {
|
|
1999
|
-
return createErrorResponse(error, DataOperationErrorMessages.ExecuteFailed);
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
// =====================================
|
|
2003
|
-
// Private Methods
|
|
2004
|
-
// =====================================
|
|
2005
|
-
/**
|
|
2006
|
-
* Determines the appropriate HTTP method for a request
|
|
2007
|
-
* @param requestUrl - The URL for the request
|
|
2008
|
-
* @param dataSourceInfo - The data source information
|
|
2009
|
-
* @param operation - The operation name
|
|
2010
|
-
* @returns The HTTP method to use
|
|
2011
|
-
*/
|
|
2012
|
-
_getHttpMethod(requestUrl, dataSourceInfo, operation) {
|
|
2013
|
-
const isSqlStoredProcedure = requestUrl.indexOf("apim/sql") > -1;
|
|
2014
|
-
if (isSqlStoredProcedure) {
|
|
2015
|
-
return HttpMethod.POST;
|
|
2016
|
-
}
|
|
2017
|
-
const method = dataSourceInfo.apis[operation]?.method;
|
|
2018
|
-
if (method) {
|
|
2019
|
-
return method;
|
|
2020
|
-
}
|
|
2021
|
-
return HttpMethod.GET;
|
|
2022
|
-
}
|
|
2023
|
-
/**
|
|
2024
|
-
* Builds the operation body parameters
|
|
2025
|
-
*/
|
|
2026
|
-
async _buildOperationBody(operation, tableName) {
|
|
2027
|
-
const operationName = operation?.connectorOperation?.operationName;
|
|
2028
|
-
if (operationName) {
|
|
2029
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2030
|
-
const hasBodyParameter = dataSourceInfo?.apis?.[operationName]?.parameters?.some((param) => param.in === "body");
|
|
2031
|
-
if (hasBodyParameter) {
|
|
2032
|
-
return await this._buildOperationBodyParam(operation, tableName);
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
return void 0;
|
|
2036
|
-
}
|
|
2037
|
-
/**
|
|
2038
|
-
* Builds operation body parameters from the operation and data source info
|
|
2039
|
-
*/
|
|
2040
|
-
async _buildOperationBodyParam(operation, tableName) {
|
|
2041
|
-
const operationName = operation.connectorOperation?.operationName;
|
|
2042
|
-
if (!operationName) {
|
|
2043
|
-
return "{}";
|
|
2044
|
-
}
|
|
2045
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2046
|
-
const apiParams = dataSourceInfo?.apis?.[operationName]?.parameters || [];
|
|
2047
|
-
const rawParams = operation.connectorOperation?.parameters || [];
|
|
2048
|
-
if (typeof rawParams !== "object" || rawParams === null) {
|
|
2049
|
-
return "{}";
|
|
2050
|
-
}
|
|
2051
|
-
const bodyParam = apiParams.find((param) => param.in === "body");
|
|
2052
|
-
if (bodyParam) {
|
|
2053
|
-
const value = rawParams[bodyParam.name];
|
|
2054
|
-
if (value !== void 0 && value !== null) {
|
|
2055
|
-
return JSON.stringify(value);
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
return "{}";
|
|
2059
|
-
}
|
|
2060
|
-
/**
|
|
2061
|
-
* Builds the operation header for a given data operation if required.
|
|
2062
|
-
*
|
|
2063
|
-
* @template TRequest - The type of the request payload for the data operation.
|
|
2064
|
-
* @param dataOperationRequest - The data operation containing details about the connector operation.
|
|
2065
|
-
* @param tableName - The name of the table associated with the data operation.
|
|
2066
|
-
* @returns A promise that resolves to the operation header as a string if a header parameter is required,
|
|
2067
|
-
* or `undefined` if no header parameter is needed.
|
|
2068
|
-
*/
|
|
2069
|
-
async _buildOperationHeader(dataOperationRequest, tableName) {
|
|
2070
|
-
const operationName = dataOperationRequest.connectorOperation?.operationName;
|
|
2071
|
-
if (operationName) {
|
|
2072
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2073
|
-
const hasHeaderParameter = dataSourceInfo?.apis?.[operationName]?.parameters?.some((param) => param.in === "header");
|
|
2074
|
-
if (hasHeaderParameter) {
|
|
2075
|
-
return await this._buildOperationHeaderParam(dataOperationRequest, tableName);
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
|
-
return void 0;
|
|
2079
|
-
}
|
|
2080
|
-
/**
|
|
2081
|
-
* Builds the operation header parameters as a JSON string for a given data operation.
|
|
2082
|
-
*
|
|
2083
|
-
* @template TRequest - The type of the request object for the data operation.
|
|
2084
|
-
* @param dataOperationRequest - The data operation containing connector operation details and parameters.
|
|
2085
|
-
* @param tableName - The name of the table associated with the data operation.
|
|
2086
|
-
* @returns A promise that resolves to a JSON string representing the header parameters,
|
|
2087
|
-
* or `undefined` if no `header` parameters are available.
|
|
2088
|
-
*/
|
|
2089
|
-
async _buildOperationHeaderParam(dataOperationRequest, tableName) {
|
|
2090
|
-
const operationName = dataOperationRequest.connectorOperation?.operationName;
|
|
2091
|
-
if (!operationName) {
|
|
2092
|
-
return {};
|
|
2093
|
-
}
|
|
2094
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2095
|
-
const apiParamSpec = dataSourceInfo?.apis?.[operationName]?.parameters || [];
|
|
2096
|
-
const inputParams = dataOperationRequest.connectorOperation?.parameters;
|
|
2097
|
-
const headers = {};
|
|
2098
|
-
if (!inputParams) {
|
|
2099
|
-
return void 0;
|
|
2100
|
-
}
|
|
2101
|
-
if (typeof inputParams === "string") {
|
|
2102
|
-
if (apiParamSpec.length === 1 && apiParamSpec[0].in === "header") {
|
|
2103
|
-
headers[apiParamSpec[0].name] = inputParams;
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
if (typeof inputParams === "object" && !Array.isArray(inputParams)) {
|
|
2107
|
-
apiParamSpec.forEach((param) => {
|
|
2108
|
-
if (param.in === "header" && param.name in inputParams) {
|
|
2109
|
-
headers[param.name] = inputParams[param.name];
|
|
2110
|
-
}
|
|
2111
|
-
});
|
|
2112
|
-
}
|
|
2113
|
-
if (Array.isArray(inputParams)) {
|
|
2114
|
-
apiParamSpec.forEach((param, index) => {
|
|
2115
|
-
if (param.in === "header" && inputParams[index] !== void 0) {
|
|
2116
|
-
headers[param.name] = inputParams[index];
|
|
2117
|
-
}
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
return headers;
|
|
2121
|
-
}
|
|
2122
|
-
/**
|
|
2123
|
-
* Constructs the request URL for table operations
|
|
2124
|
-
* @param tableName - The name of the table
|
|
2125
|
-
* @param connectionReference - The connection reference
|
|
2126
|
-
* @param options - Optional URL parameters
|
|
2127
|
-
* @param encodeOptions - Whether to encode the options
|
|
2128
|
-
* @returns The constructed URL
|
|
2129
|
-
*/
|
|
2130
|
-
async _buildTableUrl(tableName, connectionReference, options = "", encodeOptions = true) {
|
|
2131
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2132
|
-
const isSharedSql = (connectionReference.apiId ?? "").indexOf("shared_sql") > -1;
|
|
2133
|
-
const isSharePoint = (connectionReference.apiId ?? "").indexOf("shared_sharepointonline") > -1;
|
|
2134
|
-
const urlBuilder = {
|
|
2135
|
-
runtimeUrl: connectionReference.runtimeUrl ?? "",
|
|
2136
|
-
connectionName: connectionReference.connectionName ?? "",
|
|
2137
|
-
datasetName: connectionReference.datasetName ? isSharedSql ? connectionReference.datasetNameOverride : isSharePoint ? encodeURIComponent(encodeURIComponent(connectionReference.datasetName)) : encodeURIComponent(connectionReference.datasetName) : "",
|
|
2138
|
-
tableId: isSharedSql ? encodeURIComponent(encodeURIComponent(dataSourceInfo.tableId)) : dataSourceInfo.tableId,
|
|
2139
|
-
version: dataSourceInfo.version,
|
|
2140
|
-
isSharedSql
|
|
2141
|
-
};
|
|
2142
|
-
return this._constructUrl(urlBuilder, options, encodeOptions);
|
|
2143
|
-
}
|
|
2144
|
-
/**
|
|
2145
|
-
* Builds the operation URL
|
|
2146
|
-
*/
|
|
2147
|
-
async _buildOperationUrl(operation, config) {
|
|
2148
|
-
const operationName = operation.connectorOperation?.operationName;
|
|
2149
|
-
if (!operationName) {
|
|
2150
|
-
throw new Error(`${DataOperationErrorMessages.InvalidOperationParameters}: ${DataOperationErrorMessages.MissingOperationName}`);
|
|
2151
|
-
}
|
|
2152
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(config.tableName);
|
|
2153
|
-
const isSharedSql = (config.apiId ?? "").indexOf("shared_sql") > -1;
|
|
2154
|
-
const path = dataSourceInfo.apis[operationName].path;
|
|
2155
|
-
if (isSharedSql) {
|
|
2156
|
-
return this._buildSharedSqlOperationUrl(config, path);
|
|
2157
|
-
}
|
|
2158
|
-
return this._buildStandardOperationUrl(operation, config, operationName, path);
|
|
2159
|
-
}
|
|
2160
|
-
/**
|
|
2161
|
-
* Gets the connection references
|
|
2162
|
-
*/
|
|
2163
|
-
async _getConnectionReferencesAsync() {
|
|
2164
|
-
if (this._connectionReferences) {
|
|
2165
|
-
return this._connectionReferences;
|
|
2166
|
-
}
|
|
2167
|
-
const metadataClient = await this._getMetadataClient();
|
|
2168
|
-
const response = await metadataClient.getAppConnectionConfigsAsync();
|
|
2169
|
-
this._connectionReferences = response.data;
|
|
2170
|
-
return this._connectionReferences;
|
|
2171
|
-
}
|
|
2172
|
-
/**
|
|
2173
|
-
* Gets the database references
|
|
2174
|
-
*/
|
|
2175
|
-
async _getDatabaseReferencesAsync() {
|
|
2176
|
-
if (this._databaseReferences) {
|
|
2177
|
-
return this._databaseReferences;
|
|
2178
|
-
}
|
|
2179
|
-
const metadataClient = await this._getMetadataClient();
|
|
2180
|
-
const response = await metadataClient.getAppDataSourceConfigsAsync();
|
|
2181
|
-
this._databaseReferences = response.data;
|
|
2182
|
-
return this._databaseReferences;
|
|
2183
|
-
}
|
|
2184
|
-
/**
|
|
2185
|
-
* Gets the metadata client instance
|
|
2186
|
-
*/
|
|
2187
|
-
async _getMetadataClient() {
|
|
2188
|
-
const metadataClient = await this._clientProvider.getMetadataClientAsync();
|
|
2189
|
-
if (!metadataClient) {
|
|
2190
|
-
throw new PowerDataRuntimeError(ErrorCodes.MetadataClientNotAvailable);
|
|
2191
|
-
}
|
|
2192
|
-
return metadataClient;
|
|
2193
|
-
}
|
|
2194
|
-
/**
|
|
2195
|
-
* Gets the connection reference for a table
|
|
2196
|
-
*/
|
|
2197
|
-
_getConnectionReference(tableName) {
|
|
2198
|
-
const connectionReference = this._connectionReferences?.[tableName];
|
|
2199
|
-
if (!connectionReference) {
|
|
2200
|
-
throw new PowerDataRuntimeError(ErrorCodes.ConnectionReferenceNotFound, tableName);
|
|
2201
|
-
}
|
|
2202
|
-
return connectionReference;
|
|
2203
|
-
}
|
|
2204
|
-
/**
|
|
2205
|
-
* Gets both the data client and connection reference
|
|
2206
|
-
*/
|
|
2207
|
-
async _getClientsAndConnection(tableName) {
|
|
2208
|
-
await this._getReferences();
|
|
2209
|
-
const dataClient = await this._clientProvider.getDataClientAsync();
|
|
2210
|
-
if (!dataClient) {
|
|
2211
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataClientNotAvailable);
|
|
2212
|
-
}
|
|
2213
|
-
const connectionReference = this._getConnectionReference(tableName);
|
|
2214
|
-
return { dataClient, connectionReference };
|
|
2215
|
-
}
|
|
2216
|
-
/**
|
|
2217
|
-
* Builds the URL for shared SQL operations
|
|
2218
|
-
*/
|
|
2219
|
-
_buildSharedSqlOperationUrl(config, path) {
|
|
2220
|
-
const version = config.version ? `/${config.version}/` : "/";
|
|
2221
|
-
return `${config.runtimeUrl}/${config.connectionName}${version}datasets/${config.datasetName}/procedures${path}`;
|
|
2222
|
-
}
|
|
2223
|
-
/**
|
|
2224
|
-
* Builds the URL for standard operations
|
|
2225
|
-
* Assumptions / Invariants:
|
|
2226
|
-
* - The connector always defines a required path parameter for the connection id named 'connectionId'.
|
|
2227
|
-
* - When a dataset is applicable, the parameter name is 'dataset'.
|
|
2228
|
-
* - When a table is applicable, the parameter name is 'tableName'.
|
|
2229
|
-
* - A lone string parameter maps to the first remaining (non-synthetic) required API parameter.
|
|
2230
|
-
* - Array parameters map positionally to the remaining API parameters after filtering.
|
|
2231
|
-
* - Object parameters map by (case-insensitive, hyphen/underscore agnostic) key.
|
|
2232
|
-
* @param operation - The data operation containing connector operation details from runtime
|
|
2233
|
-
* @param config - The connector operation configuration
|
|
2234
|
-
* @param operationName - The name of the operation to be performed
|
|
2235
|
-
* @param path - The path template for the operation
|
|
2236
|
-
*/
|
|
2237
|
-
async _buildStandardOperationUrl(operation, config, operationName, path) {
|
|
2238
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(config.tableName);
|
|
2239
|
-
let apiParams = dataSourceInfo.apis[operationName]?.parameters || [];
|
|
2240
|
-
if (apiParams.length > 0) {
|
|
2241
|
-
apiParams = apiParams.filter((param) => param.name !== "connectionId" && param.name !== "dataset" && param.name !== "tableName");
|
|
2242
|
-
}
|
|
2243
|
-
const operationParams = operation.connectorOperation?.parameters;
|
|
2244
|
-
const rawParamValues = {
|
|
2245
|
-
connectionId: config.connectionName,
|
|
2246
|
-
dataset: (
|
|
2247
|
-
// The dataset name needs to be double encoded for sharepoint, once here and then once in the HTTP pipeline
|
|
2248
|
-
// CRUD operations already handle this, so we need to do the same here
|
|
2249
|
-
config.apiId.indexOf("shared_sharepointonline") !== -1 && config.datasetName ? encodeURIComponent(config.datasetName) : config.datasetName
|
|
2250
|
-
),
|
|
2251
|
-
tableName: config.tableName
|
|
2252
|
-
};
|
|
2253
|
-
if (operationParams !== void 0) {
|
|
2254
|
-
if (typeof operationParams === "string") {
|
|
2255
|
-
if (apiParams.length > 0) {
|
|
2256
|
-
const requiredParams = apiParams.filter((param) => param.required);
|
|
2257
|
-
rawParamValues[requiredParams?.[0]?.name ?? apiParams[0].name] = operationParams;
|
|
2258
|
-
}
|
|
2259
|
-
} else if (typeof operationParams === "object" && !Array.isArray(operationParams)) {
|
|
2260
|
-
apiParams.forEach((param) => {
|
|
2261
|
-
if (operationParams) {
|
|
2262
|
-
const value = this._getNormalizedParamValue(operationParams, param.name);
|
|
2263
|
-
if (value !== void 0) {
|
|
2264
|
-
rawParamValues[param.name] = value;
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
} else if (Array.isArray(operationParams)) {
|
|
2269
|
-
apiParams.forEach((param, index) => {
|
|
2270
|
-
rawParamValues[param.name] = operationParams[index];
|
|
2271
|
-
});
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
const { processedPath, queryParams } = this._processParameters(
|
|
2275
|
-
// deliberately pass the unfiltered list to _processParameters so path placeholders still see synthetic params.
|
|
2276
|
-
dataSourceInfo.apis[operationName]?.parameters || [],
|
|
2277
|
-
rawParamValues,
|
|
2278
|
-
path
|
|
2279
|
-
);
|
|
2280
|
-
const separator = queryParams ? processedPath.includes("?") ? "&" : "?" : "";
|
|
2281
|
-
return `${config.runtimeUrl}${processedPath}${separator}${queryParams}`;
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Normalizes the parameter name by replacing hyphens with underscores and performs case-insensitive matching
|
|
2285
|
-
*/
|
|
2286
|
-
_getNormalizedParamValue(obj, paramName) {
|
|
2287
|
-
const normalizedParamName = paramName.replace(/-/g, "_").toLowerCase();
|
|
2288
|
-
const foundKey = Object.keys(obj).find((key) => key.replace(/-/g, "_").toLowerCase() === normalizedParamName);
|
|
2289
|
-
return foundKey !== void 0 ? obj[foundKey] : void 0;
|
|
2290
|
-
}
|
|
2291
|
-
/**
|
|
2292
|
-
* Processes operation parameters into path and query parameters
|
|
2293
|
-
* @param apiParams - The API parameter specifications from the data source info
|
|
2294
|
-
* @param rawParamValues - The raw parameter values provided in the operation at runtime
|
|
2295
|
-
* @param path - The initial path template
|
|
2296
|
-
* @returns An object containing the processed path and query parameters
|
|
2297
|
-
*/
|
|
2298
|
-
_processParameters(apiParams, rawParamValues, path) {
|
|
2299
|
-
const usedParams = /* @__PURE__ */ new Set();
|
|
2300
|
-
let processedPath = path;
|
|
2301
|
-
const queryParams = [];
|
|
2302
|
-
apiParams.forEach((param, index) => {
|
|
2303
|
-
const paramValue = rawParamValues[param.name];
|
|
2304
|
-
if (paramValue === void 0) {
|
|
2305
|
-
return;
|
|
2306
|
-
}
|
|
2307
|
-
if (param.in === "path") {
|
|
2308
|
-
const placeholder = `{${param.name}}`;
|
|
2309
|
-
if (processedPath.includes(placeholder)) {
|
|
2310
|
-
processedPath = processedPath.replace(placeholder, encodeURIComponent(String(paramValue)));
|
|
2311
|
-
usedParams.add(param.name);
|
|
2312
|
-
}
|
|
2313
|
-
} else if (param.in === "query") {
|
|
2314
|
-
queryParams.push(`${encodeURIComponent(param.name)}=${encodeURIComponent(String(paramValue))}`);
|
|
2315
|
-
usedParams.add(param.name);
|
|
2316
|
-
}
|
|
2317
|
-
});
|
|
2318
|
-
return {
|
|
2319
|
-
processedPath,
|
|
2320
|
-
queryParams: queryParams.join("&")
|
|
2321
|
-
};
|
|
2322
|
-
}
|
|
2323
|
-
/**
|
|
2324
|
-
* Gets the operation configuration
|
|
2325
|
-
*/
|
|
2326
|
-
async _getOperationConfig(operation, connectionReference, tableName) {
|
|
2327
|
-
if (!operation.connectorOperation) {
|
|
2328
|
-
throw new Error(`${DataOperationErrorMessages.InvalidRequest}: ${DataOperationErrorMessages.MissingConnectorOperation}`);
|
|
2329
|
-
}
|
|
2330
|
-
const dataSourceInfo = await this._connectionsService.getDataSource(tableName);
|
|
2331
|
-
const config = {
|
|
2332
|
-
tableName,
|
|
2333
|
-
apiId: connectionReference.apiId ?? "",
|
|
2334
|
-
runtimeUrl: connectionReference.runtimeUrl ?? "",
|
|
2335
|
-
connectionName: connectionReference.connectionName ?? "",
|
|
2336
|
-
datasetName: connectionReference.datasetName ?? "",
|
|
2337
|
-
tableId: dataSourceInfo.tableId,
|
|
2338
|
-
version: dataSourceInfo.version
|
|
2339
|
-
};
|
|
2340
|
-
return config;
|
|
2341
|
-
}
|
|
2342
|
-
/**
|
|
2343
|
-
* Initializes the clients
|
|
2344
|
-
*/
|
|
2345
|
-
async _getReferences() {
|
|
2346
|
-
await this._getConnectionReferencesAsync();
|
|
2347
|
-
await this._getDatabaseReferencesAsync();
|
|
2348
|
-
}
|
|
2349
|
-
/**
|
|
2350
|
-
* Validates constructor parameters
|
|
2351
|
-
*/
|
|
2352
|
-
_validateConstructorParams(clientProvider, connectionsService) {
|
|
2353
|
-
if (!clientProvider) {
|
|
2354
|
-
throw new PowerDataRuntimeError(ErrorCodes.ClientProviderNotAvailable);
|
|
2355
|
-
}
|
|
2356
|
-
if (!connectionsService) {
|
|
2357
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceServiceNotAvailable);
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
/**
|
|
2361
|
-
* Constructs the final URL
|
|
2362
|
-
*/
|
|
2363
|
-
_constructUrl(urlBuilder, options = "", encodeOptions = true) {
|
|
2364
|
-
const apiVersion = urlBuilder.version ? `/${urlBuilder.version}/` : "/";
|
|
2365
|
-
const encodedOptions = encodeOptions && options ? options.charAt(0) + encodeURIComponent(options.slice(1)) : options;
|
|
2366
|
-
if (urlBuilder.datasetName) {
|
|
2367
|
-
return `${urlBuilder.runtimeUrl}/${urlBuilder.connectionName}${apiVersion}datasets/${urlBuilder.datasetName}/tables/${urlBuilder.tableId}/items${encodedOptions}`;
|
|
2368
|
-
}
|
|
2369
|
-
return `${urlBuilder.runtimeUrl}/${urlBuilder.connectionName}/tables/${urlBuilder.tableId}/items${encodedOptions}`;
|
|
2370
|
-
}
|
|
2371
|
-
};
|
|
2372
|
-
|
|
2373
|
-
var DataSourceServiceError;
|
|
2374
|
-
/* @__PURE__ */ (function(DataSourceServiceError2) {
|
|
2375
|
-
})(DataSourceServiceError || (DataSourceServiceError = {}));
|
|
2376
|
-
var RuntimeDataSourceService = class {
|
|
2377
|
-
/**
|
|
2378
|
-
* Creates a new instance of RuntimeDataSourceService
|
|
2379
|
-
*/
|
|
2380
|
-
constructor(_powerDataSourcesInfoProvider) {
|
|
2381
|
-
__publicField(this, "_powerDataSourcesInfoProvider");
|
|
2382
|
-
/**
|
|
2383
|
-
* Data source information
|
|
2384
|
-
*/
|
|
2385
|
-
__publicField(this, "_dataSourcesInfo");
|
|
2386
|
-
/**
|
|
2387
|
-
* Indicates whether the service has been initialized
|
|
2388
|
-
*/
|
|
2389
|
-
__publicField(this, "_isInitialized");
|
|
2390
|
-
this._powerDataSourcesInfoProvider = _powerDataSourcesInfoProvider;
|
|
2391
|
-
this._dataSourcesInfo = {};
|
|
2392
|
-
this._isInitialized = false;
|
|
2393
|
-
}
|
|
2394
|
-
/**
|
|
2395
|
-
* Initializes the service by loading user data sources
|
|
2396
|
-
* @throws PowerDataRuntimeError if initialization fails
|
|
2397
|
-
*/
|
|
2398
|
-
async initialize() {
|
|
2399
|
-
try {
|
|
2400
|
-
const userDataSources = await this._getUserDataSources();
|
|
2401
|
-
this._dataSourcesInfo = {};
|
|
2402
|
-
Object.keys(userDataSources).forEach((key) => {
|
|
2403
|
-
this._dataSourcesInfo[key] = userDataSources[key];
|
|
2404
|
-
});
|
|
2405
|
-
this._isInitialized = true;
|
|
2406
|
-
} catch (error) {
|
|
2407
|
-
throw new PowerDataRuntimeError(ErrorCodes.InitializationError, getErrorMessage(error));
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
/**
|
|
2411
|
-
* Gets all user data sources
|
|
2412
|
-
* @returns Array of data source information
|
|
2413
|
-
* @throws PowerDataRuntimeError if service is not initialized
|
|
2414
|
-
*/
|
|
2415
|
-
async getUserDataSources() {
|
|
2416
|
-
await this._ensureInitialized();
|
|
2417
|
-
return this._dataSourcesInfo;
|
|
2418
|
-
}
|
|
2419
|
-
/**
|
|
2420
|
-
* Gets information for a specific data source
|
|
2421
|
-
* @param dataSource - The ID of the data source
|
|
2422
|
-
* @returns Data source information
|
|
2423
|
-
* @throws PowerDataRuntimeError if data source is not found or service is not initialized
|
|
2424
|
-
*/
|
|
2425
|
-
async getDataSource(dataSource) {
|
|
2426
|
-
await this._ensureInitialized();
|
|
2427
|
-
const dataSourceInfo = this._dataSourcesInfo[dataSource];
|
|
2428
|
-
if (!dataSourceInfo) {
|
|
2429
|
-
const errorMessage = `Unable to find data source: ${dataSource} in data sources info.`;
|
|
2430
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourceNotFound, errorMessage);
|
|
2431
|
-
}
|
|
2432
|
-
return dataSourceInfo;
|
|
2433
|
-
}
|
|
2434
|
-
/**
|
|
2435
|
-
* Checks if a data source exists
|
|
2436
|
-
* @param dataSourceId - The ID of the data source to check
|
|
2437
|
-
* @returns True if the data source exists, false otherwise
|
|
2438
|
-
* @throws PowerDataRuntimeError if service is not initialized
|
|
2439
|
-
*/
|
|
2440
|
-
async hasDataSource(dataSource) {
|
|
2441
|
-
await this._ensureInitialized();
|
|
2442
|
-
return dataSource in this._dataSourcesInfo;
|
|
2443
|
-
}
|
|
2444
|
-
/**
|
|
2445
|
-
* Ensures the service is initialized
|
|
2446
|
-
* @throws PowerDataRuntimeError if service is not initialized
|
|
2447
|
-
*/
|
|
2448
|
-
async _ensureInitialized() {
|
|
2449
|
-
if (!this._isInitialized) {
|
|
2450
|
-
await this.initialize();
|
|
2451
|
-
}
|
|
2452
|
-
}
|
|
2453
|
-
/**
|
|
2454
|
-
* Gets user data sources from the provided data source schemas
|
|
2455
|
-
* @returns Promise resolving to array of data source information
|
|
2456
|
-
*/
|
|
2457
|
-
async _getUserDataSources() {
|
|
2458
|
-
const dataSourcesInfo = await this._powerDataSourcesInfoProvider.getDataSourcesInfo();
|
|
2459
|
-
return Promise.resolve(dataSourcesInfo);
|
|
2460
|
-
}
|
|
2461
|
-
};
|
|
2462
|
-
|
|
2463
|
-
var PowerDataRuntime = class {
|
|
2464
|
-
/**
|
|
2465
|
-
* Creates a new instance of PowerDataRuntime
|
|
2466
|
-
* @param params - Initialization parameters
|
|
2467
|
-
* @throws DataRuntimeError if initialization fails
|
|
2468
|
-
*/
|
|
2469
|
-
constructor(params) {
|
|
2470
|
-
__publicField(this, "_clientProvider");
|
|
2471
|
-
__publicField(this, "_dataSourceService");
|
|
2472
|
-
__publicField(this, "_dataOperations");
|
|
2473
|
-
__publicField(this, "_metadataOperations");
|
|
2474
|
-
__publicField(this, "_isInitialized");
|
|
2475
|
-
try {
|
|
2476
|
-
Log.createInstance(params.powerOperationExecutor);
|
|
2477
|
-
this._clientProvider = new RuntimeClientProvider(params.powerOperationExecutor);
|
|
2478
|
-
this._dataSourceService = new RuntimeDataSourceService(params.powerDataSourcesInfoProvider);
|
|
2479
|
-
this._isInitialized = false;
|
|
2480
|
-
this._initialize();
|
|
2481
|
-
} catch (error) {
|
|
2482
|
-
if (error instanceof Error) {
|
|
2483
|
-
Log.trackException(error);
|
|
2484
|
-
}
|
|
2485
|
-
throw error;
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
/**
|
|
2489
|
-
* Gets the Data operations interface
|
|
2490
|
-
* @throws PowerDataRuntimeError if operations are not initialized
|
|
2491
|
-
*/
|
|
2492
|
-
get Data() {
|
|
2493
|
-
this._ensureInitialized();
|
|
2494
|
-
if (!this._dataOperations) {
|
|
2495
|
-
this._dataOperations = this._createDataOperations();
|
|
2496
|
-
}
|
|
2497
|
-
return this._dataOperations;
|
|
2498
|
-
}
|
|
2499
|
-
/**
|
|
2500
|
-
* Gets the Metadata operations interface
|
|
2501
|
-
* @throws PowerDataRuntimeError if operations are not initialized
|
|
2502
|
-
*/
|
|
2503
|
-
get Metadata() {
|
|
2504
|
-
this._ensureInitialized();
|
|
2505
|
-
if (!this._metadataOperations) {
|
|
2506
|
-
this._metadataOperations = this._createMetadataOperations();
|
|
2507
|
-
}
|
|
2508
|
-
return this._metadataOperations;
|
|
2509
|
-
}
|
|
2510
|
-
/**
|
|
2511
|
-
* Ensures the PowerDataRuntime is initialized
|
|
2512
|
-
* @throws PowerDataRuntimeError if not initialized
|
|
2513
|
-
*/
|
|
2514
|
-
_ensureInitialized() {
|
|
2515
|
-
if (!this._isInitialized) {
|
|
2516
|
-
throw new PowerDataRuntimeError(ErrorCodes.OperationsNotInitialized);
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
/**
|
|
2520
|
-
* Initializes the PowerDataRuntime components
|
|
2521
|
-
* @throws PowerDataRuntimeError if initialization fails
|
|
2522
|
-
*/
|
|
2523
|
-
_initialize() {
|
|
2524
|
-
try {
|
|
2525
|
-
this._dataOperations = this._createDataOperations();
|
|
2526
|
-
this._metadataOperations = this._createMetadataOperations();
|
|
2527
|
-
this._isInitialized = true;
|
|
2528
|
-
} catch (error) {
|
|
2529
|
-
throw new PowerDataRuntimeError(ErrorCodes.InitializationFailed, getErrorMessage(error));
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2532
|
-
/**
|
|
2533
|
-
* Creates a new instance of DataOperations
|
|
2534
|
-
*/
|
|
2535
|
-
_createDataOperations() {
|
|
2536
|
-
const dataverseOperation = new DataverseDataOperationExecutor(this._clientProvider);
|
|
2537
|
-
const connectorOperation = new ConnectorDataOperationExecutor(this._clientProvider, this._dataSourceService);
|
|
2538
|
-
return new DefaultDataOperationOrchestrator(dataverseOperation, connectorOperation, this._dataSourceService);
|
|
2539
|
-
}
|
|
2540
|
-
/**
|
|
2541
|
-
* Creates a new instance of MetadataOperations
|
|
2542
|
-
*/
|
|
2543
|
-
_createMetadataOperations() {
|
|
2544
|
-
return new RuntimeMetadataOperations(this._clientProvider);
|
|
2545
|
-
}
|
|
2546
|
-
};
|
|
2547
|
-
|
|
2548
|
-
var powerDataRuntimeInstance;
|
|
2549
|
-
function getPowerDataRuntime(powerDataSourcesInfoProvider, powerOperationExecutor) {
|
|
2550
|
-
if (!powerDataRuntimeInstance) {
|
|
2551
|
-
powerDataRuntimeInstance = new PowerDataRuntime({
|
|
2552
|
-
powerDataSourcesInfoProvider,
|
|
2553
|
-
powerOperationExecutor
|
|
2554
|
-
});
|
|
2555
|
-
}
|
|
2556
|
-
return powerDataRuntimeInstance;
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
var _PowerDataSourcesInfoProvider = class _PowerDataSourcesInfoProvider {
|
|
2560
|
-
/**
|
|
2561
|
-
* Private constructor to enforce the singleton pattern.
|
|
2562
|
-
* @param dataSourcesInfo The data sources information to initialize the provider with.
|
|
2563
|
-
*/
|
|
2564
|
-
constructor(dataSourcesInfo) {
|
|
2565
|
-
__publicField(this, "dataSourcesInfo");
|
|
2566
|
-
this.dataSourcesInfo = dataSourcesInfo;
|
|
2567
|
-
}
|
|
2568
|
-
/**
|
|
2569
|
-
* Retrieves the singleton instance of PowerDataSourcesInfoProvider.
|
|
2570
|
-
* If the instance does not exist, it initializes it with the provided data sources info.
|
|
2571
|
-
*
|
|
2572
|
-
* @param dataSourcesInfo Optional parameter to initialize the instance if it doesn't exist.
|
|
2573
|
-
* @returns The singleton instance of PowerDataSourcesInfoProvider.
|
|
2574
|
-
* @throws Error if the instance is not initialized and no dataSourcesInfo is provided.
|
|
2575
|
-
*/
|
|
2576
|
-
static getInstance(dataSourcesInfo) {
|
|
2577
|
-
if (!this.instance) {
|
|
2578
|
-
if (!dataSourcesInfo) {
|
|
2579
|
-
throw new PowerDataRuntimeError(ErrorCodes.DataSourcesInfoNotFound);
|
|
2580
|
-
}
|
|
2581
|
-
this.instance = new _PowerDataSourcesInfoProvider(dataSourcesInfo);
|
|
2582
|
-
}
|
|
2583
|
-
return this.instance;
|
|
2584
|
-
}
|
|
2585
|
-
/**
|
|
2586
|
-
* Retrieves the data sources information.
|
|
2587
|
-
*
|
|
2588
|
-
* @returns A promise resolving to the data sources information.
|
|
2589
|
-
*/
|
|
2590
|
-
async getDataSourcesInfo() {
|
|
2591
|
-
return this.dataSourcesInfo;
|
|
2592
|
-
}
|
|
2593
|
-
};
|
|
2594
|
-
__publicField(_PowerDataSourcesInfoProvider, "instance", null);
|
|
2595
|
-
var PowerDataSourcesInfoProvider = _PowerDataSourcesInfoProvider;
|
|
2596
|
-
var powerDataSourcesInfoProvider_default = PowerDataSourcesInfoProvider;
|
|
2597
|
-
|
|
2598
|
-
var connectionsLoaded = false;
|
|
2599
|
-
async function loadConnections() {
|
|
2600
|
-
if (connectionsLoaded) {
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
connectionsLoaded = true;
|
|
2604
|
-
await loadNonCompositeConnectionsAsync();
|
|
2605
|
-
await resolveCompositeConnectionsAsync();
|
|
2606
|
-
}
|
|
2607
|
-
async function loadNonCompositeConnectionsAsync() {
|
|
2608
|
-
return executePluginAsync("AppPowerAppsClientPlugin", "loadNonCompositeConnectionsAsync", []);
|
|
2609
|
-
}
|
|
2610
|
-
async function resolveCompositeConnectionsAsync() {
|
|
2611
|
-
return executePluginAsync("AppPowerAppsClientPlugin", "resolveCompositeConnectionsAsync", []);
|
|
2612
|
-
}
|
|
2613
|
-
|
|
2614
|
-
var loadConnectionsPromise;
|
|
2615
|
-
var OperationExecutor = class {
|
|
2616
|
-
/**
|
|
2617
|
-
* Executes an operation using the plugin.
|
|
2618
|
-
* @param operationName The name of the operation.
|
|
2619
|
-
* @param action The action to perform.
|
|
2620
|
-
* @param params The parameters for the operation.
|
|
2621
|
-
* @returns A promise resolving to the operation result.
|
|
2622
|
-
*/
|
|
2623
|
-
async execute(operationName, action, params) {
|
|
2624
|
-
try {
|
|
2625
|
-
if (!loadConnectionsPromise) {
|
|
2626
|
-
loadConnectionsPromise = loadConnections();
|
|
2627
|
-
}
|
|
2628
|
-
await loadConnectionsPromise;
|
|
2629
|
-
const result = await executePluginAsync(operationName, action, params);
|
|
2630
|
-
return {
|
|
2631
|
-
success: true,
|
|
2632
|
-
data: result
|
|
2633
|
-
};
|
|
2634
|
-
} catch (error) {
|
|
2635
|
-
throw error;
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
};
|
|
2639
|
-
|
|
2640
|
-
var _executor;
|
|
2641
|
-
function getExecutor() {
|
|
2642
|
-
if (!_executor) {
|
|
2643
|
-
_executor = new OperationExecutor();
|
|
2644
|
-
}
|
|
2645
|
-
return _executor;
|
|
2646
|
-
}
|
|
2647
|
-
async function getPowerSdkInstance(dataSourcesInfo) {
|
|
2648
|
-
const executor = getExecutor();
|
|
2649
|
-
const provider = powerDataSourcesInfoProvider_default.getInstance(dataSourcesInfo);
|
|
2650
|
-
return getPowerDataRuntime(provider, executor);
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
|
-
async function createRecordAsync(dataSourcesInfo, tableName, record) {
|
|
2654
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.createRecordAsync(tableName, record);
|
|
2655
|
-
}
|
|
2656
|
-
|
|
2657
|
-
async function updateRecordAsync(dataSourcesInfo, tableName, recordId, changes) {
|
|
2658
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.updateRecordAsync(tableName, recordId, changes);
|
|
2659
|
-
}
|
|
2660
|
-
|
|
2661
|
-
async function deleteRecordAsync(dataSourcesInfo, tableName, recordId) {
|
|
2662
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.deleteRecordAsync(tableName, recordId);
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
|
-
async function retrieveRecordAsync(dataSourcesInfo, tableName, recordId, options) {
|
|
2666
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.retrieveRecordAsync(tableName, recordId, options);
|
|
2667
|
-
}
|
|
2668
|
-
|
|
2669
|
-
async function retrieveMultipleRecordsAsync(dataSourcesInfo, tableName, options) {
|
|
2670
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.retrieveMultipleRecordsAsync(tableName, options);
|
|
2671
|
-
}
|
|
2672
|
-
|
|
2673
|
-
async function executeAsync(dataSourcesInfo, operation) {
|
|
2674
|
-
return await (await getPowerSdkInstance(dataSourcesInfo)).Data.executeAsync(operation);
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2677
|
-
async function callActionAsync(dataSourcesInfo, actionName, params) {
|
|
2678
|
-
var sdkInstance = await getPowerSdkInstance(dataSourcesInfo);
|
|
2679
|
-
var orchestrator = sdkInstance.Data;
|
|
2680
|
-
var dvExecutor = orchestrator._dataverseOperation;
|
|
2681
|
-
var dataClient = await dvExecutor._getDataClient();
|
|
2682
|
-
var dbRefs = await dvExecutor.getDatabaseReferences();
|
|
2683
|
-
var sInstanceUrl = null;
|
|
2684
|
-
var sDatasetName = null;
|
|
2685
|
-
for (var sDbKey of Object.keys(dbRefs)) {
|
|
2686
|
-
var oDb = dbRefs[sDbKey];
|
|
2687
|
-
if (oDb.databaseDetails && oDb.databaseDetails.linkedEnvironmentMetadata) {
|
|
2688
|
-
sInstanceUrl = oDb.databaseDetails.linkedEnvironmentMetadata.instanceUrl;
|
|
2689
|
-
sDatasetName = oDb.databaseDetails.environmentName;
|
|
2690
|
-
break;
|
|
2691
|
-
}
|
|
2692
|
-
}
|
|
2693
|
-
if (!sInstanceUrl) {
|
|
2694
|
-
throw new Error("Cannot call unbound action: no Dataverse instance URL found. At least one Dataverse table must be registered.");
|
|
2695
|
-
}
|
|
2696
|
-
var sBaseUrl = sInstanceUrl.endsWith("/") ? sInstanceUrl : sInstanceUrl + "/";
|
|
2697
|
-
var sRequestUrl = sBaseUrl + "api/data/v9.0/" + actionName;
|
|
2698
|
-
var oResponse = await dataClient.createDataAsync(
|
|
2699
|
-
sRequestUrl,
|
|
2700
|
-
DataSources.Dataverse,
|
|
2701
|
-
actionName,
|
|
2702
|
-
params || {},
|
|
2703
|
-
{
|
|
2704
|
-
operationName: DataverseOperationName.CreateRecord,
|
|
2705
|
-
datasetName: sDatasetName,
|
|
2706
|
-
isDataVerseOperation: true
|
|
2707
|
-
}
|
|
2708
|
-
);
|
|
2709
|
-
return {
|
|
2710
|
-
success: oResponse.success,
|
|
2711
|
-
data: oResponse.data,
|
|
2712
|
-
error: oResponse.error
|
|
2713
|
-
};
|
|
2714
|
-
}
|
|
2715
|
-
|
|
2716
|
-
var _dataOperationExecutor;
|
|
2717
|
-
function getDataOperationExecutor() {
|
|
2718
|
-
return _dataOperationExecutor;
|
|
2719
|
-
}
|
|
2720
|
-
function setDataOperationExecutor(dataOperationExecutorOverride) {
|
|
2721
|
-
_dataOperationExecutor = dataOperationExecutorOverride;
|
|
2722
|
-
}
|
|
2723
|
-
function getClient(dataSourcesInfo) {
|
|
2724
|
-
return {
|
|
2725
|
-
createRecordAsync: (tableName, record) => {
|
|
2726
|
-
return createRecordAsync(dataSourcesInfo, tableName, record);
|
|
2727
|
-
},
|
|
2728
|
-
deleteRecordAsync: (tableName, recordId) => {
|
|
2729
|
-
return deleteRecordAsync(dataSourcesInfo, tableName, recordId);
|
|
2730
|
-
},
|
|
2731
|
-
executeAsync: (operation) => {
|
|
2732
|
-
return executeAsync(dataSourcesInfo, operation);
|
|
2733
|
-
},
|
|
2734
|
-
retrieveMultipleRecordsAsync: (tableName, options) => {
|
|
2735
|
-
return retrieveMultipleRecordsAsync(dataSourcesInfo, tableName, options);
|
|
2736
|
-
},
|
|
2737
|
-
retrieveRecordAsync: (tableName, recordId, options) => {
|
|
2738
|
-
return retrieveRecordAsync(dataSourcesInfo, tableName, recordId, options);
|
|
2739
|
-
},
|
|
2740
|
-
updateRecordAsync: (tableName, recordId, changes) => {
|
|
2741
|
-
return updateRecordAsync(dataSourcesInfo, tableName, recordId, changes);
|
|
2742
|
-
}
|
|
2743
|
-
};
|
|
2744
|
-
}
|
|
2745
|
-
|
|
2746
|
-
var MockDataOperationExecutor = class {
|
|
2747
|
-
constructor(data) {
|
|
2748
|
-
__publicField(this, "_dataStore");
|
|
2749
|
-
this._dataStore = data;
|
|
2750
|
-
}
|
|
2751
|
-
async createRecordAsync(tableName, data) {
|
|
2752
|
-
return {
|
|
2753
|
-
success: false,
|
|
2754
|
-
error: { message: "createRecordAsync is not supported by MockDataOperationExecutor" },
|
|
2755
|
-
data: null
|
|
2756
|
-
};
|
|
2757
|
-
}
|
|
2758
|
-
async updateRecordAsync(tableName, id, data) {
|
|
2759
|
-
return {
|
|
2760
|
-
success: false,
|
|
2761
|
-
error: { message: "updateRecordAsync is not supported by MockDataOperationExecutor" },
|
|
2762
|
-
data: null
|
|
2763
|
-
};
|
|
2764
|
-
}
|
|
2765
|
-
async deleteRecordAsync(tableName, id) {
|
|
2766
|
-
return {
|
|
2767
|
-
success: false,
|
|
2768
|
-
error: { message: "deleteRecordAsync is not supported by MockDataOperationExecutor" },
|
|
2769
|
-
data: void 0
|
|
2770
|
-
};
|
|
2771
|
-
}
|
|
2772
|
-
async retrieveRecordAsync(tableName, id, options) {
|
|
2773
|
-
if (!this._dataStore[tableName]) {
|
|
2774
|
-
return {
|
|
2775
|
-
success: false,
|
|
2776
|
-
error: { message: `table <${tableName}> not found` },
|
|
2777
|
-
data: null
|
|
2778
|
-
};
|
|
2779
|
-
}
|
|
2780
|
-
const record = this._dataStore[tableName][id];
|
|
2781
|
-
if (!record) {
|
|
2782
|
-
return {
|
|
2783
|
-
success: false,
|
|
2784
|
-
error: { message: `record with id "${id}" not found in table <${tableName}>` },
|
|
2785
|
-
data: null
|
|
2786
|
-
};
|
|
2787
|
-
}
|
|
2788
|
-
return {
|
|
2789
|
-
success: true,
|
|
2790
|
-
data: record
|
|
2791
|
-
};
|
|
2792
|
-
}
|
|
2793
|
-
async retrieveMultipleRecordsAsync(tableName, options) {
|
|
2794
|
-
if (!this._dataStore[tableName]) {
|
|
2795
|
-
return {
|
|
2796
|
-
success: false,
|
|
2797
|
-
error: { message: `table <${tableName}> not found` },
|
|
2798
|
-
data: []
|
|
2799
|
-
};
|
|
2800
|
-
}
|
|
2801
|
-
return {
|
|
2802
|
-
success: true,
|
|
2803
|
-
data: Object.values(this._dataStore[tableName])
|
|
2804
|
-
};
|
|
2805
|
-
}
|
|
2806
|
-
async executeAsync(operation) {
|
|
2807
|
-
return {
|
|
2808
|
-
success: false,
|
|
2809
|
-
error: { message: "executeAsync is not supported by MockDataOperationExecutor" },
|
|
2810
|
-
data: null
|
|
2811
|
-
};
|
|
2812
|
-
}
|
|
2813
|
-
};
|
|
2814
|
-
function createMockDataExecutor(data) {
|
|
2815
|
-
return new MockDataOperationExecutor(data);
|
|
2816
|
-
}
|
|
2817
|
-
|
|
2818
|
-
var entityClusterModeEnum = {
|
|
2819
|
-
0: "Partitioned",
|
|
2820
|
-
1: "Replicated",
|
|
2821
|
-
2: "Local"
|
|
2822
|
-
};
|
|
2823
|
-
function getEntityClusterModeName(value) {
|
|
2824
|
-
return entityClusterModeEnum[value];
|
|
2825
|
-
}
|
|
2826
|
-
var ownershipTypeEnum = {
|
|
2827
|
-
0: "None",
|
|
2828
|
-
1: "UserOwned",
|
|
2829
|
-
2: "TeamOwned",
|
|
2830
|
-
4: "BusinessOwned",
|
|
2831
|
-
8: "OrganizationOwned",
|
|
2832
|
-
16: "BusinessParented",
|
|
2833
|
-
32: "Filtered"
|
|
2834
|
-
};
|
|
2835
|
-
function getOwnershipTypeName(value) {
|
|
2836
|
-
return ownershipTypeEnum[value];
|
|
2837
|
-
}
|
|
2838
|
-
var privilegeTypeEnum = {
|
|
2839
|
-
0: "None",
|
|
2840
|
-
1: "Create",
|
|
2841
|
-
2: "Read",
|
|
2842
|
-
3: "Write",
|
|
2843
|
-
4: "Delete",
|
|
2844
|
-
5: "Assign",
|
|
2845
|
-
6: "Share",
|
|
2846
|
-
7: "Append",
|
|
2847
|
-
8: "AppendTo"
|
|
2848
|
-
};
|
|
2849
|
-
function getPrivilegeTypeName(value) {
|
|
2850
|
-
return privilegeTypeEnum[value];
|
|
2851
|
-
}
|
|
2852
|
-
var attributeTypeCodeEnum = {
|
|
2853
|
-
0: "Boolean",
|
|
2854
|
-
1: "Customer",
|
|
2855
|
-
2: "DateTime",
|
|
2856
|
-
3: "Decimal",
|
|
2857
|
-
4: "Double",
|
|
2858
|
-
5: "Integer",
|
|
2859
|
-
6: "Lookup",
|
|
2860
|
-
7: "Memo",
|
|
2861
|
-
8: "Money",
|
|
2862
|
-
9: "Owner",
|
|
2863
|
-
10: "PartyList",
|
|
2864
|
-
11: "Picklist",
|
|
2865
|
-
12: "State",
|
|
2866
|
-
13: "Status",
|
|
2867
|
-
14: "String",
|
|
2868
|
-
15: "Uniqueidentifier",
|
|
2869
|
-
16: "CalendarRules",
|
|
2870
|
-
17: "Virtual",
|
|
2871
|
-
18: "BigInt",
|
|
2872
|
-
19: "ManagedProperty",
|
|
2873
|
-
20: "EntityName"
|
|
2874
|
-
};
|
|
2875
|
-
function getAttributeTypeCodeName(value) {
|
|
2876
|
-
return attributeTypeCodeEnum[value];
|
|
2877
|
-
}
|
|
2878
|
-
var attributeRequiredLevelEnum = {
|
|
2879
|
-
0: "None",
|
|
2880
|
-
1: "SystemRequired",
|
|
2881
|
-
2: "ApplicationRequired",
|
|
2882
|
-
3: "Recommended"
|
|
2883
|
-
};
|
|
2884
|
-
function getAttributeRequiredLevelName(value) {
|
|
2885
|
-
return attributeRequiredLevelEnum[value];
|
|
2886
|
-
}
|
|
2887
|
-
var relationshipTypeEnum = {
|
|
2888
|
-
0: "OneToManyRelationship",
|
|
2889
|
-
1: "ManyToManyRelationship"
|
|
2890
|
-
};
|
|
2891
|
-
function getRelationshipTypeName(value) {
|
|
2892
|
-
return relationshipTypeEnum[value];
|
|
2893
|
-
}
|
|
2894
|
-
var securityTypesEnum = {
|
|
2895
|
-
0: "None",
|
|
2896
|
-
1: "Append",
|
|
2897
|
-
2: "ParentChild",
|
|
2898
|
-
8: "Pointer",
|
|
2899
|
-
16: "Inheritance"
|
|
2900
|
-
// The referencing entity record inherits security from the referenced security record.
|
|
2901
|
-
};
|
|
2902
|
-
function getSecurityTypesName(value) {
|
|
2903
|
-
return securityTypesEnum[value];
|
|
2904
|
-
}
|
|
2905
|
-
var associatedMenuBehaviorEnum = {
|
|
2906
|
-
0: "UseCollectionName",
|
|
2907
|
-
1: "UseLabel",
|
|
2908
|
-
2: "DoNotDisplay"
|
|
2909
|
-
};
|
|
2910
|
-
function getAssociatedMenuBehaviorName(value) {
|
|
2911
|
-
return associatedMenuBehaviorEnum[value];
|
|
2912
|
-
}
|
|
2913
|
-
var associatedMenuGroupEnum = {
|
|
2914
|
-
0: "Details",
|
|
2915
|
-
1: "Sales",
|
|
2916
|
-
2: "Service",
|
|
2917
|
-
3: "Marketing"
|
|
2918
|
-
};
|
|
2919
|
-
function getAssociatedMenuGroupName(value) {
|
|
2920
|
-
return associatedMenuGroupEnum[value];
|
|
2921
|
-
}
|
|
2922
|
-
var cascadeTypeEnum = {
|
|
2923
|
-
0: "NoCascade",
|
|
2924
|
-
1: "Cascade",
|
|
2925
|
-
2: "Active",
|
|
2926
|
-
3: "UserOwned",
|
|
2927
|
-
4: "RemoveLink",
|
|
2928
|
-
5: "Restrict"
|
|
2929
|
-
// Prevent the Referenced entity record from being deleted when referencing entities exist.
|
|
2930
|
-
};
|
|
2931
|
-
function getCascadeTypeName(value) {
|
|
2932
|
-
return cascadeTypeEnum[value];
|
|
2933
|
-
}
|
|
2934
|
-
export {
|
|
2935
|
-
callActionAsync,
|
|
2936
|
-
createMockDataExecutor,
|
|
2937
|
-
getAssociatedMenuBehaviorName,
|
|
2938
|
-
getAssociatedMenuGroupName,
|
|
2939
|
-
getAttributeRequiredLevelName,
|
|
2940
|
-
getAttributeTypeCodeName,
|
|
2941
|
-
getCascadeTypeName,
|
|
2942
|
-
getClient,
|
|
2943
|
-
getContext,
|
|
2944
|
-
getEntityClusterModeName,
|
|
2945
|
-
getOwnershipTypeName,
|
|
2946
|
-
getPrivilegeTypeName,
|
|
2947
|
-
getRelationshipTypeName,
|
|
2948
|
-
getSecurityTypesName,
|
|
2949
|
-
initializeLogger,
|
|
2950
|
-
setConfig,
|
|
2951
|
-
setDataOperationExecutor
|
|
2952
|
-
};
|