pptb-standard-sample-tool 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/headless.js CHANGED
@@ -1,5 +1,43 @@
1
1
  "use strict";
2
2
  /// <reference types="@pptb/types" />
3
+ function getDataverseApi() {
4
+ const runtime = globalThis;
5
+ const api = runtime.dataverseAPI ?? runtime.window?.dataverseAPI;
6
+ if (!api) {
7
+ throw new Error("Dataverse API is not available in this runtime context");
8
+ }
9
+ return api;
10
+ }
11
+ function sanitizeEntityName(value) {
12
+ const trimmed = value.trim();
13
+ if (!/^[A-Za-z0-9_]+$/.test(trimmed)) {
14
+ throw new Error("Invalid entity name. Only letters, numbers, and underscores are allowed.");
15
+ }
16
+ return trimmed.toLowerCase();
17
+ }
18
+ async function resolveEntityAttributes(api, entityName) {
19
+ try {
20
+ const metadata = await api.getEntityMetadata(entityName, true, ["PrimaryIdAttribute", "PrimaryNameAttribute"]);
21
+ const idAttribute = typeof metadata.PrimaryIdAttribute === "string" && metadata.PrimaryIdAttribute.trim().length > 0 ? metadata.PrimaryIdAttribute : `${entityName}id`;
22
+ const nameAttribute = typeof metadata.PrimaryNameAttribute === "string" && metadata.PrimaryNameAttribute.trim().length > 0 ? metadata.PrimaryNameAttribute : undefined;
23
+ return { idAttribute, nameAttribute };
24
+ }
25
+ catch {
26
+ // Fallback keeps headless invocation resilient when metadata lookup is unavailable.
27
+ return {
28
+ idAttribute: `${entityName}id`,
29
+ nameAttribute: "name",
30
+ };
31
+ }
32
+ }
33
+ function buildFetchXml(entityName, idAttribute, nameAttribute) {
34
+ const attributeLines = [
35
+ ` <attribute name="${idAttribute}" />`,
36
+ ...(nameAttribute ? [` <attribute name="${nameAttribute}" />`] : []),
37
+ ];
38
+ const orderLine = nameAttribute ? `\n <order attribute="${nameAttribute}" />` : "";
39
+ return `<fetch top="10">\n <entity name="${entityName}">\n${attributeLines.join("\n")}${orderLine}\n </entity>\n</fetch>`;
40
+ }
3
41
  /**
4
42
  * Headless invocation handler.
5
43
  *
@@ -8,26 +46,30 @@
8
46
  */
9
47
  async function invokeHeadless(input, context) {
10
48
  const { toolId, toolName, invocationMode, authToken, updateProgress, logger } = context;
49
+ const dataverseApi = getDataverseApi();
11
50
  logger.info(`Starting headless run for ${toolName} (${toolId}) in mode ${invocationMode}`);
12
51
  updateProgress(10, "validating input");
13
- const entityName = typeof input.entityName === "string" && input.entityName.trim() !== "" ? input.entityName.trim() : "account";
52
+ const entityName = sanitizeEntityName(typeof input.entityName === "string" && input.entityName.trim() !== "" ? input.entityName : "account");
14
53
  if (authToken) {
15
54
  updateProgress(40, "auth token received");
16
55
  }
17
56
  else {
18
57
  updateProgress(40, "running without auth token");
19
58
  }
20
- updateProgress(80, "building FetchXML");
21
- const fetchXml = `<fetch top="10">
22
- <entity name="${entityName}">
23
- <attribute name="name" />
24
- <attribute name="${entityName}id" />
25
- <order attribute="name" />
26
- </entity>
27
- </fetch>`;
59
+ updateProgress(55, "resolving entity metadata");
60
+ const { idAttribute, nameAttribute } = await resolveEntityAttributes(dataverseApi, entityName);
61
+ updateProgress(75, "building FetchXML");
62
+ const fetchXml = buildFetchXml(entityName, idAttribute, nameAttribute);
63
+ updateProgress(90, "executing FetchXML query");
64
+ const result = await dataverseApi.fetchXmlQuery(fetchXml);
28
65
  updateProgress(100, "done");
29
- logger.info(`Headless run complete for entity: ${entityName}`);
30
- return { fetchXml };
66
+ logger.info(`Headless run complete for entity: ${entityName}. Returned ${result.value.length} record(s).`);
67
+ return {
68
+ entityName,
69
+ fetchXml,
70
+ recordCount: result.value.length,
71
+ records: result.value,
72
+ };
31
73
  }
32
74
  module.exports = {
33
75
  invokeHeadless,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pptb-standard-sample-tool",
3
- "version": "1.2.4",
3
+ "version": "1.2.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pptb-standard-sample-tool",
9
- "version": "1.2.4",
9
+ "version": "1.2.8",
10
10
  "license": "GPL-3.0",
11
11
  "devDependencies": {
12
12
  "@pptb/types": "^1.2.4-beta.4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptb-standard-sample-tool",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "displayName": "HTML Sample Tool",
5
5
  "description": "A sample Power Platform ToolBox tool built with HTML, CSS, and TypeScript",
6
6
  "main": "index.html",
package/pptb.config.json CHANGED
@@ -13,8 +13,17 @@
13
13
  },
14
14
  "returnTopic": {
15
15
  "properties": {
16
+ "entityName": {
17
+ "type": "string"
18
+ },
16
19
  "fetchXml": {
17
20
  "type": "string"
21
+ },
22
+ "recordCount": {
23
+ "type": "number"
24
+ },
25
+ "records": {
26
+ "type": "array"
18
27
  }
19
28
  }
20
29
  }