runline 0.11.2 → 0.11.4

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.
Files changed (31) hide show
  1. package/dist/plugin/loader.js +5 -0
  2. package/dist/plugins/googleDocs/src/documents.js +91 -0
  3. package/dist/plugins/googleDocs/src/formatting.js +126 -0
  4. package/dist/plugins/googleDocs/src/images.js +66 -0
  5. package/dist/plugins/googleDocs/src/index.js +45 -1008
  6. package/dist/plugins/googleDocs/src/shared.js +110 -0
  7. package/dist/plugins/googleDocs/src/structure.js +392 -0
  8. package/dist/plugins/googleDocs/src/tables.js +390 -0
  9. package/dist/plugins/googleDocs/src/tabs.js +77 -0
  10. package/dist/plugins/googleDocs/src/text.js +313 -0
  11. package/dist/plugins/linear/src/attachments.js +36 -12
  12. package/dist/plugins/linear/src/comments.js +20 -8
  13. package/dist/plugins/linear/src/cycles.js +22 -8
  14. package/dist/plugins/linear/src/initiatives.js +59 -19
  15. package/dist/plugins/linear/src/issues.js +123 -41
  16. package/dist/plugins/linear/src/labels.js +31 -11
  17. package/dist/plugins/linear/src/organization.js +1 -1
  18. package/dist/plugins/linear/src/projects.js +171 -57
  19. package/dist/plugins/linear/src/shared.js +16 -5
  20. package/dist/plugins/linear/src/states.js +14 -6
  21. package/dist/plugins/linear/src/teams.js +35 -12
  22. package/dist/plugins/linear/src/users.js +7 -3
  23. package/dist/plugins/linear/src/views.js +29 -10
  24. package/dist/plugins/linear/src/webhooks.js +39 -13
  25. package/dist/plugins/salesforce/src/index.js +33 -219
  26. package/dist/plugins/salesforce/src/metadata.js +50 -0
  27. package/dist/plugins/salesforce/src/query.js +52 -0
  28. package/dist/plugins/salesforce/src/queryResult.js +4 -0
  29. package/dist/plugins/salesforce/src/shared.js +122 -0
  30. package/dist/plugins/salesforce/src/sobjects.js +152 -0
  31. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import * as t from "typebox";
2
- import { CUSTOM_VIEW_FIELDS, FEED_ITEM_FIELDS, INITIATIVE_FIELDS, ISSUE_LITE, LIST_INPUT_SCHEMA, PROJECT_FIELDS, bindGetAction, bindListAction, buildConnArgs, gql, key, mergeIssueScopeFilter, requireUnscoped, } from "./shared.js";
2
+ import { bindGetAction, bindListAction, buildConnArgs, CUSTOM_VIEW_FIELDS, FEED_ITEM_FIELDS, gql, INITIATIVE_FIELDS, ISSUE_LITE, key, LIST_INPUT_SCHEMA, mergeIssueScopeFilter, PROJECT_FIELDS, requireUnscoped, } from "./shared.js";
3
3
  const ISSUE_FILTER_DESCRIPTION = "IssueFilter payload. Examples: label { labels: { id: { in: ['label-id'] } } }; project { project: { id: { eq: 'project-id' } } }; assignee { assignee: { id: { eq: 'user-id' } } }; state { state: { id: { eq: 'state-id' } } }; priority { priority: { eq: 1 } }; due window { dueDate: { gte: '2026-06-09', lte: '2026-06-16' } }; combine with and/or arrays.";
4
4
  export function registerViewActions(rl) {
5
5
  const listAction = bindListAction(rl);
@@ -11,7 +11,9 @@ export function registerViewActions(rl) {
11
11
  viewId: t.String({ description: "The custom view ID or slug" }),
12
12
  ...LIST_INPUT_SCHEMA,
13
13
  ...(includeSubTeamsDescription
14
- ? { includeSubTeams: t.Optional(t.Boolean({ description: includeSubTeamsDescription })) }
14
+ ? {
15
+ includeSubTeams: t.Optional(t.Boolean({ description: includeSubTeamsDescription })),
16
+ }
15
17
  : {}),
16
18
  }),
17
19
  async execute(input, ctx) {
@@ -24,7 +26,8 @@ export function registerViewActions(rl) {
24
26
  const { argsDecl, argsCall, vars } = buildConnArgs(scopedOpts, filterTypeName);
25
27
  const declParts = ["$id: String!", argsDecl.slice(1, -1)];
26
28
  const callParts = [argsCall.slice(1, -1)];
27
- const includeSubTeamsSet = includeSubTeamsDescription !== undefined && opts.includeSubTeams !== undefined;
29
+ const includeSubTeamsSet = includeSubTeamsDescription !== undefined &&
30
+ opts.includeSubTeams !== undefined;
28
31
  if (includeSubTeamsSet) {
29
32
  declParts.push("$includeSubTeams: Boolean");
30
33
  callParts.push("includeSubTeams: $includeSubTeams");
@@ -47,16 +50,22 @@ export function registerViewActions(rl) {
47
50
  description: t.Optional(t.String({ description: "The description of the custom view" })),
48
51
  icon: t.Optional(t.String({ description: "The icon of the custom view" })),
49
52
  color: t.Optional(t.String({ description: "The color of the custom view icon (hex)" })),
50
- shared: t.Optional(t.Boolean({ description: "false creates a personal view; true shares the view with the workspace or scoped container" })),
53
+ shared: t.Optional(t.Boolean({
54
+ description: "false creates a personal view; true shares the view with the workspace or scoped container",
55
+ })),
51
56
  filterData: t.Optional(t.Object({}, { description: ISSUE_FILTER_DESCRIPTION })),
52
57
  projectFilterData: t.Optional(t.Object({}, { description: "ProjectFilter for project views" })),
53
58
  initiativeFilterData: t.Optional(t.Object({}, { description: "InitiativeFilter for initiative views" })),
54
59
  feedItemFilterData: t.Optional(t.Object({}, { description: "FeedItemFilter for update/feed item views" })),
55
60
  teamId: t.Optional(t.String({ description: "Scope the view to a team" })),
56
61
  projectId: t.Optional(t.String({ description: "Scope the view to a project-specific view" })),
57
- initiativeId: t.Optional(t.String({ description: "Scope the view to an initiative-specific view" })),
62
+ initiativeId: t.Optional(t.String({
63
+ description: "Scope the view to an initiative-specific view",
64
+ })),
58
65
  ownerId: t.Optional(t.String({ description: "Set the user that owns the view" })),
59
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
66
+ id: t.Optional(t.String({
67
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
68
+ })),
60
69
  }),
61
70
  async execute(input, ctx) {
62
71
  requireUnscoped(ctx, "view.create");
@@ -67,19 +76,25 @@ export function registerViewActions(rl) {
67
76
  rl.registerAction("view.update", {
68
77
  description: "Update a custom view. All fields optional; only provided fields are updated.",
69
78
  inputSchema: t.Object({
70
- id: t.String({ description: "The identifier of the custom view to update" }),
79
+ id: t.String({
80
+ description: "The identifier of the custom view to update",
81
+ }),
71
82
  name: t.Optional(t.String({ description: "The name of the custom view" })),
72
83
  description: t.Optional(t.String({ description: "The description of the custom view" })),
73
84
  icon: t.Optional(t.String({ description: "The icon of the custom view" })),
74
85
  color: t.Optional(t.String({ description: "The color of the custom view icon (hex)" })),
75
- shared: t.Optional(t.Boolean({ description: "false creates a personal view; true shares the view with the workspace or scoped container" })),
86
+ shared: t.Optional(t.Boolean({
87
+ description: "false creates a personal view; true shares the view with the workspace or scoped container",
88
+ })),
76
89
  filterData: t.Optional(t.Object({}, { description: ISSUE_FILTER_DESCRIPTION })),
77
90
  projectFilterData: t.Optional(t.Object({}, { description: "ProjectFilter for project views" })),
78
91
  initiativeFilterData: t.Optional(t.Object({}, { description: "InitiativeFilter for initiative views" })),
79
92
  feedItemFilterData: t.Optional(t.Object({}, { description: "FeedItemFilter for update/feed item views" })),
80
93
  teamId: t.Optional(t.String({ description: "Scope the view to a team" })),
81
94
  projectId: t.Optional(t.String({ description: "Scope the view to a project-specific view" })),
82
- initiativeId: t.Optional(t.String({ description: "Scope the view to an initiative-specific view" })),
95
+ initiativeId: t.Optional(t.String({
96
+ description: "Scope the view to an initiative-specific view",
97
+ })),
83
98
  ownerId: t.Optional(t.String({ description: "Set the user that owns the view" })),
84
99
  }),
85
100
  async execute(input, ctx) {
@@ -91,7 +106,11 @@ export function registerViewActions(rl) {
91
106
  });
92
107
  rl.registerAction("view.delete", {
93
108
  description: "Delete a custom view.",
94
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the custom view to delete" }) }),
109
+ inputSchema: t.Object({
110
+ id: t.String({
111
+ description: "The identifier of the custom view to delete",
112
+ }),
113
+ }),
95
114
  async execute(input, ctx) {
96
115
  requireUnscoped(ctx, "view.delete");
97
116
  const data = await gql(key(ctx), `mutation($id: String!) { customViewDelete(id: $id) { success } }`, { id: input.id });
@@ -1,5 +1,5 @@
1
1
  import * as t from "typebox";
2
- import { WEBHOOK_FIELDS, bindGetAction, bindListAction, gql, key, requireUnscoped } from "./shared.js";
2
+ import { bindGetAction, bindListAction, gql, key, requireUnscoped, WEBHOOK_FIELDS, } from "./shared.js";
3
3
  export function registerWebhookActions(rl) {
4
4
  const listAction = bindListAction(rl);
5
5
  const getAction = bindGetAction(rl);
@@ -8,14 +8,28 @@ export function registerWebhookActions(rl) {
8
8
  rl.registerAction("webhook.create", {
9
9
  description: "Create a webhook. resourceTypes example: ['Issue','Comment','Project'].",
10
10
  inputSchema: t.Object({
11
- url: t.String({ description: "The URL that will be called on data changes" }),
12
- resourceTypes: t.Array(t.String(), { description: "List of resources the webhook should subscribe to (e.g. ['Issue','Comment'])" }),
11
+ url: t.String({
12
+ description: "The URL that will be called on data changes",
13
+ }),
14
+ resourceTypes: t.Array(t.String(), {
15
+ description: "List of resources the webhook should subscribe to (e.g. ['Issue','Comment'])",
16
+ }),
13
17
  label: t.Optional(t.String({ description: "Label for the webhook" })),
14
- teamId: t.Optional(t.String({ description: "The identifier or key of the team associated with the webhook. Omit and set allPublicTeams=true for workspace-wide" })),
15
- allPublicTeams: t.Optional(t.Boolean({ description: "Whether this webhook is enabled for all public teams" })),
16
- enabled: t.Optional(t.Boolean({ description: "Whether this webhook is enabled (default true)" })),
17
- secret: t.Optional(t.String({ description: "A secret token used to sign the webhook payload" })),
18
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
18
+ teamId: t.Optional(t.String({
19
+ description: "The identifier or key of the team associated with the webhook. Omit and set allPublicTeams=true for workspace-wide",
20
+ })),
21
+ allPublicTeams: t.Optional(t.Boolean({
22
+ description: "Whether this webhook is enabled for all public teams",
23
+ })),
24
+ enabled: t.Optional(t.Boolean({
25
+ description: "Whether this webhook is enabled (default true)",
26
+ })),
27
+ secret: t.Optional(t.String({
28
+ description: "A secret token used to sign the webhook payload",
29
+ })),
30
+ id: t.Optional(t.String({
31
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
32
+ })),
19
33
  }),
20
34
  async execute(input, ctx) {
21
35
  requireUnscoped(ctx, "webhooks.*");
@@ -27,11 +41,17 @@ export function registerWebhookActions(rl) {
27
41
  description: "Update a webhook. teamId and allPublicTeams cannot be changed after creation.",
28
42
  inputSchema: t.Object({
29
43
  id: t.String({ description: "The identifier of the webhook to update" }),
30
- url: t.Optional(t.String({ description: "The URL that will be called on data changes" })),
31
- resourceTypes: t.Optional(t.Array(t.String(), { description: "List of resources the webhook should subscribe to" })),
44
+ url: t.Optional(t.String({
45
+ description: "The URL that will be called on data changes",
46
+ })),
47
+ resourceTypes: t.Optional(t.Array(t.String(), {
48
+ description: "List of resources the webhook should subscribe to",
49
+ })),
32
50
  label: t.Optional(t.String({ description: "Label for the webhook" })),
33
51
  enabled: t.Optional(t.Boolean({ description: "Whether this webhook is enabled" })),
34
- secret: t.Optional(t.String({ description: "A secret token used to sign the webhook payload" })),
52
+ secret: t.Optional(t.String({
53
+ description: "A secret token used to sign the webhook payload",
54
+ })),
35
55
  }),
36
56
  async execute(input, ctx) {
37
57
  requireUnscoped(ctx, "webhooks.*");
@@ -42,7 +62,9 @@ export function registerWebhookActions(rl) {
42
62
  });
43
63
  rl.registerAction("webhook.delete", {
44
64
  description: "Delete a webhook.",
45
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the webhook to delete" }) }),
65
+ inputSchema: t.Object({
66
+ id: t.String({ description: "The identifier of the webhook to delete" }),
67
+ }),
46
68
  async execute(input, ctx) {
47
69
  requireUnscoped(ctx, "webhooks.*");
48
70
  const data = await gql(key(ctx), `mutation($id: String!) { webhookDelete(id: $id) { success } }`, { id: input.id });
@@ -51,7 +73,11 @@ export function registerWebhookActions(rl) {
51
73
  });
52
74
  rl.registerAction("webhook.rotateSecret", {
53
75
  description: "Rotate a webhook's signing secret. Returns the new secret.",
54
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the webhook to rotate the secret for" }) }),
76
+ inputSchema: t.Object({
77
+ id: t.String({
78
+ description: "The identifier of the webhook to rotate the secret for",
79
+ }),
80
+ }),
55
81
  async execute(input, ctx) {
56
82
  requireUnscoped(ctx, "webhooks.*");
57
83
  const data = await gql(key(ctx), `mutation($id: String!) { webhookRotateSecret(id: $id) { success secret } }`, { id: input.id });
@@ -1,224 +1,38 @@
1
- const API_VERSION = "v59.0";
2
- function getConn(ctx) {
3
- const c = ctx.connection.config;
4
- return {
5
- instanceUrl: c.instanceUrl.replace(/\/$/, ""),
6
- accessToken: c.accessToken,
7
- };
8
- }
9
- async function api(conn, method, endpoint, body, qs) {
10
- const url = new URL(`${conn.instanceUrl}/services/data/${API_VERSION}${endpoint}`);
11
- if (qs) {
12
- for (const [k, v] of Object.entries(qs)) {
13
- if (v !== undefined && v !== null)
14
- url.searchParams.set(k, String(v));
15
- }
16
- }
17
- const init = {
18
- method,
19
- headers: {
20
- Authorization: `Bearer ${conn.accessToken}`,
21
- "Content-Type": "application/json",
22
- },
23
- };
24
- if (body && Object.keys(body).length > 0)
25
- init.body = JSON.stringify(body);
26
- const res = await fetch(url.toString(), init);
27
- if (res.status === 204)
28
- return { success: true };
29
- if (!res.ok)
30
- throw new Error(`Salesforce error ${res.status}: ${await res.text()}`);
31
- return res.json();
32
- }
33
- const SOBJECTS = [
34
- "Account",
35
- "Contact",
36
- "Lead",
37
- "Opportunity",
38
- "Case",
39
- "Task",
40
- "User",
41
- ];
42
- const DEFAULT_FIELDS = {
43
- Account: "Id,Name,Type",
44
- Contact: "Id,FirstName,LastName,Email",
45
- Lead: "Id,Company,FirstName,LastName,Email,Status",
46
- Opportunity: "Id,AccountId,Amount,Probability,StageName",
47
- Case: "Id,AccountId,ContactId,Priority,Status,Subject",
48
- Task: "Id,Subject,Status,Priority",
49
- User: "Id,Name,Email",
50
- };
51
- function registerSObject(rl, sObject, conn) {
52
- const lower = sObject.toLowerCase();
53
- rl.registerAction(`${lower}.create`, {
54
- description: `Create a ${sObject}`,
55
- inputSchema: {
56
- data: {
57
- type: "object",
58
- required: true,
59
- description: `${sObject} field values`,
60
- },
61
- },
62
- async execute(input, ctx) {
63
- return api(conn(ctx), "POST", `/sobjects/${sObject}`, input.data);
64
- },
65
- });
66
- rl.registerAction(`${lower}.get`, {
67
- description: `Get a ${sObject} by ID`,
68
- inputSchema: { id: { type: "string", required: true } },
69
- async execute(input, ctx) {
70
- return api(conn(ctx), "GET", `/sobjects/${sObject}/${input.id}`);
71
- },
72
- });
73
- rl.registerAction(`${lower}.update`, {
74
- description: `Update a ${sObject}`,
75
- inputSchema: {
76
- id: { type: "string", required: true },
77
- data: { type: "object", required: true },
78
- },
79
- async execute(input, ctx) {
80
- const p = input;
81
- await api(conn(ctx), "PATCH", `/sobjects/${sObject}/${p.id}`, p.data);
82
- return { success: true, id: p.id };
83
- },
84
- });
85
- rl.registerAction(`${lower}.delete`, {
86
- description: `Delete a ${sObject}`,
87
- inputSchema: { id: { type: "string", required: true } },
88
- async execute(input, ctx) {
89
- await api(conn(ctx), "DELETE", `/sobjects/${sObject}/${input.id}`);
90
- return { success: true };
91
- },
92
- });
93
- rl.registerAction(`${lower}.query`, {
94
- description: `Query ${sObject}s with SOQL`,
95
- inputSchema: {
96
- fields: {
97
- type: "string",
98
- required: false,
99
- description: `Comma-separated (default: ${DEFAULT_FIELDS[sObject] ?? "Id"})`,
100
- },
101
- where: {
102
- type: "string",
103
- required: false,
104
- description: "SOQL WHERE clause",
105
- },
106
- limit: { type: "number", required: false },
107
- },
108
- async execute(input, ctx) {
109
- const p = (input ?? {});
110
- const fields = p.fields || DEFAULT_FIELDS[sObject] || "Id";
111
- let q = `SELECT ${fields} FROM ${sObject}`;
112
- if (p.where)
113
- q += ` WHERE ${p.where}`;
114
- if (p.limit)
115
- q += ` LIMIT ${p.limit}`;
116
- const data = (await api(conn(ctx), "GET", "/query", undefined, {
117
- q,
118
- }));
119
- return data.records;
120
- },
121
- });
122
- rl.registerAction(`${lower}.upsert`, {
123
- description: `Upsert a ${sObject} by external ID`,
124
- inputSchema: {
125
- externalIdField: { type: "string", required: true },
126
- externalIdValue: { type: "string", required: true },
127
- data: { type: "object", required: true },
128
- },
129
- async execute(input, ctx) {
130
- const p = input;
131
- return api(conn(ctx), "PATCH", `/sobjects/${sObject}/${p.externalIdField}/${p.externalIdValue}`, p.data);
132
- },
133
- });
134
- }
1
+ import * as t from "typebox";
2
+ import { registerMetadataActions } from "./metadata.js";
3
+ import { registerQueryActions } from "./query.js";
4
+ import { registerGenericSObjectActions, registerStandardSObjectActions, } from "./sobjects.js";
135
5
  export default function salesforce(rl) {
136
6
  rl.setName("salesforce");
137
- rl.setVersion("0.1.0");
138
- rl.setConnectionSchema({
139
- instanceUrl: {
140
- type: "string",
141
- required: true,
142
- description: "Salesforce instance URL (e.g. https://yourorg.my.salesforce.com)",
7
+ rl.setVersion("0.2.0");
8
+ rl.setConnectionSchema(t.Object({
9
+ instanceUrl: t.Optional(t.String({
10
+ description: "Salesforce API instance URL, e.g. https://your-domain.my.salesforce.com. Required for static accessToken auth; optional for client credentials when loginUrl is set.",
143
11
  env: "SALESFORCE_INSTANCE_URL",
144
- },
145
- accessToken: {
146
- type: "string",
147
- required: true,
148
- description: "Salesforce OAuth2 access token",
12
+ })),
13
+ accessToken: t.Optional(t.String({
14
+ description: "Salesforce OAuth2 access token. Use for static-token auth.",
149
15
  env: "SALESFORCE_ACCESS_TOKEN",
150
- },
151
- });
152
- for (const sObject of SOBJECTS) {
153
- registerSObject(rl, sObject, getConn);
154
- }
155
- // ── Generic sObject ─────────────────────────────────
156
- rl.registerAction("sobject.create", {
157
- description: "Create any sObject record",
158
- inputSchema: {
159
- sObject: { type: "string", required: true },
160
- data: { type: "object", required: true },
161
- },
162
- async execute(input, ctx) {
163
- const p = input;
164
- return api(getConn(ctx), "POST", `/sobjects/${p.sObject}`, p.data);
165
- },
166
- });
167
- rl.registerAction("sobject.get", {
168
- description: "Get any sObject record",
169
- inputSchema: {
170
- sObject: { type: "string", required: true },
171
- id: { type: "string", required: true },
172
- },
173
- async execute(input, ctx) {
174
- const p = input;
175
- return api(getConn(ctx), "GET", `/sobjects/${p.sObject}/${p.id}`);
176
- },
177
- });
178
- rl.registerAction("sobject.update", {
179
- description: "Update any sObject record",
180
- inputSchema: {
181
- sObject: { type: "string", required: true },
182
- id: { type: "string", required: true },
183
- data: { type: "object", required: true },
184
- },
185
- async execute(input, ctx) {
186
- const p = input;
187
- await api(getConn(ctx), "PATCH", `/sobjects/${p.sObject}/${p.id}`, p.data);
188
- return { success: true };
189
- },
190
- });
191
- rl.registerAction("sobject.delete", {
192
- description: "Delete any sObject record",
193
- inputSchema: {
194
- sObject: { type: "string", required: true },
195
- id: { type: "string", required: true },
196
- },
197
- async execute(input, ctx) {
198
- const p = input;
199
- await api(getConn(ctx), "DELETE", `/sobjects/${p.sObject}/${p.id}`);
200
- return { success: true };
201
- },
202
- });
203
- // ── SOQL Query ──────────────────────────────────────
204
- rl.registerAction("soql.query", {
205
- description: "Execute a raw SOQL query",
206
- inputSchema: {
207
- query: { type: "string", required: true, description: "Full SOQL query" },
208
- },
209
- async execute(input, ctx) {
210
- const data = (await api(getConn(ctx), "GET", "/query", undefined, {
211
- q: input.query,
212
- }));
213
- return data.records;
214
- },
215
- });
216
- // ── Describe ────────────────────────────────────────
217
- rl.registerAction("sobject.describe", {
218
- description: "Describe an sObject's metadata/fields",
219
- inputSchema: { sObject: { type: "string", required: true } },
220
- async execute(input, ctx) {
221
- return api(getConn(ctx), "GET", `/sobjects/${input.sObject}/describe`);
222
- },
223
- });
16
+ })),
17
+ loginUrl: t.Optional(t.String({
18
+ description: "Salesforce OAuth token host for client credentials, usually your My Domain URL such as https://your-domain.my.salesforce.com.",
19
+ env: "SALESFORCE_LOGIN_URL",
20
+ })),
21
+ clientId: t.Optional(t.String({
22
+ description: "Salesforce Connected App consumer key for OAuth client credentials flow.",
23
+ env: "SALESFORCE_CLIENT_ID",
24
+ })),
25
+ clientSecret: t.Optional(t.String({
26
+ description: "Salesforce Connected App consumer secret for OAuth client credentials flow.",
27
+ env: "SALESFORCE_CLIENT_SECRET",
28
+ })),
29
+ apiVersion: t.Optional(t.String({
30
+ description: "Salesforce REST API version (default v59.0). Accepts vXX.0 or XX.0.",
31
+ env: "SALESFORCE_API_VERSION",
32
+ })),
33
+ }));
34
+ registerMetadataActions(rl);
35
+ registerQueryActions(rl);
36
+ registerStandardSObjectActions(rl);
37
+ registerGenericSObjectActions(rl);
224
38
  }
@@ -0,0 +1,50 @@
1
+ import * as t from "typebox";
2
+ import { api, getSession, identity } from "./shared.js";
3
+ export function registerMetadataActions(rl) {
4
+ rl.registerAction("connection.test", {
5
+ description: "Validate Salesforce auth and return safe connection metadata",
6
+ inputSchema: t.Object({}),
7
+ async execute(_input, ctx) {
8
+ const sessionPromise = getSession(ctx);
9
+ const session = await sessionPromise;
10
+ let limits;
11
+ let limitsError;
12
+ try {
13
+ limits = (await api(ctx, "GET", "/limits", undefined, undefined, sessionPromise));
14
+ }
15
+ catch (error) {
16
+ limitsError = error instanceof Error ? error.message : String(error);
17
+ }
18
+ return {
19
+ ok: true,
20
+ instanceUrl: session.instanceUrl,
21
+ tokenType: session.tokenType,
22
+ scope: session.scope,
23
+ id: session.id,
24
+ limits,
25
+ limitsError,
26
+ };
27
+ },
28
+ });
29
+ rl.registerAction("auth.identity", {
30
+ description: "Return the Salesforce OAuth identity for the current connection",
31
+ inputSchema: t.Object({}),
32
+ async execute(_input, ctx) {
33
+ return identity(ctx);
34
+ },
35
+ });
36
+ rl.registerAction("limits.get", {
37
+ description: "Return Salesforce org REST API limits",
38
+ inputSchema: t.Object({}),
39
+ async execute(_input, ctx) {
40
+ return api(ctx, "GET", "/limits");
41
+ },
42
+ });
43
+ rl.registerAction("metadata.objects", {
44
+ description: "List available Salesforce sObjects and metadata summaries",
45
+ inputSchema: t.Object({}),
46
+ async execute(_input, ctx) {
47
+ return api(ctx, "GET", "/sobjects");
48
+ },
49
+ });
50
+ }
@@ -0,0 +1,52 @@
1
+ import * as t from "typebox";
2
+ import { records } from "./queryResult.js";
3
+ import { api, rest } from "./shared.js";
4
+ const QueryInput = t.Object({
5
+ query: t.String({ description: "Full SOQL query" }),
6
+ });
7
+ async function queryPage(ctx, endpoint, query) {
8
+ return (await api(ctx, "GET", endpoint, undefined, {
9
+ q: query,
10
+ }));
11
+ }
12
+ export function registerQueryActions(rl) {
13
+ rl.registerAction("soql.query", {
14
+ description: "Execute a raw SOQL query and return the first page of records",
15
+ inputSchema: QueryInput,
16
+ async execute(input, ctx) {
17
+ return records(await queryPage(ctx, "/query", input.query));
18
+ },
19
+ });
20
+ rl.registerAction("soql.queryPage", {
21
+ description: "Execute a raw SOQL query and return Salesforce pagination metadata",
22
+ inputSchema: QueryInput,
23
+ async execute(input, ctx) {
24
+ return queryPage(ctx, "/query", input.query);
25
+ },
26
+ });
27
+ rl.registerAction("soql.queryAll", {
28
+ description: "Execute a raw SOQL query including deleted and archived records; returns the first page of records",
29
+ inputSchema: QueryInput,
30
+ async execute(input, ctx) {
31
+ return records(await queryPage(ctx, "/queryAll", input.query));
32
+ },
33
+ });
34
+ rl.registerAction("soql.queryAllPage", {
35
+ description: "Execute a raw SOQL query including deleted and archived records and return Salesforce pagination metadata",
36
+ inputSchema: QueryInput,
37
+ async execute(input, ctx) {
38
+ return queryPage(ctx, "/queryAll", input.query);
39
+ },
40
+ });
41
+ rl.registerAction("soql.nextPage", {
42
+ description: "Fetch the next page from a Salesforce nextRecordsUrl returned by soql.queryPage or soql.queryAllPage",
43
+ inputSchema: t.Object({
44
+ nextRecordsUrl: t.String({
45
+ description: "Salesforce nextRecordsUrl, e.g. /services/data/v59.0/query/01g...",
46
+ }),
47
+ }),
48
+ async execute(input, ctx) {
49
+ return rest(ctx, "GET", input.nextRecordsUrl);
50
+ },
51
+ });
52
+ }
@@ -0,0 +1,4 @@
1
+ export function records(data) {
2
+ const value = data.records;
3
+ return Array.isArray(value) ? value : [];
4
+ }