@arbium/enterprise-agent-connect 0.0.0-stage → 0.1.1
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 +117 -2
- package/dist/connectors/dell-techdirect/connector.json +39 -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.js +49 -0
- package/dist/connectors/dell-techdirect/tools.js.map +1 -0
- package/dist/connectors/dell-techdirect/vendor.js +57 -0
- package/dist/connectors/dell-techdirect/vendor.js.map +1 -0
- package/dist/connectors/entra/connector.json +85 -0
- package/dist/connectors/entra/index.js +4 -0
- package/dist/connectors/entra/index.js.map +1 -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.js +7 -0
- package/dist/connectors/fedex/index.js.map +1 -0
- package/dist/connectors/fedex/tools.js +152 -0
- package/dist/connectors/fedex/tools.js.map +1 -0
- package/dist/connectors/fedex/vendor.js +98 -0
- package/dist/connectors/fedex/vendor.js.map +1 -0
- package/dist/connectors/http/index.js +235 -0
- package/dist/connectors/http/index.js.map +1 -0
- package/dist/connectors/intune/connector.json +106 -0
- package/dist/connectors/intune/index.js +4 -0
- package/dist/connectors/intune/index.js.map +1 -0
- package/dist/connectors/intune/tools.js +416 -0
- package/dist/connectors/intune/tools.js.map +1 -0
- package/dist/connectors/jira/connector.json +129 -0
- package/dist/connectors/jira/index.js +7 -0
- package/dist/connectors/jira/index.js.map +1 -0
- package/dist/connectors/jira/jql.js +67 -0
- package/dist/connectors/jira/jql.js.map +1 -0
- package/dist/connectors/jira/tools.js +464 -0
- package/dist/connectors/jira/tools.js.map +1 -0
- package/dist/connectors/jira/vendor.js +94 -0
- package/dist/connectors/jira/vendor.js.map +1 -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/outlook-calendar/connector.json +136 -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.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.js +4 -0
- package/dist/connectors/outlook-mail/index.js.map +1 -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.js +7 -0
- package/dist/connectors/salesforce/index.js.map +1 -0
- package/dist/connectors/salesforce/soql.js +60 -0
- package/dist/connectors/salesforce/soql.js.map +1 -0
- package/dist/connectors/salesforce/tools.js +234 -0
- package/dist/connectors/salesforce/tools.js.map +1 -0
- package/dist/connectors/salesforce/vendor.js +107 -0
- package/dist/connectors/salesforce/vendor.js.map +1 -0
- package/dist/connectors/sharepoint-files/connector.json +194 -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.js +12 -0
- package/dist/connectors/sharepoint-files/index.js.map +1 -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.js +167 -0
- package/dist/connectors/sharepoint-files/vendor.js.map +1 -0
- package/dist/connectors/teams/connector.json +298 -0
- package/dist/connectors/teams/index.js +5 -0
- package/dist/connectors/teams/index.js.map +1 -0
- package/dist/connectors/teams/tools.js +391 -0
- package/dist/connectors/teams/tools.js.map +1 -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.js +84 -0
- package/dist/packages/connector-kit/src/certificate.js.map +1 -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.js +492 -0
- package/dist/packages/connector-kit/src/connector.js.map +1 -0
- package/dist/packages/connector-kit/src/oauth.js +79 -0
- package/dist/packages/connector-kit/src/oauth.js.map +1 -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/rollback/to-legacy.sql +87 -0
- package/dist/packages/server/src/api.js +684 -0
- package/dist/packages/server/src/api.js.map +1 -0
- package/dist/packages/server/src/app.js +444 -0
- package/dist/packages/server/src/app.js.map +1 -0
- package/dist/packages/server/src/builtin.js +24 -0
- package/dist/packages/server/src/builtin.js.map +1 -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/index.js +129 -0
- package/dist/packages/server/src/index.js.map +1 -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.js +101 -0
- package/dist/packages/server/src/openapi.js.map +1 -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.js +69 -0
- package/dist/packages/server/src/server.js.map +1 -0
- package/dist/packages/server/src/service.js +908 -0
- package/dist/packages/server/src/service.js.map +1 -0
- package/dist/packages/server/src/store.js +411 -0
- package/dist/packages/server/src/store.js.map +1 -0
- package/dist/packages/server/src/teams/activity.js +187 -0
- package/dist/packages/server/src/teams/activity.js.map +1 -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.js +118 -0
- package/dist/packages/server/src/teams/approval.js.map +1 -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.js +165 -0
- package/dist/packages/server/src/teams/claude.js.map +1 -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.js +319 -0
- package/dist/packages/server/src/teams/package.js.map +1 -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.js +143 -0
- package/dist/packages/server/src/teams/runner.js.map +1 -0
- package/dist/packages/server/src/teams/runtime.js +701 -0
- package/dist/packages/server/src/teams/runtime.js.map +1 -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 +42 -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,194 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "sharepoint-files",
|
|
3
|
+
"name": "SharePoint",
|
|
4
|
+
"description": "Let agents work with files and Excel spreadsheets in the SharePoint sites you add, and look up people in your organization. Agents have no OneDrive of their own: a person's OneDrive is a site too, reached only if you add it and give the app access to it.",
|
|
5
|
+
"logo": "/brand/registry/sharepoint.svg",
|
|
6
|
+
"identity": "Your Microsoft app registration, through the Microsoft connection. It reaches only the files and spreadsheets in the sites you give it, unless you choose all sites, read-only.",
|
|
7
|
+
"provider": "microsoft",
|
|
8
|
+
"order": 3,
|
|
9
|
+
"accountKey": "tenantId",
|
|
10
|
+
"connectionKind": "guided",
|
|
11
|
+
"setup": [
|
|
12
|
+
{
|
|
13
|
+
"title": "Add these Microsoft Graph permissions to the app",
|
|
14
|
+
"body": "In the app, open API permissions, select Add a permission, then Microsoft Graph, then Application permissions, and add exactly these. Sites.Selected reaches only the sites you give the app, one by one. Unless you choose all sites, read-only, do not add Sites.Read.All, Sites.ReadWrite.All or Files.Read.All: they reach every site and file in your organization.",
|
|
15
|
+
"copy": [
|
|
16
|
+
"az ad app permission add --id {clientId} --api 00000003-0000-0000-c000-000000000000 --api-permissions \"$(az ad sp show --id 00000003-0000-0000-c000-000000000000 --query \"appRoles[?value=='{scope}'].id\" -o tsv)=Role\""
|
|
17
|
+
],
|
|
18
|
+
"click": [
|
|
19
|
+
"In the Microsoft Entra admin center, go to Entra ID, then App registrations, and open {brand.microsoft.appName}.",
|
|
20
|
+
"Select API permissions, then Add a permission, then Microsoft Graph, then Application permissions.",
|
|
21
|
+
"Tick {scopes} and select Add permissions."
|
|
22
|
+
],
|
|
23
|
+
"shell": "bash"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"title": "Grant admin consent",
|
|
27
|
+
"body": "Still under API permissions, select \"Grant admin consent\". This needs a Global Administrator or Privileged Role Administrator, and is needed again whenever you add a permission. Each permission should then show Granted. With Commands, a permission that was granted already is answered with \"Permission being assigned already exists\", which is fine.",
|
|
28
|
+
"click": [
|
|
29
|
+
"Still under API permissions, select Grant admin consent for your organization, then Yes.",
|
|
30
|
+
"Each permission should show Granted under Status."
|
|
31
|
+
],
|
|
32
|
+
"copy": [
|
|
33
|
+
"SP=$(az ad sp show --id {clientId} --query id -o tsv)",
|
|
34
|
+
"GRAPH=$(az ad sp show --id 00000003-0000-0000-c000-000000000000 --query id -o tsv)",
|
|
35
|
+
"az rest --method post --url \"https://graph.microsoft.com/v1.0/servicePrincipals/$SP/appRoleAssignments\" --body \"{\\\"principalId\\\": \\\"$SP\\\", \\\"resourceId\\\": \\\"$GRAPH\\\", \\\"appRoleId\\\": \\\"$(az ad sp show --id 00000003-0000-0000-c000-000000000000 --query \"appRoles[?value=='{scope}'].id\" -o tsv)\\\"}\""
|
|
36
|
+
],
|
|
37
|
+
"shell": "bash"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"afterConnect": [],
|
|
41
|
+
"fields": [
|
|
42
|
+
{
|
|
43
|
+
"id": "access",
|
|
44
|
+
"label": "Which sites the app can reach",
|
|
45
|
+
"secret": false,
|
|
46
|
+
"options": [
|
|
47
|
+
{
|
|
48
|
+
"value": "selected",
|
|
49
|
+
"label": "Only the sites you give it",
|
|
50
|
+
"description": "Recommended. The app reaches a site only after it is given access to that site."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"value": "all_read",
|
|
54
|
+
"label": "All sites, read-only",
|
|
55
|
+
"description": "The app can read every site and every person's OneDrive in your organization, files and spreadsheets alike, with no grant per site. Each API key still reaches only the sites and folders you choose for it. To let agents add files or edit spreadsheets in a site, give the app write access to that site as well.",
|
|
56
|
+
"scopes": ["Sites.Read.All"]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"capabilities": [
|
|
62
|
+
{
|
|
63
|
+
"id": "read_files",
|
|
64
|
+
"label": "Read files",
|
|
65
|
+
"description": "List and read files in the sites you add, and only those.",
|
|
66
|
+
"scopes": ["Sites.Selected"],
|
|
67
|
+
"permissions": [],
|
|
68
|
+
"fill": {
|
|
69
|
+
"site_role": "read"
|
|
70
|
+
},
|
|
71
|
+
"tools": ["graph_list_sites", "graph_list_files", "graph_read_file"],
|
|
72
|
+
"forbidden": "Microsoft refused this. An administrator has to give the app read access to this site (the SharePoint page in {brand.productName} shows the command). A new grant can take a few minutes to apply."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "read_sheets",
|
|
76
|
+
"label": "Read spreadsheets",
|
|
77
|
+
"description": "List Excel workbooks, their sheets and tables, and read cells in the sites you add.",
|
|
78
|
+
"scopes": ["Sites.Selected"],
|
|
79
|
+
"permissions": [],
|
|
80
|
+
"fill": {
|
|
81
|
+
"site_role": "read"
|
|
82
|
+
},
|
|
83
|
+
"tools": [
|
|
84
|
+
"excel_list_workbooks",
|
|
85
|
+
"excel_list_worksheets",
|
|
86
|
+
"excel_read_range",
|
|
87
|
+
"excel_list_tables",
|
|
88
|
+
"excel_read_table"
|
|
89
|
+
],
|
|
90
|
+
"forbidden": "Microsoft refused this. An administrator has to give the app read access to this site (the SharePoint page in {brand.productName} shows the command). A new grant can take a few minutes to apply."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "write_files",
|
|
94
|
+
"label": "Add and change files",
|
|
95
|
+
"destructive": true,
|
|
96
|
+
"description": "Add files to those sites and replace existing ones. The app needs write access to each of them, not read.",
|
|
97
|
+
"scopes": ["Sites.Selected"],
|
|
98
|
+
"permissions": [],
|
|
99
|
+
"fill": {
|
|
100
|
+
"site_role": "write"
|
|
101
|
+
},
|
|
102
|
+
"tools": ["graph_upload_file"],
|
|
103
|
+
"forbidden": "Microsoft refused this. Adding or changing files needs the app to have write access to this site; a site given read access only refuses changes. The SharePoint page in {brand.productName} shows the command. A new grant can take a few minutes to apply."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "write_sheets",
|
|
107
|
+
"label": "Edit spreadsheets",
|
|
108
|
+
"description": "Change cells and add rows to tables in those workbooks. The app needs write access to each of those sites, not read.",
|
|
109
|
+
"scopes": ["Sites.Selected"],
|
|
110
|
+
"permissions": [],
|
|
111
|
+
"fill": {
|
|
112
|
+
"site_role": "write"
|
|
113
|
+
},
|
|
114
|
+
"tools": ["excel_update_range", "excel_add_table_rows"],
|
|
115
|
+
"forbidden": "Microsoft refused this. Editing spreadsheets needs the app to have write access to this site; a site given read access only refuses changes. The SharePoint page in {brand.productName} shows the command. A new grant can take a few minutes to apply."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "read_directory",
|
|
119
|
+
"label": "Read users and groups",
|
|
120
|
+
"description": "Look up people's names, email addresses and job titles, and list group members.",
|
|
121
|
+
"note": "Reaches everyone in your organization, not just chosen sites. Read-only. Leave it off unless agents need to look people up.",
|
|
122
|
+
"scopes": ["User.Read.All", "GroupMember.Read.All"],
|
|
123
|
+
"permissions": [],
|
|
124
|
+
"tools": ["graph_list_users"],
|
|
125
|
+
"forbidden": "Microsoft refused this. The app needs {scopes} with admin consent."
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"limits": [
|
|
129
|
+
{
|
|
130
|
+
"id": "sites",
|
|
131
|
+
"label": "Sites",
|
|
132
|
+
"help": "The sites whose files and spreadsheets this key may use, from the sites the app can open. It can use no others.",
|
|
133
|
+
"kind": "list",
|
|
134
|
+
"required": true,
|
|
135
|
+
"pattern": "^https://[A-Za-z0-9-]+\\.sharepoint\\.com(/(sites|teams|personal)/[A-Za-z0-9][A-Za-z0-9._-]*)?/?$"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"id": "folders",
|
|
139
|
+
"label": "Folder",
|
|
140
|
+
"help": "Optional, for each site: the one folder this key may use there, for files and spreadsheets alike, such as Contracts/Signed. Leave it empty for the whole site.",
|
|
141
|
+
"kind": "map",
|
|
142
|
+
"keys": "sites",
|
|
143
|
+
"required": false,
|
|
144
|
+
"pattern": "^(?!(?:.*/)?\\.{1,2}(?:/|$))[^\\\\:?#*\"<>|%]+$"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"siteAccess": {
|
|
148
|
+
"grant": [
|
|
149
|
+
{
|
|
150
|
+
"title": "With Microsoft Graph PowerShell",
|
|
151
|
+
"body": "Run by a SharePoint or Global Administrator.",
|
|
152
|
+
"clickUnavailable": true,
|
|
153
|
+
"link": {
|
|
154
|
+
"label": "Install Microsoft Graph PowerShell",
|
|
155
|
+
"href": "https://learn.microsoft.com/powershell/microsoftgraph/installation"
|
|
156
|
+
},
|
|
157
|
+
"copy": [
|
|
158
|
+
"# Needs Microsoft Graph PowerShell: Install-Module Microsoft.Graph -Scope CurrentUser",
|
|
159
|
+
"Connect-MgGraph -Scopes \"Sites.FullControl.All\"",
|
|
160
|
+
"$site = Get-MgSite -SiteId '{siteRef}'",
|
|
161
|
+
"New-MgSitePermission -SiteId $site.Id -BodyParameter @{ roles = @('{site_role}'); grantedToIdentities = @(@{ application = @{ id = '{clientId}'; displayName = \"{brand.microsoft.appName}\" } }) }"
|
|
162
|
+
],
|
|
163
|
+
"shell": "powershell"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"title": "Or raise a site the app already reads",
|
|
167
|
+
"siteRole": "write",
|
|
168
|
+
"body": "A site given read access refuses changes. To let agents add files or edit spreadsheets there, change that grant to write.",
|
|
169
|
+
"clickUnavailable": true,
|
|
170
|
+
"copy": [
|
|
171
|
+
"# Needs Microsoft Graph PowerShell: Install-Module Microsoft.Graph -Scope CurrentUser",
|
|
172
|
+
"Connect-MgGraph -Scopes \"Sites.FullControl.All\"",
|
|
173
|
+
"$site = Get-MgSite -SiteId '{siteRef}'",
|
|
174
|
+
"$p = Get-MgSitePermission -SiteId $site.Id | Where-Object { $_.GrantedToIdentitiesV2.Application.Id -eq '{clientId}' }",
|
|
175
|
+
"Update-MgSitePermission -SiteId $site.Id -PermissionId $p.Id -Roles '{site_role}'"
|
|
176
|
+
],
|
|
177
|
+
"shell": "powershell"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"request": "Hello, please grant the Microsoft app {brand.microsoft.appName} (application ID {clientId}) {site_role} access to the SharePoint site {site}. It is the app our AI agents use, and it reaches only the sites it is given. A SharePoint or Global Administrator can do it with Microsoft Graph PowerShell:\n\n{grantCommands}\n\nThank you.",
|
|
181
|
+
"write": ["write_files", "write_sheets"]
|
|
182
|
+
},
|
|
183
|
+
"verify": {
|
|
184
|
+
"label": "Microsoft permissions the app has",
|
|
185
|
+
"check": "permissions",
|
|
186
|
+
"ifEmpty": "The app has no Microsoft Graph application permissions yet. Add the permissions above and grant admin consent."
|
|
187
|
+
},
|
|
188
|
+
"discover": {
|
|
189
|
+
"label": "Sites agents can use",
|
|
190
|
+
"check": "sites",
|
|
191
|
+
"ifEmpty": "No sites yet. Add the sites agents may use below."
|
|
192
|
+
},
|
|
193
|
+
"revoke": "Remove the app's access to each site (Remove-MgSitePermission), or remove its Sites.Selected and Sites.Read.All permissions. To stop every Microsoft app at once, remove the app registration (see the Microsoft connection)."
|
|
194
|
+
}
|