@arbium/enterprise-agent-connect 0.0.0-stage → 0.1.2-dev.d2aa5ca
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/LICENSE +202 -0
- package/README.md +264 -2
- package/dist/connectors/dell-techdirect/connector.json +39 -0
- package/dist/connectors/dell-techdirect/index.d.ts +8 -0
- package/dist/connectors/dell-techdirect/index.js +7 -0
- package/dist/connectors/dell-techdirect/index.js.map +1 -0
- package/dist/connectors/dell-techdirect/tools.d.ts +2 -0
- package/dist/connectors/dell-techdirect/tools.js +49 -0
- package/dist/connectors/dell-techdirect/tools.js.map +1 -0
- package/dist/connectors/dell-techdirect/vendor.d.ts +6 -0
- package/dist/connectors/dell-techdirect/vendor.js +57 -0
- package/dist/connectors/dell-techdirect/vendor.js.map +1 -0
- package/dist/connectors/dynamics-365/connector.json +213 -0
- package/dist/connectors/dynamics-365/index.d.ts +11 -0
- package/dist/connectors/dynamics-365/index.js +10 -0
- package/dist/connectors/dynamics-365/index.js.map +1 -0
- package/dist/connectors/dynamics-365/tools.d.ts +35 -0
- package/dist/connectors/dynamics-365/tools.js +806 -0
- package/dist/connectors/dynamics-365/tools.js.map +1 -0
- package/dist/connectors/dynamics-365/vendor.d.ts +9 -0
- package/dist/connectors/dynamics-365/vendor.js +110 -0
- package/dist/connectors/dynamics-365/vendor.js.map +1 -0
- package/dist/connectors/entra/connector.json +85 -0
- package/dist/connectors/entra/index.d.ts +2 -0
- package/dist/connectors/entra/index.js +4 -0
- package/dist/connectors/entra/index.js.map +1 -0
- package/dist/connectors/entra/tools.d.ts +14 -0
- package/dist/connectors/entra/tools.js +262 -0
- package/dist/connectors/entra/tools.js.map +1 -0
- package/dist/connectors/fedex/connector.json +118 -0
- package/dist/connectors/fedex/index.d.ts +8 -0
- package/dist/connectors/fedex/index.js +7 -0
- package/dist/connectors/fedex/index.js.map +1 -0
- package/dist/connectors/fedex/tools.d.ts +3 -0
- package/dist/connectors/fedex/tools.js +152 -0
- package/dist/connectors/fedex/tools.js.map +1 -0
- package/dist/connectors/fedex/vendor.d.ts +7 -0
- package/dist/connectors/fedex/vendor.js +98 -0
- package/dist/connectors/fedex/vendor.js.map +1 -0
- package/dist/connectors/gong/connector.json +127 -0
- package/dist/connectors/gong/index.d.ts +8 -0
- package/dist/connectors/gong/index.js +7 -0
- package/dist/connectors/gong/index.js.map +1 -0
- package/dist/connectors/gong/tools.d.ts +8 -0
- package/dist/connectors/gong/tools.js +424 -0
- package/dist/connectors/gong/tools.js.map +1 -0
- package/dist/connectors/gong/vendor.d.ts +4 -0
- package/dist/connectors/gong/vendor.js +97 -0
- package/dist/connectors/gong/vendor.js.map +1 -0
- package/dist/connectors/http/index.d.ts +38 -0
- package/dist/connectors/http/index.js +322 -0
- package/dist/connectors/http/index.js.map +1 -0
- package/dist/connectors/intune/connector.json +106 -0
- package/dist/connectors/intune/index.d.ts +2 -0
- package/dist/connectors/intune/index.js +4 -0
- package/dist/connectors/intune/index.js.map +1 -0
- package/dist/connectors/intune/tools.d.ts +12 -0
- package/dist/connectors/intune/tools.js +416 -0
- package/dist/connectors/intune/tools.js.map +1 -0
- package/dist/connectors/jamf/connector.json +182 -0
- package/dist/connectors/jamf/index.d.ts +8 -0
- package/dist/connectors/jamf/index.js +7 -0
- package/dist/connectors/jamf/index.js.map +1 -0
- package/dist/connectors/jamf/tools.d.ts +7 -0
- package/dist/connectors/jamf/tools.js +659 -0
- package/dist/connectors/jamf/tools.js.map +1 -0
- package/dist/connectors/jamf/vendor.d.ts +5 -0
- package/dist/connectors/jamf/vendor.js +66 -0
- package/dist/connectors/jamf/vendor.js.map +1 -0
- package/dist/connectors/jira/connector.json +272 -0
- package/dist/connectors/jira/index.d.ts +8 -0
- package/dist/connectors/jira/index.js +7 -0
- package/dist/connectors/jira/index.js.map +1 -0
- package/dist/connectors/jira/jql.d.ts +4 -0
- package/dist/connectors/jira/jql.js +67 -0
- package/dist/connectors/jira/jql.js.map +1 -0
- package/dist/connectors/jira/tools.d.ts +3 -0
- package/dist/connectors/jira/tools.js +464 -0
- package/dist/connectors/jira/tools.js.map +1 -0
- package/dist/connectors/jira/vendor.d.ts +3 -0
- package/dist/connectors/jira/vendor.js +94 -0
- package/dist/connectors/jira/vendor.js.map +1 -0
- package/dist/connectors/microsoft/client.d.ts +58 -0
- package/dist/connectors/microsoft/client.js +434 -0
- package/dist/connectors/microsoft/client.js.map +1 -0
- package/dist/connectors/microsoft/provider.json +118 -0
- package/dist/connectors/netsuite/connector.json +315 -0
- package/dist/connectors/netsuite/index.d.ts +8 -0
- package/dist/connectors/netsuite/index.js +7 -0
- package/dist/connectors/netsuite/index.js.map +1 -0
- package/dist/connectors/netsuite/tools.d.ts +24 -0
- package/dist/connectors/netsuite/tools.js +447 -0
- package/dist/connectors/netsuite/tools.js.map +1 -0
- package/dist/connectors/netsuite/vendor.d.ts +26 -0
- package/dist/connectors/netsuite/vendor.js +248 -0
- package/dist/connectors/netsuite/vendor.js.map +1 -0
- package/dist/connectors/odata/index.d.ts +36 -0
- package/dist/connectors/odata/index.js +460 -0
- package/dist/connectors/odata/index.js.map +1 -0
- package/dist/connectors/okta/connector.json +193 -0
- package/dist/connectors/okta/index.d.ts +8 -0
- package/dist/connectors/okta/index.js +7 -0
- package/dist/connectors/okta/index.js.map +1 -0
- package/dist/connectors/okta/tools.d.ts +6 -0
- package/dist/connectors/okta/tools.js +429 -0
- package/dist/connectors/okta/tools.js.map +1 -0
- package/dist/connectors/okta/vendor.d.ts +14 -0
- package/dist/connectors/okta/vendor.js +203 -0
- package/dist/connectors/okta/vendor.js.map +1 -0
- package/dist/connectors/outlook-calendar/connector.json +136 -0
- package/dist/connectors/outlook-calendar/index.d.ts +2 -0
- package/dist/connectors/outlook-calendar/index.js +4 -0
- package/dist/connectors/outlook-calendar/index.js.map +1 -0
- package/dist/connectors/outlook-calendar/tools.d.ts +65 -0
- package/dist/connectors/outlook-calendar/tools.js +398 -0
- package/dist/connectors/outlook-calendar/tools.js.map +1 -0
- package/dist/connectors/outlook-mail/connector.json +154 -0
- package/dist/connectors/outlook-mail/index.d.ts +2 -0
- package/dist/connectors/outlook-mail/index.js +4 -0
- package/dist/connectors/outlook-mail/index.js.map +1 -0
- package/dist/connectors/outlook-mail/tools.d.ts +8 -0
- package/dist/connectors/outlook-mail/tools.js +236 -0
- package/dist/connectors/outlook-mail/tools.js.map +1 -0
- package/dist/connectors/salesforce/connector.json +122 -0
- package/dist/connectors/salesforce/index.d.ts +8 -0
- package/dist/connectors/salesforce/index.js +7 -0
- package/dist/connectors/salesforce/index.js.map +1 -0
- package/dist/connectors/salesforce/soql.d.ts +3 -0
- package/dist/connectors/salesforce/soql.js +60 -0
- package/dist/connectors/salesforce/soql.js.map +1 -0
- package/dist/connectors/salesforce/tools.d.ts +9 -0
- package/dist/connectors/salesforce/tools.js +234 -0
- package/dist/connectors/salesforce/tools.js.map +1 -0
- package/dist/connectors/salesforce/vendor.d.ts +3 -0
- package/dist/connectors/salesforce/vendor.js +107 -0
- package/dist/connectors/salesforce/vendor.js.map +1 -0
- package/dist/connectors/sap-s4hana/connector.json +263 -0
- package/dist/connectors/sap-s4hana/index.d.ts +8 -0
- package/dist/connectors/sap-s4hana/index.js +7 -0
- package/dist/connectors/sap-s4hana/index.js.map +1 -0
- package/dist/connectors/sap-s4hana/tools.d.ts +4 -0
- package/dist/connectors/sap-s4hana/tools.js +761 -0
- package/dist/connectors/sap-s4hana/tools.js.map +1 -0
- package/dist/connectors/sap-s4hana/vendor.d.ts +5 -0
- package/dist/connectors/sap-s4hana/vendor.js +176 -0
- package/dist/connectors/sap-s4hana/vendor.js.map +1 -0
- package/dist/connectors/servicenow/connector.json +228 -0
- package/dist/connectors/servicenow/index.d.ts +8 -0
- package/dist/connectors/servicenow/index.js +7 -0
- package/dist/connectors/servicenow/index.js.map +1 -0
- package/dist/connectors/servicenow/tools.d.ts +4 -0
- package/dist/connectors/servicenow/tools.js +884 -0
- package/dist/connectors/servicenow/tools.js.map +1 -0
- package/dist/connectors/servicenow/vendor.d.ts +4 -0
- package/dist/connectors/servicenow/vendor.js +109 -0
- package/dist/connectors/servicenow/vendor.js.map +1 -0
- package/dist/connectors/sharepoint-files/connector.json +194 -0
- package/dist/connectors/sharepoint-files/excel.d.ts +16 -0
- package/dist/connectors/sharepoint-files/excel.js +300 -0
- package/dist/connectors/sharepoint-files/excel.js.map +1 -0
- package/dist/connectors/sharepoint-files/index.d.ts +11 -0
- package/dist/connectors/sharepoint-files/index.js +12 -0
- package/dist/connectors/sharepoint-files/index.js.map +1 -0
- package/dist/connectors/sharepoint-files/tools.d.ts +52 -0
- package/dist/connectors/sharepoint-files/tools.js +365 -0
- package/dist/connectors/sharepoint-files/tools.js.map +1 -0
- package/dist/connectors/sharepoint-files/vendor.d.ts +11 -0
- package/dist/connectors/sharepoint-files/vendor.js +167 -0
- package/dist/connectors/sharepoint-files/vendor.js.map +1 -0
- package/dist/connectors/slack/connector.json +148 -0
- package/dist/connectors/slack/index.d.ts +8 -0
- package/dist/connectors/slack/index.js +7 -0
- package/dist/connectors/slack/index.js.map +1 -0
- package/dist/connectors/slack/tools.d.ts +3 -0
- package/dist/connectors/slack/tools.js +355 -0
- package/dist/connectors/slack/tools.js.map +1 -0
- package/dist/connectors/slack/vendor.d.ts +17 -0
- package/dist/connectors/slack/vendor.js +195 -0
- package/dist/connectors/slack/vendor.js.map +1 -0
- package/dist/connectors/soap/index.d.ts +19 -0
- package/dist/connectors/soap/index.js +248 -0
- package/dist/connectors/soap/index.js.map +1 -0
- package/dist/connectors/soap/xml.d.ts +12 -0
- package/dist/connectors/soap/xml.js +126 -0
- package/dist/connectors/soap/xml.js.map +1 -0
- package/dist/connectors/sql/engines.d.ts +58 -0
- package/dist/connectors/sql/engines.js +292 -0
- package/dist/connectors/sql/engines.js.map +1 -0
- package/dist/connectors/sql/index.d.ts +19 -0
- package/dist/connectors/sql/index.js +212 -0
- package/dist/connectors/sql/index.js.map +1 -0
- package/dist/connectors/teams/connector.json +298 -0
- package/dist/connectors/teams/index.d.ts +2 -0
- package/dist/connectors/teams/index.js +5 -0
- package/dist/connectors/teams/index.js.map +1 -0
- package/dist/connectors/teams/tools.d.ts +2 -0
- package/dist/connectors/teams/tools.js +391 -0
- package/dist/connectors/teams/tools.js.map +1 -0
- package/dist/connectors/workday/connector.json +186 -0
- package/dist/connectors/workday/index.d.ts +8 -0
- package/dist/connectors/workday/index.js +7 -0
- package/dist/connectors/workday/index.js.map +1 -0
- package/dist/connectors/workday/tools.d.ts +33 -0
- package/dist/connectors/workday/tools.js +410 -0
- package/dist/connectors/workday/tools.js.map +1 -0
- package/dist/connectors/workday/vendor.d.ts +18 -0
- package/dist/connectors/workday/vendor.js +195 -0
- package/dist/connectors/workday/vendor.js.map +1 -0
- package/dist/packages/connector-kit/src/branding.d.ts +57 -0
- package/dist/packages/connector-kit/src/branding.js +102 -0
- package/dist/packages/connector-kit/src/branding.js.map +1 -0
- package/dist/packages/connector-kit/src/certificate.d.ts +19 -0
- package/dist/packages/connector-kit/src/certificate.js +84 -0
- package/dist/packages/connector-kit/src/certificate.js.map +1 -0
- package/dist/packages/connector-kit/src/common.d.ts +40 -0
- package/dist/packages/connector-kit/src/common.js +107 -0
- package/dist/packages/connector-kit/src/common.js.map +1 -0
- package/dist/packages/connector-kit/src/connector.d.ts +1346 -0
- package/dist/packages/connector-kit/src/connector.js +1034 -0
- package/dist/packages/connector-kit/src/connector.js.map +1 -0
- package/dist/packages/connector-kit/src/index.d.ts +5 -0
- package/dist/packages/connector-kit/src/index.js +5 -0
- package/dist/packages/connector-kit/src/index.js.map +1 -0
- package/dist/packages/connector-kit/src/oauth.d.ts +15 -0
- package/dist/packages/connector-kit/src/oauth.js +96 -0
- package/dist/packages/connector-kit/src/oauth.js.map +1 -0
- package/dist/packages/connector-kit/src/types.d.ts +85 -0
- package/dist/packages/connector-kit/src/types.js +20 -0
- package/dist/packages/connector-kit/src/types.js.map +1 -0
- package/dist/packages/server/migrations/0001_tables.sql +268 -0
- package/dist/packages/server/migrations/0002_organizations.sql +72 -0
- package/dist/packages/server/migrations/0003_drop_unused.sql +3 -0
- package/dist/packages/server/migrations/0004_trigger_runners.sql +15 -0
- package/dist/packages/server/migrations/0005_run_runner.sql +3 -0
- package/dist/packages/server/migrations/0006_approvals.sql +36 -0
- package/dist/packages/server/migrations/0007_app_events.sql +110 -0
- package/dist/packages/server/migrations/rollback/to-legacy.sql +90 -0
- package/dist/packages/server/src/api.d.ts +3714 -0
- package/dist/packages/server/src/api.js +818 -0
- package/dist/packages/server/src/api.js.map +1 -0
- package/dist/packages/server/src/app.d.ts +23 -0
- package/dist/packages/server/src/app.js +467 -0
- package/dist/packages/server/src/app.js.map +1 -0
- package/dist/packages/server/src/builtin.d.ts +4 -0
- package/dist/packages/server/src/builtin.js +42 -0
- package/dist/packages/server/src/builtin.js.map +1 -0
- package/dist/packages/server/src/consent.d.ts +27 -0
- package/dist/packages/server/src/consent.js +36 -0
- package/dist/packages/server/src/consent.js.map +1 -0
- package/dist/packages/server/src/events/admin.d.ts +156 -0
- package/dist/packages/server/src/events/admin.js +255 -0
- package/dist/packages/server/src/events/admin.js.map +1 -0
- package/dist/packages/server/src/events/deliver.d.ts +43 -0
- package/dist/packages/server/src/events/deliver.js +129 -0
- package/dist/packages/server/src/events/deliver.js.map +1 -0
- package/dist/packages/server/src/events/runtime.d.ts +28 -0
- package/dist/packages/server/src/events/runtime.js +397 -0
- package/dist/packages/server/src/events/runtime.js.map +1 -0
- package/dist/packages/server/src/events/store.d.ts +172 -0
- package/dist/packages/server/src/events/store.js +275 -0
- package/dist/packages/server/src/events/store.js.map +1 -0
- package/dist/packages/server/src/index.d.ts +40 -0
- package/dist/packages/server/src/index.js +185 -0
- package/dist/packages/server/src/index.js.map +1 -0
- package/dist/packages/server/src/migrate.d.ts +11 -0
- package/dist/packages/server/src/migrate.js +134 -0
- package/dist/packages/server/src/migrate.js.map +1 -0
- package/dist/packages/server/src/openapi.d.ts +4 -0
- package/dist/packages/server/src/openapi.js +101 -0
- package/dist/packages/server/src/openapi.js.map +1 -0
- package/dist/packages/server/src/queue.d.ts +10 -0
- package/dist/packages/server/src/queue.js +45 -0
- package/dist/packages/server/src/queue.js.map +1 -0
- package/dist/packages/server/src/secrets.d.ts +19 -0
- package/dist/packages/server/src/secrets.js +76 -0
- package/dist/packages/server/src/secrets.js.map +1 -0
- package/dist/packages/server/src/server.d.ts +1 -0
- package/dist/packages/server/src/server.js +82 -0
- package/dist/packages/server/src/server.js.map +1 -0
- package/dist/packages/server/src/service.d.ts +760 -0
- package/dist/packages/server/src/service.js +918 -0
- package/dist/packages/server/src/service.js.map +1 -0
- package/dist/packages/server/src/store.d.ts +158 -0
- package/dist/packages/server/src/store.js +415 -0
- package/dist/packages/server/src/store.js.map +1 -0
- package/dist/packages/server/src/teams/activity.d.ts +123 -0
- package/dist/packages/server/src/teams/activity.js +188 -0
- package/dist/packages/server/src/teams/activity.js.map +1 -0
- package/dist/packages/server/src/teams/admin.d.ts +335 -0
- package/dist/packages/server/src/teams/admin.js +699 -0
- package/dist/packages/server/src/teams/admin.js.map +1 -0
- package/dist/packages/server/src/teams/approval.d.ts +57 -0
- package/dist/packages/server/src/teams/approval.js +118 -0
- package/dist/packages/server/src/teams/approval.js.map +1 -0
- package/dist/packages/server/src/teams/bot.d.ts +25 -0
- package/dist/packages/server/src/teams/bot.js +124 -0
- package/dist/packages/server/src/teams/bot.js.map +1 -0
- package/dist/packages/server/src/teams/claude.d.ts +46 -0
- package/dist/packages/server/src/teams/claude.js +165 -0
- package/dist/packages/server/src/teams/claude.js.map +1 -0
- package/dist/packages/server/src/teams/jwt.d.ts +17 -0
- package/dist/packages/server/src/teams/jwt.js +121 -0
- package/dist/packages/server/src/teams/jwt.js.map +1 -0
- package/dist/packages/server/src/teams/package.d.ts +79 -0
- package/dist/packages/server/src/teams/package.js +319 -0
- package/dist/packages/server/src/teams/package.js.map +1 -0
- package/dist/packages/server/src/teams/provision.d.ts +84 -0
- package/dist/packages/server/src/teams/provision.js +505 -0
- package/dist/packages/server/src/teams/provision.js.map +1 -0
- package/dist/packages/server/src/teams/runner.d.ts +80 -0
- package/dist/packages/server/src/teams/runner.js +187 -0
- package/dist/packages/server/src/teams/runner.js.map +1 -0
- package/dist/packages/server/src/teams/runtime.d.ts +91 -0
- package/dist/packages/server/src/teams/runtime.js +679 -0
- package/dist/packages/server/src/teams/runtime.js.map +1 -0
- package/dist/packages/server/src/teams/store.d.ts +233 -0
- package/dist/packages/server/src/teams/store.js +507 -0
- package/dist/packages/server/src/teams/store.js.map +1 -0
- package/package.json +68 -4
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { soqlObject, SoqlRejected } from "./soql.js";
|
|
3
|
+
import { audited, Denied, json, listLimit, VendorFailed, } from "../../packages/connector-kit/src/common.js";
|
|
4
|
+
const API = "/services/data/v63.0";
|
|
5
|
+
const NAME = /^[A-Za-z][A-Za-z0-9_]{0,79}$/;
|
|
6
|
+
const RECORD_ID = /^[A-Za-z0-9]{15}(?:[A-Za-z0-9]{3})?$/;
|
|
7
|
+
async function ok(ctx, mark, req) {
|
|
8
|
+
const res = await ctx.call(req);
|
|
9
|
+
mark(res.status);
|
|
10
|
+
if (res.status < 200 || res.status >= 300) {
|
|
11
|
+
const errors = Array.isArray(res.data)
|
|
12
|
+
? res.data
|
|
13
|
+
: [];
|
|
14
|
+
const detail = errors
|
|
15
|
+
.map((e) => [e.errorCode, e.message].filter(Boolean).join(": "))
|
|
16
|
+
.join("; ");
|
|
17
|
+
throw new VendorFailed(res.status, `Salesforce answered ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
18
|
+
}
|
|
19
|
+
return res.data;
|
|
20
|
+
}
|
|
21
|
+
// Granted objects, lowercased: Salesforce object names are case-insensitive.
|
|
22
|
+
function granted(ctx) {
|
|
23
|
+
const objects = listLimit(ctx.limits, "objects");
|
|
24
|
+
return objects && new Set(objects.map((o) => o.toLowerCase()));
|
|
25
|
+
}
|
|
26
|
+
function checkObject(ctx, object) {
|
|
27
|
+
if (!NAME.test(object))
|
|
28
|
+
throw new Denied("Give an object API name such as Account or Invoice__c");
|
|
29
|
+
const allowed = granted(ctx);
|
|
30
|
+
if (allowed && !allowed.has(object.toLowerCase()))
|
|
31
|
+
throw new Denied(`This agent is not allowed to use ${object} records`);
|
|
32
|
+
return object;
|
|
33
|
+
}
|
|
34
|
+
function recordPath(ctx, object, id) {
|
|
35
|
+
checkObject(ctx, object);
|
|
36
|
+
if (!RECORD_ID.test(id))
|
|
37
|
+
throw new Denied("Give a 15 or 18 character record id");
|
|
38
|
+
return `${API}/sobjects/${object}/${id}`;
|
|
39
|
+
}
|
|
40
|
+
// The id must belong to the granted object: Salesforce can serve a record under another
|
|
41
|
+
// object's path, so its type is read back before it is changed.
|
|
42
|
+
async function checkRecordType(ctx, mark, object, id) {
|
|
43
|
+
const path = recordPath(ctx, object, id);
|
|
44
|
+
const current = await ok(ctx, mark, { method: "GET", path: `${path}?fields=Id` });
|
|
45
|
+
if (current.attributes?.type?.toLowerCase() !== object.toLowerCase())
|
|
46
|
+
throw new Denied(`${id} is not a record of type ${object}`);
|
|
47
|
+
return path;
|
|
48
|
+
}
|
|
49
|
+
// Salesforce deletes a record's cascade children with it (master-detail, and standard ones
|
|
50
|
+
// such as an Account's Contacts), and their cascade children in turn. With an objects limit,
|
|
51
|
+
// a delete that would take records of other objects along, at any depth, is refused. Not
|
|
52
|
+
// counted: Salesforce's own bookkeeping that goes with any record (feeds, field history,
|
|
53
|
+
// sharing rows, change events) and children no one can query. A child only automation
|
|
54
|
+
// creates (not createable) is still real data, so it counts.
|
|
55
|
+
const SYSTEM_CHILD = /(Feed|History|Share|ChangeEvent)$/;
|
|
56
|
+
export function cascadeChildren(children, usable) {
|
|
57
|
+
const names = children
|
|
58
|
+
.filter((r) => r.cascadeDelete && !SYSTEM_CHILD.test(r.childSObject))
|
|
59
|
+
.map((r) => r.childSObject)
|
|
60
|
+
.filter((n) => usable.has(n.toLowerCase()));
|
|
61
|
+
return [...new Set(names)];
|
|
62
|
+
}
|
|
63
|
+
export function cascadeRefusal(object, children) {
|
|
64
|
+
const shown = children.slice(0, 10).join(", ");
|
|
65
|
+
const more = children.length > 10 ? ` and ${children.length - 10} more` : "";
|
|
66
|
+
return `Deleting this ${object} record also deletes its related ${shown}${more} records, which this agent is not allowed to use`;
|
|
67
|
+
}
|
|
68
|
+
// Breadth-first through the allowed cascade children: each allowed object is described once,
|
|
69
|
+
// so the walk ends after at most one describe per object in the limit.
|
|
70
|
+
async function checkCascade(ctx, mark, object) {
|
|
71
|
+
const allowed = granted(ctx);
|
|
72
|
+
if (!allowed)
|
|
73
|
+
return;
|
|
74
|
+
const global = await ok(ctx, mark, { method: "GET", path: `${API}/sobjects` });
|
|
75
|
+
const usable = new Set(global.sobjects.filter((o) => o.queryable).map((o) => o.name.toLowerCase()));
|
|
76
|
+
const outside = new Set();
|
|
77
|
+
const seen = new Set([object.toLowerCase()]);
|
|
78
|
+
for (let level = [object]; level.length;) {
|
|
79
|
+
const next = [];
|
|
80
|
+
for (const name of level) {
|
|
81
|
+
const described = await ok(ctx, mark, {
|
|
82
|
+
method: "GET",
|
|
83
|
+
path: `${API}/sobjects/${name}/describe`,
|
|
84
|
+
});
|
|
85
|
+
for (const child of cascadeChildren(described.childRelationships, usable)) {
|
|
86
|
+
const k = child.toLowerCase();
|
|
87
|
+
if (!allowed.has(k))
|
|
88
|
+
outside.add(child);
|
|
89
|
+
else if (!seen.has(k)) {
|
|
90
|
+
seen.add(k);
|
|
91
|
+
next.push(child);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
level = next;
|
|
96
|
+
}
|
|
97
|
+
if (outside.size)
|
|
98
|
+
throw new Denied(cascadeRefusal(object, [...outside]));
|
|
99
|
+
}
|
|
100
|
+
const fieldValues = z
|
|
101
|
+
.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
102
|
+
.describe("Field API names and their values.");
|
|
103
|
+
function checkFields(fields) {
|
|
104
|
+
const names = fieldNames(Object.keys(fields));
|
|
105
|
+
if (names.length === 0 || names.length > 100)
|
|
106
|
+
throw new Denied("Give between 1 and 100 fields");
|
|
107
|
+
return names;
|
|
108
|
+
}
|
|
109
|
+
function fieldNames(fields) {
|
|
110
|
+
const bad = fields.find((f) => !NAME.test(f));
|
|
111
|
+
if (bad)
|
|
112
|
+
throw new Denied(`${bad} is not a field API name on this object`);
|
|
113
|
+
return fields;
|
|
114
|
+
}
|
|
115
|
+
export const salesforceTools = {
|
|
116
|
+
names: [
|
|
117
|
+
"salesforce_query",
|
|
118
|
+
"salesforce_get_record",
|
|
119
|
+
"salesforce_create_record",
|
|
120
|
+
"salesforce_update_record",
|
|
121
|
+
"salesforce_delete_record",
|
|
122
|
+
],
|
|
123
|
+
register(server, ctx, allowed) {
|
|
124
|
+
const readOnly = { readOnlyHint: true, openWorldHint: true };
|
|
125
|
+
const fieldList = z.array(z.string()).max(100);
|
|
126
|
+
if (allowed.has("salesforce_query"))
|
|
127
|
+
server.registerTool("salesforce_query", {
|
|
128
|
+
description: "Run a read-only SOQL query, e.g. `SELECT Id, Name FROM Account WHERE Industry = 'Energy' LIMIT 20`. " +
|
|
129
|
+
"If this agent is limited to some objects, query one of them at a time: no subqueries or relationship fields.",
|
|
130
|
+
inputSchema: z.object({
|
|
131
|
+
soql: z.string().min(1).max(10000),
|
|
132
|
+
max_records: z.number().int().min(1).max(200).default(50),
|
|
133
|
+
}),
|
|
134
|
+
annotations: readOnly,
|
|
135
|
+
}, ({ soql, max_records }) => audited(ctx, "salesforce_query", soql, async (mark) => {
|
|
136
|
+
const allowed = granted(ctx);
|
|
137
|
+
if (allowed) {
|
|
138
|
+
let object;
|
|
139
|
+
try {
|
|
140
|
+
object = soqlObject(soql);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (error instanceof SoqlRejected)
|
|
144
|
+
throw new Denied(error.message);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
checkObject(ctx, object);
|
|
148
|
+
}
|
|
149
|
+
const data = await ok(ctx, mark, {
|
|
150
|
+
method: "GET",
|
|
151
|
+
path: `${API}/query?q=${encodeURIComponent(soql)}`,
|
|
152
|
+
headers: { "sforce-query-options": "batchSize=200" },
|
|
153
|
+
});
|
|
154
|
+
const records = data.records.filter((r) => {
|
|
155
|
+
const type = r.attributes?.type?.toLowerCase();
|
|
156
|
+
return !allowed || type === "aggregateresult" || (type && allowed.has(type));
|
|
157
|
+
});
|
|
158
|
+
return json({
|
|
159
|
+
total: data.totalSize,
|
|
160
|
+
records: records.slice(0, max_records),
|
|
161
|
+
more: records.length > max_records || data.done === false,
|
|
162
|
+
});
|
|
163
|
+
}));
|
|
164
|
+
if (allowed.has("salesforce_get_record"))
|
|
165
|
+
server.registerTool("salesforce_get_record", {
|
|
166
|
+
description: "Read one Salesforce record by object and id, optionally only some fields.",
|
|
167
|
+
inputSchema: z.object({
|
|
168
|
+
object: z.string().describe("Object API name, e.g. Account or Invoice__c."),
|
|
169
|
+
id: z.string().describe("15 or 18 character record id."),
|
|
170
|
+
fields: fieldList
|
|
171
|
+
.optional()
|
|
172
|
+
.describe("Field API names. All readable fields if omitted."),
|
|
173
|
+
}),
|
|
174
|
+
annotations: readOnly,
|
|
175
|
+
}, ({ object, id, fields }) => audited(ctx, "salesforce_get_record", `${object}/${id}`, async (mark) => {
|
|
176
|
+
const path = recordPath(ctx, object, id);
|
|
177
|
+
const query = fields?.length ? `?fields=${fieldNames(fields).join(",")}` : "";
|
|
178
|
+
const record = await ok(ctx, mark, { method: "GET", path: path + query });
|
|
179
|
+
if (record.attributes?.type?.toLowerCase() !== object.toLowerCase())
|
|
180
|
+
throw new Denied(`${id} is not a record of type ${object}`);
|
|
181
|
+
return json(record);
|
|
182
|
+
}));
|
|
183
|
+
if (allowed.has("salesforce_update_record"))
|
|
184
|
+
server.registerTool("salesforce_update_record", {
|
|
185
|
+
description: "Update fields on an existing Salesforce record.",
|
|
186
|
+
inputSchema: z.object({
|
|
187
|
+
object: z.string().describe("Object API name, e.g. Account or Invoice__c."),
|
|
188
|
+
id: z.string().describe("15 or 18 character record id."),
|
|
189
|
+
fields: fieldValues,
|
|
190
|
+
}),
|
|
191
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
192
|
+
}, ({ object, id, fields }) => audited(ctx, "salesforce_update_record", `${object}/${id}`, async (mark) => {
|
|
193
|
+
recordPath(ctx, object, id);
|
|
194
|
+
const names = checkFields(fields);
|
|
195
|
+
const path = await checkRecordType(ctx, mark, object, id);
|
|
196
|
+
await ok(ctx, mark, { method: "PATCH", path, body: fields });
|
|
197
|
+
return json({ updated: true, fields: names });
|
|
198
|
+
}));
|
|
199
|
+
if (allowed.has("salesforce_create_record"))
|
|
200
|
+
server.registerTool("salesforce_create_record", {
|
|
201
|
+
description: "Create a Salesforce record of an object this agent may use.",
|
|
202
|
+
inputSchema: z.object({
|
|
203
|
+
object: z.string().describe("Object API name, e.g. Account or Invoice__c."),
|
|
204
|
+
fields: fieldValues,
|
|
205
|
+
}),
|
|
206
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
207
|
+
}, ({ object, fields }) => audited(ctx, "salesforce_create_record", object, async (mark, retarget) => {
|
|
208
|
+
checkObject(ctx, object);
|
|
209
|
+
checkFields(fields);
|
|
210
|
+
const created = await ok(ctx, mark, {
|
|
211
|
+
method: "POST",
|
|
212
|
+
path: `${API}/sobjects/${object}`,
|
|
213
|
+
body: fields,
|
|
214
|
+
});
|
|
215
|
+
retarget(`${object}/${created.id}`);
|
|
216
|
+
return json({ id: created.id });
|
|
217
|
+
}));
|
|
218
|
+
if (allowed.has("salesforce_delete_record"))
|
|
219
|
+
server.registerTool("salesforce_delete_record", {
|
|
220
|
+
description: "Delete a Salesforce record. It goes to the Recycle Bin, where Salesforce keeps it for 15 days.",
|
|
221
|
+
inputSchema: z.object({
|
|
222
|
+
object: z.string().describe("Object API name, e.g. Account or Invoice__c."),
|
|
223
|
+
id: z.string().describe("15 or 18 character record id."),
|
|
224
|
+
}),
|
|
225
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
226
|
+
}, ({ object, id }) => audited(ctx, "salesforce_delete_record", `${object}/${id}`, async (mark) => {
|
|
227
|
+
const path = await checkRecordType(ctx, mark, object, id);
|
|
228
|
+
await checkCascade(ctx, mark, object);
|
|
229
|
+
await ok(ctx, mark, { method: "DELETE", path });
|
|
230
|
+
return json({ deleted: true });
|
|
231
|
+
}));
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../connectors/salesforce/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { ConnectError, TokenCache, } from "../../packages/connector-kit/src/types.js";
|
|
3
|
+
// The customer's External Client App, client credentials flow, running as their integration
|
|
4
|
+
// user. Tokens come from their My Domain, and the API is called on the instance_url it returns.
|
|
5
|
+
const MY_DOMAIN = /^[a-z0-9][a-z0-9-]*(\.[a-z0-9-]+)?\.my\.salesforce\.com$/;
|
|
6
|
+
const USER_ID = /^005[A-Za-z0-9]{12}(?:[A-Za-z0-9]{3})?$/;
|
|
7
|
+
// Salesforce does not say when a token expires (it follows the org's session timeout, at
|
|
8
|
+
// least 15 minutes), so a token is reused for 10 minutes (the cache drops it a minute before
|
|
9
|
+
// expiresIn) and dropped early on a 401.
|
|
10
|
+
const TOKEN_SECONDS = 11 * 60;
|
|
11
|
+
export function normalizeMyDomain(input) {
|
|
12
|
+
let host = input
|
|
13
|
+
.trim()
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/^https?:\/\//, "")
|
|
16
|
+
.replace(/\/.*$/, "");
|
|
17
|
+
if (/^[a-z0-9][a-z0-9-]*$/.test(host))
|
|
18
|
+
host = `${host}.my.salesforce.com`;
|
|
19
|
+
if (!MY_DOMAIN.test(host))
|
|
20
|
+
throw new ConnectError("Enter your My Domain, the address ending in .my.salesforce.com");
|
|
21
|
+
return host;
|
|
22
|
+
}
|
|
23
|
+
function instanceUrl(raw) {
|
|
24
|
+
const url = typeof raw === "string" ? URL.parse(raw) : null;
|
|
25
|
+
if (!url || url.protocol !== "https:" || !MY_DOMAIN.test(url.hostname) || url.port)
|
|
26
|
+
throw new ConnectError("Salesforce returned an unexpected address for your org");
|
|
27
|
+
return url.origin;
|
|
28
|
+
}
|
|
29
|
+
export function salesforceVendor(fetchImpl = fetch) {
|
|
30
|
+
const tokens = new TokenCache();
|
|
31
|
+
async function mint(myDomain, clientId, clientSecret) {
|
|
32
|
+
const res = await fetchImpl(`https://${myDomain}/services/oauth2/token`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
35
|
+
body: new URLSearchParams({
|
|
36
|
+
grant_type: "client_credentials",
|
|
37
|
+
client_id: clientId,
|
|
38
|
+
client_secret: clientSecret,
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
const body = (await res.json().catch(() => ({})));
|
|
42
|
+
if (!res.ok || !body.access_token) {
|
|
43
|
+
const why = (body.error_description ?? body.error ?? String(res.status)).split(/\r?\n/)[0];
|
|
44
|
+
throw new ConnectError(`Salesforce refused the sign-in: ${why.slice(0, 300)}`);
|
|
45
|
+
}
|
|
46
|
+
return body;
|
|
47
|
+
}
|
|
48
|
+
const cacheKey = (c) => createHash("sha256")
|
|
49
|
+
.update(`${c.config.myDomain}\n${c.secret.client_id}\n${c.secret.client_secret}`)
|
|
50
|
+
.digest("hex");
|
|
51
|
+
const token = (c) => tokens.get(cacheKey(c), async () => ({
|
|
52
|
+
token: (await mint(c.config.myDomain, c.secret.client_id, c.secret.client_secret))
|
|
53
|
+
.access_token,
|
|
54
|
+
expiresIn: TOKEN_SECONDS,
|
|
55
|
+
}));
|
|
56
|
+
async function send(base, access, request) {
|
|
57
|
+
const res = await fetchImpl(`${base}${request.path}`, {
|
|
58
|
+
method: request.method,
|
|
59
|
+
headers: {
|
|
60
|
+
authorization: `Bearer ${access}`,
|
|
61
|
+
accept: "application/json",
|
|
62
|
+
...request.headers,
|
|
63
|
+
...(request.body === undefined ? {} : { "content-type": "application/json" }),
|
|
64
|
+
},
|
|
65
|
+
body: request.body === undefined ? undefined : JSON.stringify(request.body),
|
|
66
|
+
});
|
|
67
|
+
const raw = await res.text();
|
|
68
|
+
return { status: res.status, data: raw ? safeJson(raw) : null };
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
async connect(fields) {
|
|
72
|
+
const myDomain = normalizeMyDomain(fields.my_domain ?? "");
|
|
73
|
+
const clientId = fields.client_id?.trim();
|
|
74
|
+
const clientSecret = fields.client_secret?.trim();
|
|
75
|
+
if (!clientId || !clientSecret)
|
|
76
|
+
throw new ConnectError("Enter the consumer key and consumer secret");
|
|
77
|
+
const minted = await mint(myDomain, clientId, clientSecret);
|
|
78
|
+
// The identity URL ends in the Run As user's id; verify reads that user back.
|
|
79
|
+
const userId = minted.id?.split("/").pop() ?? "";
|
|
80
|
+
if (!USER_ID.test(userId))
|
|
81
|
+
throw new ConnectError("Salesforce did not say which user the app runs as");
|
|
82
|
+
return {
|
|
83
|
+
config: { myDomain, instanceUrl: instanceUrl(minted.instance_url), userId },
|
|
84
|
+
secret: { client_id: clientId, client_secret: clientSecret },
|
|
85
|
+
accountLabel: myDomain,
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
async call(connection, request) {
|
|
89
|
+
const base = instanceUrl(connection.config.instanceUrl);
|
|
90
|
+
let res = await send(base, await token(connection), request);
|
|
91
|
+
if (res.status === 401) {
|
|
92
|
+
tokens.forget(cacheKey(connection));
|
|
93
|
+
res = await send(base, await token(connection), request);
|
|
94
|
+
}
|
|
95
|
+
return res;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function safeJson(raw) {
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(raw);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return raw;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=vendor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor.js","sourceRoot":"","sources":["../../../connectors/salesforce/vendor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "sap-s4hana",
|
|
3
|
+
"name": "SAP S/4HANA",
|
|
4
|
+
"description": "Let agents look up customers, suppliers, orders, stock and invoices in SAP S/4HANA and, if you allow it, create sales and purchase orders, within the company codes, sales and purchasing organizations and plants you choose.",
|
|
5
|
+
"logo": "/brand/registry/sap.svg",
|
|
6
|
+
"identity": "A dedicated SAP user for {brand.microsoft.appName}: a communication user on SAP S/4HANA Cloud, or a technical (system) user on premise. Agents never see more than this user's SAP authorizations allow.",
|
|
7
|
+
"accountKey": "system",
|
|
8
|
+
"connectionKind": "guided",
|
|
9
|
+
"setup": [
|
|
10
|
+
{
|
|
11
|
+
"title": "Create a communication user",
|
|
12
|
+
"body": "In SAP S/4HANA Cloud, open the Maintain Communication Users app and create a user for {brand.microsoft.appName}. Let SAP propose a password and copy it now: it is shown only once.",
|
|
13
|
+
"option": { "field": "deployment", "value": "cloud" },
|
|
14
|
+
"click": [
|
|
15
|
+
"SAP Fiori launchpad > Communication Management > Maintain Communication Users > New",
|
|
16
|
+
"User Name: a name such as AGENT_CONNECT, Description: {brand.microsoft.appName} > Propose Password > copy it > Create"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"title": "Create a communication system",
|
|
21
|
+
"body": "Open the Communication Systems app and create a system for {brand.microsoft.appName}. Tick Inbound Only, and add the communication user under Users for Inbound Communication with the authentication method User ID and Password.",
|
|
22
|
+
"option": { "field": "deployment", "value": "cloud" },
|
|
23
|
+
"click": [
|
|
24
|
+
"Communication Management > Communication Systems > New",
|
|
25
|
+
"System ID and Name: AGENT_CONNECT > Create > Inbound Only: on",
|
|
26
|
+
"Users for Inbound Communication > + > the communication user, User ID and Password > OK > Save"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"title": "Create a communication arrangement for each scenario",
|
|
31
|
+
"body": "Open the Communication Arrangements app and create one arrangement per scenario below, each with the communication system above. Agents can only reach the services of these scenarios. To sign in with OAuth 2.0, choose OAuth 2.0 as the inbound authentication of each arrangement. The arrangement shows the API host under Inbound Services, for example my123456-api.s4hana.cloud.sap: enter that host below.",
|
|
32
|
+
"option": { "field": "deployment", "value": "cloud" },
|
|
33
|
+
"copy": ["{scope}"],
|
|
34
|
+
"click": [
|
|
35
|
+
"Communication Management > Communication Arrangements > New > Scenario: the scenario > Create",
|
|
36
|
+
"Communication System: AGENT_CONNECT > Save"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"title": "Activate the OData services",
|
|
41
|
+
"body": "On the SAP Gateway system, add each service below in transaction /IWFND/MAINT_SERVICE (system alias LOCAL on an embedded Gateway), then check that its node /sap/opu/odata/sap/ followed by the service name is active in transaction SICF.",
|
|
42
|
+
"option": { "field": "deployment", "value": "on_premise" },
|
|
43
|
+
"permissions": true,
|
|
44
|
+
"click": [
|
|
45
|
+
"Transaction /IWFND/MAINT_SERVICE > Add Service > System Alias: LOCAL > Technical Service Name: the service > Get Services > select it > Add Selected Services > Local Object",
|
|
46
|
+
"Transaction SICF > Service Path: /sap/opu/odata/sap/ the service > Execute > right-click the service node > Activate Service"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"title": "Create a role for the services and your organizations",
|
|
51
|
+
"body": "In transaction PFCG create a role, add the same services to its menu (Authorization Default, TADIR Service, R3TR IWSG and the service name followed by _0001), and in its authorizations give display access, plus create for the order capabilities you tick, only for the organizations agents need: V_VBAK_VKO and V_VBAK_AAT (sales organizations, order types), M_BEST_EKO, M_BEST_BSA and M_BEST_WRK (purchasing organizations, order types, plants), M_MSEG_WWA (plants) and F_BKPF_BUK (company codes). SAP then enforces these too, whatever the limits here.",
|
|
52
|
+
"option": { "field": "deployment", "value": "on_premise" },
|
|
53
|
+
"click": [
|
|
54
|
+
"Transaction PFCG > Role: Z_AGENT_CONNECT > Single Role > Menu > Authorization Default > TADIR Service, R3TR IWSG, the services with _0001",
|
|
55
|
+
"Authorizations > Change Authorization Data > fill the organizational levels > Generate > Save"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"title": "Create a technical user",
|
|
60
|
+
"body": "In transaction SU01 create a user of type System for {brand.microsoft.appName}, give it a password and the role above. A System user cannot sign in to SAP GUI and its password does not expire.",
|
|
61
|
+
"option": { "field": "deployment", "value": "on_premise" },
|
|
62
|
+
"click": [
|
|
63
|
+
"Transaction SU01 > User: AGENT_CONNECT > Create",
|
|
64
|
+
"Logon Data > User Type: System > set the password",
|
|
65
|
+
"Roles > Z_AGENT_CONNECT > Save"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"title": "Find the Gateway's https address",
|
|
70
|
+
"body": "Agents reach SAP through this service, which usually runs inside your network next to SAP. Use the Gateway's https host and port, for example sap-gw.example.internal:44300 (transaction SMICM, Goto, Services lists the HTTPS port). If your SAP certificate comes from an internal certificate authority, whoever runs this service adds that authority to it first.",
|
|
71
|
+
"option": { "field": "deployment", "value": "on_premise" },
|
|
72
|
+
"click": ["Transaction SMICM > Goto > Services > the HTTPS line's host name and port"]
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"afterConnect": [],
|
|
76
|
+
"fields": [
|
|
77
|
+
{
|
|
78
|
+
"id": "deployment",
|
|
79
|
+
"label": "SAP system",
|
|
80
|
+
"secret": false,
|
|
81
|
+
"options": [
|
|
82
|
+
{
|
|
83
|
+
"value": "cloud",
|
|
84
|
+
"label": "SAP S/4HANA Cloud",
|
|
85
|
+
"description": "Reached through communication arrangements and a communication user."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"value": "on_premise",
|
|
89
|
+
"label": "On premise or private cloud",
|
|
90
|
+
"description": "SAP S/4HANA reached through SAP Gateway with a technical user."
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "auth",
|
|
96
|
+
"label": "Sign-in",
|
|
97
|
+
"secret": false,
|
|
98
|
+
"requires": { "field": "deployment", "value": "cloud" },
|
|
99
|
+
"options": [
|
|
100
|
+
{
|
|
101
|
+
"value": "basic",
|
|
102
|
+
"label": "User name and password",
|
|
103
|
+
"description": "The communication user's name and password on every call."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"value": "oauth",
|
|
107
|
+
"label": "OAuth 2.0 client credentials",
|
|
108
|
+
"description": "The communication user signs in for a short-lived token. Its arrangements must use OAuth 2.0."
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "host",
|
|
114
|
+
"label": "API host",
|
|
115
|
+
"help": "The host shown under Inbound Services in the communication arrangement.",
|
|
116
|
+
"placeholder": "my123456-api.s4hana.cloud.sap",
|
|
117
|
+
"secret": false,
|
|
118
|
+
"requires": { "field": "deployment", "value": "cloud" }
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "gateway_host",
|
|
122
|
+
"label": "Gateway address",
|
|
123
|
+
"help": "The SAP Gateway's https host and port.",
|
|
124
|
+
"placeholder": "sap-gw.example.internal:44300",
|
|
125
|
+
"secret": false,
|
|
126
|
+
"requires": { "field": "deployment", "value": "on_premise" }
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"id": "sap_client",
|
|
130
|
+
"label": "Client",
|
|
131
|
+
"help": "The three-digit SAP client, for example 100. Leave empty for the system's default client.",
|
|
132
|
+
"placeholder": "100",
|
|
133
|
+
"secret": false,
|
|
134
|
+
"requires": { "field": "deployment", "value": "on_premise" }
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "user",
|
|
138
|
+
"label": "User name",
|
|
139
|
+
"help": "The communication user (Cloud) or the technical user (on premise).",
|
|
140
|
+
"secret": false
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"id": "password",
|
|
144
|
+
"label": "Password",
|
|
145
|
+
"secret": true
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"capabilities": [
|
|
149
|
+
{
|
|
150
|
+
"id": "partners",
|
|
151
|
+
"label": "Look up customers and suppliers",
|
|
152
|
+
"description": "Find business partners by name or number: name, whether they are a customer or supplier, blocked or not, city and country. Partners are shared across your organizations, so the limits below do not narrow them.",
|
|
153
|
+
"scopes": ["SAP_COM_0008"],
|
|
154
|
+
"roles": ["API_BUSINESS_PARTNER"],
|
|
155
|
+
"permissions": ["API_BUSINESS_PARTNER"],
|
|
156
|
+
"forbidden": "The SAP user needs the business partner service: on SAP S/4HANA Cloud the arrangement for SAP_COM_0008, on premise API_BUSINESS_PARTNER in its role.",
|
|
157
|
+
"tools": ["sap_find_business_partners"]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "read_sales",
|
|
161
|
+
"label": "Read sales orders",
|
|
162
|
+
"description": "List and read sales orders with their lines, status and delivery status.",
|
|
163
|
+
"scopes": ["SAP_COM_0109"],
|
|
164
|
+
"roles": ["API_SALES_ORDER_SRV"],
|
|
165
|
+
"permissions": ["API_SALES_ORDER_SRV"],
|
|
166
|
+
"forbidden": "The SAP user needs the sales order service: on SAP S/4HANA Cloud the arrangement for SAP_COM_0109, on premise API_SALES_ORDER_SRV and display access to the sales organization in its role.",
|
|
167
|
+
"tools": ["sap_list_sales_orders", "sap_get_sales_order"]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "create_sales",
|
|
171
|
+
"label": "Create sales orders",
|
|
172
|
+
"description": "Create sales orders for customers from materials and quantities. SAP prices them from your master data. Agents cannot change or cancel orders.",
|
|
173
|
+
"scopes": ["SAP_COM_0109"],
|
|
174
|
+
"roles": ["API_SALES_ORDER_SRV"],
|
|
175
|
+
"permissions": ["API_SALES_ORDER_SRV"],
|
|
176
|
+
"forbidden": "On premise, the SAP user's role needs create access (V_VBAK_VKO activity 01) for the sales organization and order type.",
|
|
177
|
+
"tools": ["sap_create_sales_order"]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"id": "read_purchasing",
|
|
181
|
+
"label": "Read purchase orders",
|
|
182
|
+
"description": "List and read purchase orders with their lines, approval status, and what is delivered and invoiced.",
|
|
183
|
+
"scopes": ["SAP_COM_0053"],
|
|
184
|
+
"roles": ["API_PURCHASEORDER_PROCESS_SRV"],
|
|
185
|
+
"permissions": ["API_PURCHASEORDER_PROCESS_SRV"],
|
|
186
|
+
"forbidden": "The SAP user needs the purchase order service: on SAP S/4HANA Cloud the arrangement for SAP_COM_0053, on premise API_PURCHASEORDER_PROCESS_SRV and display access to the purchasing organization in its role.",
|
|
187
|
+
"tools": ["sap_list_purchase_orders", "sap_get_purchase_order"]
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"id": "create_purchasing",
|
|
191
|
+
"label": "Create purchase orders",
|
|
192
|
+
"description": "Create purchase orders to suppliers. Each goes through your purchase order approval as usual: agents can never approve one. Once approved and sent, it commits your company to pay.",
|
|
193
|
+
"destructive": true,
|
|
194
|
+
"costs": true,
|
|
195
|
+
"note": "Agents with this can commit your company to spend money. Keep each agent to the company codes, purchasing organizations and plants it needs, and keep your approval rules in place.",
|
|
196
|
+
"scopes": ["SAP_COM_0053"],
|
|
197
|
+
"roles": ["API_PURCHASEORDER_PROCESS_SRV"],
|
|
198
|
+
"permissions": ["API_PURCHASEORDER_PROCESS_SRV"],
|
|
199
|
+
"forbidden": "On premise, the SAP user's role needs create access (M_BEST_EKO activity 01) for the purchasing organization, order type and plant.",
|
|
200
|
+
"tools": ["sap_create_purchase_order"]
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"id": "stock",
|
|
204
|
+
"label": "Read products and stock",
|
|
205
|
+
"description": "Find products by number or description, and read a material's stock by plant, storage location and batch.",
|
|
206
|
+
"scopes": ["SAP_COM_0009", "SAP_COM_0164"],
|
|
207
|
+
"roles": ["API_PRODUCT_SRV", "API_MATERIAL_STOCK_SRV"],
|
|
208
|
+
"permissions": ["API_PRODUCT_SRV", "API_MATERIAL_STOCK_SRV"],
|
|
209
|
+
"forbidden": "The SAP user needs the product and stock services: on SAP S/4HANA Cloud the arrangements for SAP_COM_0009 and SAP_COM_0164, on premise API_PRODUCT_SRV and API_MATERIAL_STOCK_SRV in its role.",
|
|
210
|
+
"tools": ["sap_find_products", "sap_get_stock"]
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"id": "finance",
|
|
214
|
+
"label": "Read invoices and payments",
|
|
215
|
+
"description": "List supplier invoices, and open or paid customer and supplier items in accounting with their due dates.",
|
|
216
|
+
"scopes": ["SAP_COM_0057", "SAP_COM_0303"],
|
|
217
|
+
"roles": ["API_SUPPLIERINVOICE_PROCESS_SRV", "API_OPLACCTGDOCITEMCUBE_SRV"],
|
|
218
|
+
"permissions": ["API_SUPPLIERINVOICE_PROCESS_SRV", "API_OPLACCTGDOCITEMCUBE_SRV"],
|
|
219
|
+
"forbidden": "The SAP user needs the invoice and accounting item services: on SAP S/4HANA Cloud the arrangements for SAP_COM_0057 and SAP_COM_0303, on premise API_SUPPLIERINVOICE_PROCESS_SRV and API_OPLACCTGDOCITEMCUBE_SRV and display access to the company code in its role.",
|
|
220
|
+
"tools": ["sap_list_supplier_invoices", "sap_list_account_items"]
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
"limits": [
|
|
224
|
+
{
|
|
225
|
+
"id": "company_codes",
|
|
226
|
+
"label": "Company codes",
|
|
227
|
+
"help": "Purchase orders, invoices and accounting items in these company codes only. Leave empty to allow every company code the SAP user can see.",
|
|
228
|
+
"kind": "list",
|
|
229
|
+
"required": false,
|
|
230
|
+
"pattern": "^[A-Za-z0-9]{1,4}$"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"id": "sales_organizations",
|
|
234
|
+
"label": "Sales organizations",
|
|
235
|
+
"help": "Sales orders of these sales organizations only. Leave empty to allow every one the SAP user can see.",
|
|
236
|
+
"kind": "list",
|
|
237
|
+
"required": false,
|
|
238
|
+
"pattern": "^[A-Za-z0-9]{1,4}$"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "purchasing_organizations",
|
|
242
|
+
"label": "Purchasing organizations",
|
|
243
|
+
"help": "Purchase orders of these purchasing organizations only. Leave empty to allow every one the SAP user can see.",
|
|
244
|
+
"kind": "list",
|
|
245
|
+
"required": false,
|
|
246
|
+
"pattern": "^[A-Za-z0-9]{1,4}$"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"id": "plants",
|
|
250
|
+
"label": "Plants",
|
|
251
|
+
"help": "Stock at these plants only, new order lines must name one of them, and orders with lines at other plants are not shown. Leave empty to allow every plant.",
|
|
252
|
+
"kind": "list",
|
|
253
|
+
"required": false,
|
|
254
|
+
"pattern": "^[A-Za-z0-9]{1,4}$"
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
"verify": {
|
|
258
|
+
"label": "Services the SAP user can use",
|
|
259
|
+
"check": "services",
|
|
260
|
+
"ifEmpty": "The SAP user cannot open any of the services yet. Follow the setup steps for the capabilities you ticked."
|
|
261
|
+
},
|
|
262
|
+
"revoke": "On SAP S/4HANA Cloud, delete the communication arrangements and the communication user for {brand.microsoft.appName}. On premise, lock the technical user in transaction SU01."
|
|
263
|
+
}
|