@credal/actions 0.2.146 → 0.2.148
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/autogen/templates.js +4 -0
- package/dist/actions/autogen/types.d.ts +3 -0
- package/dist/actions/autogen/types.js +1 -0
- package/dist/actions/groups.js +1 -14
- package/dist/actions/providers/google-oauth/getDriveFileContentById.js +24 -27
- package/dist/actions/providers/googlemail/searchGmailMessages.d.ts +14 -0
- package/dist/actions/providers/googlemail/searchGmailMessages.js +42 -24
- package/dist/actions/providers/salesforce/getSalesforceRecordByQuery.d.ts +3 -0
- package/dist/actions/providers/salesforce/getSalesforceRecordByQuery.js +43 -0
- package/dist/actions/providers/slack/archiveChannel.js +2 -9
- package/dist/actions/providers/slackUser/searchSlack.js +68 -32
- package/package.json +1 -1
- package/dist/actions/providers/confluence/updatePage.d.ts +0 -3
- package/dist/actions/providers/confluence/updatePage.js +0 -47
- package/dist/actions/providers/jamf/types.d.ts +0 -8
- package/dist/actions/providers/jamf/types.js +0 -7
|
@@ -7951,6 +7951,10 @@ export const googlemailSearchGmailMessagesDefinition = {
|
|
|
7951
7951
|
type: "number",
|
|
7952
7952
|
description: "Maximum number of messages to return (optional)",
|
|
7953
7953
|
},
|
|
7954
|
+
timeout: {
|
|
7955
|
+
type: "number",
|
|
7956
|
+
description: "Timeout for the query in seconds (optional)",
|
|
7957
|
+
},
|
|
7954
7958
|
},
|
|
7955
7959
|
},
|
|
7956
7960
|
output: {
|
|
@@ -5091,12 +5091,15 @@ export type googleOauthQueryGoogleBigQueryFunction = ActionFunction<googleOauthQ
|
|
|
5091
5091
|
export declare const googlemailSearchGmailMessagesParamsSchema: z.ZodObject<{
|
|
5092
5092
|
query: z.ZodString;
|
|
5093
5093
|
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
5094
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
5094
5095
|
}, "strip", z.ZodTypeAny, {
|
|
5095
5096
|
query: string;
|
|
5096
5097
|
maxResults?: number | undefined;
|
|
5098
|
+
timeout?: number | undefined;
|
|
5097
5099
|
}, {
|
|
5098
5100
|
query: string;
|
|
5099
5101
|
maxResults?: number | undefined;
|
|
5102
|
+
timeout?: number | undefined;
|
|
5100
5103
|
}>;
|
|
5101
5104
|
export type googlemailSearchGmailMessagesParamsType = z.infer<typeof googlemailSearchGmailMessagesParamsSchema>;
|
|
5102
5105
|
export declare const googlemailSearchGmailMessagesOutputSchema: z.ZodObject<{
|
|
@@ -2943,6 +2943,7 @@ export const googleOauthQueryGoogleBigQueryOutputSchema = z.object({
|
|
|
2943
2943
|
export const googlemailSearchGmailMessagesParamsSchema = z.object({
|
|
2944
2944
|
query: z.string().describe('Gmail search query (e.g. "from:alice subject:urgent")'),
|
|
2945
2945
|
maxResults: z.number().describe("Maximum number of messages to return (optional)").optional(),
|
|
2946
|
+
timeout: z.number().describe("Timeout for the query in seconds (optional)").optional(),
|
|
2946
2947
|
});
|
|
2947
2948
|
export const googlemailSearchGmailMessagesOutputSchema = z.object({
|
|
2948
2949
|
success: z.boolean(),
|
package/dist/actions/groups.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { genericFillTemplateDefinition, confluenceOverwritePageDefinition, googlemapsValidateAddressDefinition, mathAddDefinition, mongoInsertMongoDocDefinition, slackSendMessageDefinition, slackGetChannelMessagesDefinition, slackCreateChannelDefinition, slackArchiveChannelDefinition, snowflakeGetRowByFieldValueDefinition, zendeskCreateZendeskTicketDefinition, zendeskListZendeskTicketsDefinition, zendeskGetTicketDetailsDefinition, zendeskUpdateTicketStatusDefinition, zendeskAddCommentToTicketDefinition, zendeskAssignTicketDefinition, openstreetmapGetLatitudeLongitudeFromLocationDefinition, nwsGetForecastForLocationDefinition, jiraAssignJiraTicketDefinition, jiraCommentJiraTicketDefinition, jiraCreateJiraTicketDefinition, jiraGetJiraTicketDetailsDefinition, jiraGetJiraTicketHistoryDefinition, jiraUpdateJiraTicketDetailsDefinition, jiraUpdateJiraTicketStatusDefinition, jiraGetServiceDesksDefinition, jiraCreateServiceDeskRequestDefinition, googlemapsNearbysearchRestaurantsDefinition, firecrawlScrapeUrlDefinition, resendSendEmailDefinition, linkedinCreateShareLinkedinPostUrlDefinition, googleOauthCreateNewGoogleDocDefinition, xCreateShareXPostUrlDefinition, firecrawlScrapeTweetDataWithNitterDefinition, finnhubSymbolLookupDefinition, finnhubGetBasicFinancialsDefinition, confluenceFetchPageContentDefinition, snowflakeRunSnowflakeQueryDefinition, lookerEnableUserByEmailDefinition, googleOauthUpdateDocDefinition, googleOauthScheduleCalendarMeetingDefinition, googleOauthListCalendarsDefinition, googleOauthListCalendarEventsDefinition, googleOauthUpdateCalendarEventDefinition, googleOauthDeleteCalendarEventDefinition, googleOauthCreateSpreadsheetDefinition, googleOauthUpdateSpreadsheetDefinition, googleOauthCreatePresentationDefinition, googleOauthUpdatePresentationDefinition, googleOauthSearchDriveByKeywordsDefinition, googlemailSearchGmailMessagesDefinition, googlemailListGmailThreadsDefinition, googleOauthListGroupsDefinition, googleOauthGetGroupDefinition, googleOauthListGroupMembersDefinition, googleOauthHasGroupMemberDefinition, googleOauthAddGroupMemberDefinition, googleOauthDeleteGroupMemberDefinition, salesforceUpdateRecordDefinition, salesforceCreateCaseDefinition, salesforceGenerateSalesReportDefinition, salesforceGetRecordDefinition, salesforceGetSalesforceRecordsByQueryDefinition, microsoftMessageTeamsChatDefinition, microsoftMessageTeamsChannelDefinition, asanaCommentTaskDefinition, asanaCreateTaskDefinition, asanaUpdateTaskDefinition, asanaSearchTasksDefinition, githubCreateOrUpdateFileDefinition, githubCreateBranchDefinition, githubCreatePullRequestDefinition, microsoftUpdateSpreadsheetDefinition, microsoftUpdateDocumentDefinition, microsoftCreateDocumentDefinition, microsoftGetDocumentDefinition, salesforceFetchSalesforceSchemaByObjectDefinition, firecrawlDeepResearchDefinition, jiraGetJiraIssuesByQueryDefinition, githubListPullRequestsDefinition, salesforceCreateRecordDefinition, ashbyCreateNoteDefinition, ashbyGetCandidateInfoDefinition, ashbyListCandidatesDefinition, ashbyListCandidateNotesDefinition, ashbySearchCandidatesDefinition, ashbyCreateCandidateDefinition, ashbyUpdateCandidateDefinition, ashbyAddCandidateToProjectDefinition, bingGetTopNSearchResultUrlsDefinition, gongGetGongTranscriptsDefinition, kandjiGetFVRecoveryKeyForDeviceDefinition, asanaListAsanaTasksByProjectDefinition, notionSearchByTitleDefinition, asanaGetTasksDetailsDefinition,
|
|
1
|
+
import { genericFillTemplateDefinition, confluenceOverwritePageDefinition, googlemapsValidateAddressDefinition, mathAddDefinition, mongoInsertMongoDocDefinition, slackSendMessageDefinition, slackGetChannelMessagesDefinition, slackCreateChannelDefinition, slackArchiveChannelDefinition, snowflakeGetRowByFieldValueDefinition, zendeskCreateZendeskTicketDefinition, zendeskListZendeskTicketsDefinition, zendeskGetTicketDetailsDefinition, zendeskUpdateTicketStatusDefinition, zendeskAddCommentToTicketDefinition, zendeskAssignTicketDefinition, openstreetmapGetLatitudeLongitudeFromLocationDefinition, nwsGetForecastForLocationDefinition, jiraAssignJiraTicketDefinition, jiraCommentJiraTicketDefinition, jiraCreateJiraTicketDefinition, jiraGetJiraTicketDetailsDefinition, jiraGetJiraTicketHistoryDefinition, jiraUpdateJiraTicketDetailsDefinition, jiraUpdateJiraTicketStatusDefinition, jiraGetServiceDesksDefinition, jiraCreateServiceDeskRequestDefinition, googlemapsNearbysearchRestaurantsDefinition, firecrawlScrapeUrlDefinition, resendSendEmailDefinition, linkedinCreateShareLinkedinPostUrlDefinition, googleOauthCreateNewGoogleDocDefinition, xCreateShareXPostUrlDefinition, firecrawlScrapeTweetDataWithNitterDefinition, finnhubSymbolLookupDefinition, finnhubGetBasicFinancialsDefinition, confluenceFetchPageContentDefinition, snowflakeRunSnowflakeQueryDefinition, lookerEnableUserByEmailDefinition, googleOauthUpdateDocDefinition, googleOauthScheduleCalendarMeetingDefinition, googleOauthListCalendarsDefinition, googleOauthListCalendarEventsDefinition, googleOauthUpdateCalendarEventDefinition, googleOauthDeleteCalendarEventDefinition, googleOauthCreateSpreadsheetDefinition, googleOauthUpdateSpreadsheetDefinition, googleOauthCreatePresentationDefinition, googleOauthUpdatePresentationDefinition, googleOauthSearchDriveByKeywordsDefinition, googlemailSearchGmailMessagesDefinition, googlemailListGmailThreadsDefinition, googleOauthListGroupsDefinition, googleOauthGetGroupDefinition, googleOauthListGroupMembersDefinition, googleOauthHasGroupMemberDefinition, googleOauthAddGroupMemberDefinition, googleOauthDeleteGroupMemberDefinition, salesforceUpdateRecordDefinition, salesforceCreateCaseDefinition, salesforceGenerateSalesReportDefinition, salesforceGetRecordDefinition, salesforceGetSalesforceRecordsByQueryDefinition, microsoftMessageTeamsChatDefinition, microsoftMessageTeamsChannelDefinition, asanaCommentTaskDefinition, asanaCreateTaskDefinition, asanaUpdateTaskDefinition, asanaSearchTasksDefinition, githubCreateOrUpdateFileDefinition, githubCreateBranchDefinition, githubCreatePullRequestDefinition, microsoftUpdateSpreadsheetDefinition, microsoftUpdateDocumentDefinition, microsoftCreateDocumentDefinition, microsoftGetDocumentDefinition, salesforceFetchSalesforceSchemaByObjectDefinition, firecrawlDeepResearchDefinition, jiraGetJiraIssuesByQueryDefinition, githubListPullRequestsDefinition, salesforceCreateRecordDefinition, ashbyCreateNoteDefinition, ashbyGetCandidateInfoDefinition, ashbyListCandidatesDefinition, ashbyListCandidateNotesDefinition, ashbySearchCandidatesDefinition, ashbyCreateCandidateDefinition, ashbyUpdateCandidateDefinition, ashbyAddCandidateToProjectDefinition, bingGetTopNSearchResultUrlsDefinition, gongGetGongTranscriptsDefinition, kandjiGetFVRecoveryKeyForDeviceDefinition, asanaListAsanaTasksByProjectDefinition, notionSearchByTitleDefinition, asanaGetTasksDetailsDefinition, jamfGetJamfComputerInventoryDefinition, jamfGetJamfFileVaultRecoveryKeyDefinition, oktaListOktaUsersDefinition, oktaGetOktaUserDefinition, oktaListOktaUserGroupsDefinition, oktaListOktaGroupsDefinition, oktaGetOktaGroupDefinition, oktaListOktaGroupMembersDefinition, oktaRemoveUserFromGroupDefinition, oktaAddUserToGroupDefinition, oktaResetPasswordDefinition, oktaResetMFADefinition, oktaListMFADefinition, jamfGetJamfUserComputerIdDefinition, jamfLockJamfComputerByIdDefinition, oktaTriggerOktaWorkflowDefinition, jiraOrgAssignJiraTicketDefinition, jiraOrgCreateJiraTicketDefinition, jiraOrgCommentJiraTicketDefinition, jiraOrgGetJiraTicketDetailsDefinition, jiraOrgGetJiraTicketHistoryDefinition, jiraOrgUpdateJiraTicketDetailsDefinition, jiraOrgUpdateJiraTicketStatusDefinition, jiraOrgGetJiraIssuesByQueryDefinition, googleOauthGetDriveFileContentByIdDefinition, googleOauthSearchDriveByQueryDefinition, } from "./autogen/templates.js";
|
|
2
2
|
export const ACTION_GROUPS = {
|
|
3
3
|
GENERIC: {
|
|
4
4
|
description: "Generic utility actions",
|
|
@@ -47,7 +47,6 @@ export const ACTION_GROUPS = {
|
|
|
47
47
|
googleOauthUpdatePresentationDefinition,
|
|
48
48
|
googleOauthSearchDriveByKeywordsDefinition,
|
|
49
49
|
googleOauthSearchDriveByQueryDefinition,
|
|
50
|
-
googleOauthSearchDriveByQueryAndGetFileContentDefinition,
|
|
51
50
|
googleOauthGetDriveFileContentByIdDefinition,
|
|
52
51
|
],
|
|
53
52
|
},
|
|
@@ -199,8 +198,6 @@ export const ACTION_GROUPS = {
|
|
|
199
198
|
githubCreateBranchDefinition,
|
|
200
199
|
githubCreatePullRequestDefinition,
|
|
201
200
|
githubListPullRequestsDefinition,
|
|
202
|
-
githubGetFileContentDefinition,
|
|
203
|
-
githubListDirectoryDefinition,
|
|
204
201
|
],
|
|
205
202
|
},
|
|
206
203
|
ASHBY: {
|
|
@@ -248,14 +245,4 @@ export const ACTION_GROUPS = {
|
|
|
248
245
|
oktaTriggerOktaWorkflowDefinition,
|
|
249
246
|
],
|
|
250
247
|
},
|
|
251
|
-
LINEAR: {
|
|
252
|
-
description: "Actions for interacting with Linear",
|
|
253
|
-
actions: [
|
|
254
|
-
linearGetIssueDetailsDefinition,
|
|
255
|
-
linearGetProjectsDefinition,
|
|
256
|
-
linearGetProjectDetailsDefinition,
|
|
257
|
-
linearGetTeamDetailsDefinition,
|
|
258
|
-
linearGetTeamsDefinition,
|
|
259
|
-
],
|
|
260
|
-
},
|
|
261
248
|
};
|
|
@@ -16,6 +16,8 @@ import { read, utils } from "xlsx";
|
|
|
16
16
|
import officeParser from "officeparser";
|
|
17
17
|
const BASE_WEB_URL = "https://drive.google.com/file/d/";
|
|
18
18
|
const BASE_API_URL = "https://www.googleapis.com/drive/v3/files/";
|
|
19
|
+
const NEWLINE_REGEX = /\r?\n+/g;
|
|
20
|
+
const WHITESPACE_REGEX = / +/g;
|
|
19
21
|
const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
|
|
20
22
|
var _b, _c, _d, _e;
|
|
21
23
|
if (!authParams.authToken) {
|
|
@@ -31,7 +33,10 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
|
|
|
31
33
|
`?fields=name,mimeType,size,driveId,parents,` +
|
|
32
34
|
`shortcutDetails(targetId,targetMimeType)` +
|
|
33
35
|
`&supportsAllDrives=true`;
|
|
34
|
-
const res = yield axiosClient.get(metaUrl, {
|
|
36
|
+
const res = yield axiosClient.get(metaUrl, {
|
|
37
|
+
headers,
|
|
38
|
+
timeout: timeoutLimit,
|
|
39
|
+
});
|
|
35
40
|
return res.data;
|
|
36
41
|
});
|
|
37
42
|
try {
|
|
@@ -97,15 +102,8 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
|
|
|
97
102
|
};
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
|
-
else if (mimeType === "text/plain" || mimeType === "text/html" || mimeType === "application/rtf") {
|
|
101
|
-
const downloadUrl = `${BASE_API_URL}${encodeURIComponent(params.fileId)}?alt=media${sharedDriveParam}`;
|
|
102
|
-
const downloadRes = yield axiosClient.get(downloadUrl, {
|
|
103
|
-
headers,
|
|
104
|
-
responseType: "text",
|
|
105
|
-
});
|
|
106
|
-
content = downloadRes.data;
|
|
107
|
-
}
|
|
108
105
|
else if (mimeType === "text/plain" ||
|
|
106
|
+
mimeType === "text/html" ||
|
|
109
107
|
mimeType === "text/csv" ||
|
|
110
108
|
mimeType === "text/tab-separated-values" ||
|
|
111
109
|
mimeType === "application/rtf" ||
|
|
@@ -113,11 +111,9 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
|
|
|
113
111
|
const downloadUrl = `${BASE_API_URL}${encodeURIComponent(params.fileId)}?alt=media${sharedDriveParam}`;
|
|
114
112
|
const downloadRes = yield axiosClient.get(downloadUrl, {
|
|
115
113
|
headers,
|
|
116
|
-
responseType: "
|
|
114
|
+
responseType: "text",
|
|
117
115
|
});
|
|
118
|
-
|
|
119
|
-
const rawContentBuffer = Buffer.from(bufferResults); // Convert rawContent ArrayBuffer to Buffer
|
|
120
|
-
content = rawContentBuffer.toString("utf-8");
|
|
116
|
+
content = downloadRes.data;
|
|
121
117
|
}
|
|
122
118
|
else if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
|
|
123
119
|
mimeType === "application/vnd.ms-excel") {
|
|
@@ -127,16 +123,21 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
|
|
|
127
123
|
responseType: "arraybuffer",
|
|
128
124
|
});
|
|
129
125
|
// 1. Read the buffer into a workbook
|
|
130
|
-
const workbook = read(downloadRes.data, { type: "buffer" });
|
|
126
|
+
const workbook = read(downloadRes.data, { type: "buffer", sheetStubs: false });
|
|
127
|
+
// Convert sheets to CSV with early termination if charLimit is set
|
|
128
|
+
const sheetTexts = [];
|
|
129
|
+
let totalLength = 0;
|
|
130
|
+
const effectiveLimit = charLimit ? charLimit * 1.5 : 100000; // Process 1.5x limit for safety
|
|
131
131
|
// 2. Convert all sheets to plain text (CSV-style)
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
for (const sheetName of workbook.SheetNames) {
|
|
133
|
+
if (totalLength >= effectiveLimit)
|
|
134
|
+
break; // Early termination
|
|
134
135
|
const sheet = workbook.Sheets[sheetName];
|
|
135
|
-
const csv = utils.sheet_to_csv(sheet);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
content =
|
|
136
|
+
const csv = utils.sheet_to_csv(sheet);
|
|
137
|
+
sheetTexts.push(`--- Sheet: ${sheetName} ---\n${csv}`);
|
|
138
|
+
totalLength += csv.length;
|
|
139
|
+
}
|
|
140
|
+
content = sheetTexts.join("\n").trim();
|
|
140
141
|
}
|
|
141
142
|
else if (mimeType === "application/vnd.openxmlformats-officedocument.presentationml.presentation") {
|
|
142
143
|
// Handle modern PowerPoint files (.pptx only)
|
|
@@ -160,14 +161,10 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
|
|
|
160
161
|
else {
|
|
161
162
|
return { success: false, error: `Unsupported file type: ${mimeType}` };
|
|
162
163
|
}
|
|
163
|
-
// 5)
|
|
164
|
-
content = (content !== null && content !== void 0 ? content : "")
|
|
165
|
-
.trim()
|
|
166
|
-
.replace(/\r?\n+/g, " ")
|
|
167
|
-
.replace(/ +/g, " ");
|
|
164
|
+
// 5) Apply content limit early, then normalize whitespace
|
|
168
165
|
const originalLength = content.length;
|
|
166
|
+
content = content.trim().replace(NEWLINE_REGEX, " ").replace(WHITESPACE_REGEX, " ");
|
|
169
167
|
if (charLimit && content.length > charLimit) {
|
|
170
|
-
// TODO in the future do this around the most valuable snippet of the doc?
|
|
171
168
|
content = content.slice(0, charLimit);
|
|
172
169
|
}
|
|
173
170
|
return {
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
export interface GmailMessageResult {
|
|
2
|
+
id: string;
|
|
3
|
+
threadId: string;
|
|
4
|
+
snippet: string;
|
|
5
|
+
labelIds?: string[];
|
|
6
|
+
internalDate: string;
|
|
7
|
+
emailBody: string;
|
|
8
|
+
from?: string;
|
|
9
|
+
to?: string;
|
|
10
|
+
subject?: string;
|
|
11
|
+
cc?: string;
|
|
12
|
+
bcc?: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
1
15
|
import type { googlemailSearchGmailMessagesFunction } from "../../autogen/types.js";
|
|
2
16
|
declare const searchGmailMessages: googlemailSearchGmailMessagesFunction;
|
|
3
17
|
export default searchGmailMessages;
|
|
@@ -15,12 +15,16 @@ const MAX_EMAIL_CONTENTS_FETCHED = 50;
|
|
|
15
15
|
const DEFAULT_EMAIL_CONTENTS_FETCHED = 25;
|
|
16
16
|
const MAX_RESULTS_PER_REQUEST = 100;
|
|
17
17
|
const MAX_EMAILS_FETCHED_CONCURRENTLY = 5;
|
|
18
|
+
const DEFAULT_EMAIL_FETCH_TIMEOUT = 5000; // 5 second timeout per email
|
|
18
19
|
const limiter = new RateLimiter({ tokensPerInterval: MAX_EMAILS_FETCHED_CONCURRENTLY, interval: "second" });
|
|
20
|
+
const QUOTED_REPLY_REGEX = /^>.*$/gm;
|
|
21
|
+
const NEWLINE_NORMALIZE_REGEX = /\r\n|\r/g;
|
|
22
|
+
const MULTIPLE_NEWLINES_REGEX = /\n{3,}/g;
|
|
19
23
|
function cleanAndTruncateEmail(text, maxLength = 2000) {
|
|
20
24
|
if (!text)
|
|
21
25
|
return "";
|
|
22
|
-
// Remove quoted replies
|
|
23
|
-
text = text.replace(
|
|
26
|
+
// Remove quoted replies
|
|
27
|
+
text = text.replace(QUOTED_REPLY_REGEX, "");
|
|
24
28
|
// Remove signatures
|
|
25
29
|
const signatureMarkers = ["\nBest", "\nRegards", "\nThanks", "\nSincerely"];
|
|
26
30
|
for (const marker of signatureMarkers) {
|
|
@@ -31,17 +35,14 @@ function cleanAndTruncateEmail(text, maxLength = 2000) {
|
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
// Normalize whitespace
|
|
34
|
-
text = text
|
|
35
|
-
.replace(/\r\n|\r/g, "\n")
|
|
36
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
37
|
-
.trim();
|
|
38
|
+
text = text.replace(NEWLINE_NORMALIZE_REGEX, "\n").replace(MULTIPLE_NEWLINES_REGEX, "\n\n").trim();
|
|
38
39
|
return text.slice(0, maxLength).trim();
|
|
39
40
|
}
|
|
40
41
|
const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
|
|
41
42
|
if (!authParams.authToken) {
|
|
42
43
|
return { success: false, error: MISSING_AUTH_TOKEN, messages: [] };
|
|
43
44
|
}
|
|
44
|
-
const { query, maxResults } = params;
|
|
45
|
+
const { query, maxResults, timeout } = params;
|
|
45
46
|
const max = Math.min(maxResults !== null && maxResults !== void 0 ? maxResults : DEFAULT_EMAIL_CONTENTS_FETCHED, MAX_EMAIL_CONTENTS_FETCHED);
|
|
46
47
|
const allMessages = [];
|
|
47
48
|
const errorMessages = [];
|
|
@@ -49,9 +50,11 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
|
|
|
49
50
|
let fetched = 0;
|
|
50
51
|
try {
|
|
51
52
|
while (fetched < max) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
// Calculate the optimal batch size for this request
|
|
54
|
+
const batchSize = Math.min(MAX_RESULTS_PER_REQUEST, // API maximum
|
|
55
|
+
max - fetched, // Only fetch what we still need
|
|
56
|
+
MAX_EMAILS_FETCHED_CONCURRENTLY);
|
|
57
|
+
const url = `https://gmail.googleapis.com/gmail/v1/users/me/messages?q=${encodeURIComponent(query)}&maxResults=${batchSize}${pageToken ? `&pageToken=${encodeURIComponent(pageToken)}` : ""}`;
|
|
55
58
|
const listRes = yield axiosClient.get(url, {
|
|
56
59
|
headers: { Authorization: `Bearer ${authParams.authToken}` },
|
|
57
60
|
});
|
|
@@ -59,35 +62,42 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
|
|
|
59
62
|
if (!Array.isArray(messageList) || messageList.length === 0)
|
|
60
63
|
break;
|
|
61
64
|
const batch = messageList.slice(0, max - allMessages.length);
|
|
62
|
-
const results = yield Promise.
|
|
65
|
+
const results = yield Promise.allSettled(batch.map((msg) => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
66
|
try {
|
|
64
67
|
yield limiter.removeTokens(1);
|
|
65
68
|
const msgRes = yield axiosClient.get(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${msg.id}?format=full`, {
|
|
66
69
|
headers: { Authorization: `Bearer ${authParams.authToken}` },
|
|
70
|
+
timeout: timeout ? timeout * 1000 : DEFAULT_EMAIL_FETCH_TIMEOUT,
|
|
67
71
|
validateStatus: () => true,
|
|
68
72
|
});
|
|
69
73
|
const { id, threadId, snippet, labelIds, internalDate, payload } = msgRes.data;
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const headers = {};
|
|
75
|
+
for (const header of payload.headers) {
|
|
76
|
+
const lowerName = header.name.toLowerCase();
|
|
77
|
+
if (lowerName === "from" ||
|
|
78
|
+
lowerName === "to" ||
|
|
79
|
+
lowerName === "subject" ||
|
|
80
|
+
lowerName === "cc" ||
|
|
81
|
+
lowerName === "bcc") {
|
|
82
|
+
headers[lowerName] = header.value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
76
85
|
const rawBody = getEmailContent(msgRes.data) || "";
|
|
77
86
|
const emailBody = cleanAndTruncateEmail(rawBody);
|
|
78
|
-
|
|
87
|
+
const message = {
|
|
79
88
|
id,
|
|
80
89
|
threadId,
|
|
81
90
|
snippet,
|
|
82
91
|
labelIds,
|
|
83
92
|
internalDate,
|
|
84
93
|
emailBody,
|
|
85
|
-
from:
|
|
86
|
-
to:
|
|
87
|
-
subject:
|
|
88
|
-
cc:
|
|
89
|
-
bcc:
|
|
94
|
+
from: headers.from,
|
|
95
|
+
to: headers.to,
|
|
96
|
+
subject: headers.subject,
|
|
97
|
+
cc: headers.cc,
|
|
98
|
+
bcc: headers.bcc,
|
|
90
99
|
};
|
|
100
|
+
return message;
|
|
91
101
|
}
|
|
92
102
|
catch (err) {
|
|
93
103
|
const errorMessage = err instanceof Error ? err.message : "Failed to fetch message details";
|
|
@@ -108,7 +118,15 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
|
|
|
108
118
|
};
|
|
109
119
|
}
|
|
110
120
|
})));
|
|
111
|
-
|
|
121
|
+
const successfulResults = results
|
|
122
|
+
.filter((r) => r.status === "fulfilled")
|
|
123
|
+
.map(r => r.value);
|
|
124
|
+
const failedResults = results.filter((r) => r.status === "rejected");
|
|
125
|
+
failedResults.forEach(r => {
|
|
126
|
+
const errorMessage = r.reason instanceof Error ? r.reason.message : "Failed to fetch message details";
|
|
127
|
+
errorMessages.push(errorMessage);
|
|
128
|
+
});
|
|
129
|
+
allMessages.push(...successfulResults);
|
|
112
130
|
fetched = allMessages.length;
|
|
113
131
|
if (!nextPageToken || fetched >= max)
|
|
114
132
|
break;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const axiosClient_1 = require("../../util/axiosClient");
|
|
13
|
+
const getSalesforceRecordByQuery = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
|
|
14
|
+
const { authToken, baseUrl } = authParams;
|
|
15
|
+
const { query, limit } = params;
|
|
16
|
+
if (!authToken || !baseUrl) {
|
|
17
|
+
return {
|
|
18
|
+
success: false,
|
|
19
|
+
error: "authToken and baseUrl are required for Salesforce API",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// The API limits the maximum number of records returned to 2000, the limit lets the user set a smaller custom limit
|
|
23
|
+
const url = `${baseUrl}/services/data/v56.0/query/?q=${encodeURIComponent(query + " LIMIT " + (limit != undefined && limit <= 2000 ? limit : 2000))}`;
|
|
24
|
+
try {
|
|
25
|
+
const response = yield axiosClient_1.axiosClient.get(url, {
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: `Bearer ${authToken}`,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
success: true,
|
|
32
|
+
records: response.data,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error("Error retrieving Salesforce record:", error);
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: error instanceof Error ? error.message : "An unknown error occurred",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
exports.default = getSalesforceRecordByQuery;
|
|
@@ -9,21 +9,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { WebClient } from "@slack/web-api";
|
|
11
11
|
import { MISSING_AUTH_TOKEN } from "../../util/missingAuthConstants.js";
|
|
12
|
-
import { getSlackChannels } from "./helpers.js";
|
|
13
12
|
const archiveChannel = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
|
|
14
13
|
if (!authParams.authToken) {
|
|
15
14
|
throw new Error(MISSING_AUTH_TOKEN);
|
|
16
15
|
}
|
|
17
16
|
try {
|
|
18
17
|
const client = new WebClient(authParams.authToken);
|
|
19
|
-
const {
|
|
20
|
-
const
|
|
21
|
-
const channel = allChannels.find(channel => channel.name == channelName);
|
|
22
|
-
if (!channel || !channel.id) {
|
|
23
|
-
throw Error(`Channel with name ${channelName} not found`);
|
|
24
|
-
}
|
|
25
|
-
yield client.conversations.join({ channel: channel.id });
|
|
26
|
-
const result = yield client.conversations.archive({ channel: channel.id });
|
|
18
|
+
const { channelId } = params;
|
|
19
|
+
const result = yield client.conversations.archive({ channel: channelId });
|
|
27
20
|
if (!result.ok) {
|
|
28
21
|
return {
|
|
29
22
|
success: false,
|
|
@@ -22,24 +22,37 @@ class SlackUserCache {
|
|
|
22
22
|
constructor(client) {
|
|
23
23
|
this.client = client;
|
|
24
24
|
this.cache = new Map();
|
|
25
|
+
this.pendingRequests = new Map();
|
|
25
26
|
this.client = client;
|
|
26
27
|
}
|
|
27
28
|
get(id) {
|
|
28
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
30
30
|
const cached = this.cache.get(id);
|
|
31
31
|
if (cached)
|
|
32
32
|
return cached;
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
const pending = this.pendingRequests.get(id);
|
|
34
|
+
if (pending)
|
|
35
|
+
return pending;
|
|
36
|
+
const promise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
38
|
+
try {
|
|
39
|
+
const res = yield this.client.users.info({ user: id });
|
|
40
|
+
const u = {
|
|
41
|
+
name: (_g = (_e = (_c = (_b = (_a = res.user) === null || _a === void 0 ? void 0 : _a.profile) === null || _b === void 0 ? void 0 : _b.display_name) !== null && _c !== void 0 ? _c : (_d = res.user) === null || _d === void 0 ? void 0 : _d.real_name) !== null && _e !== void 0 ? _e : (_f = res.user) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : "",
|
|
42
|
+
email: (_k = (_j = (_h = res.user) === null || _h === void 0 ? void 0 : _h.profile) === null || _j === void 0 ? void 0 : _j.email) !== null && _k !== void 0 ? _k : "",
|
|
43
|
+
};
|
|
44
|
+
if (res.user && id) {
|
|
45
|
+
this.cache.set(id, u);
|
|
46
|
+
return u;
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
this.pendingRequests.delete(id);
|
|
52
|
+
}
|
|
53
|
+
}))();
|
|
54
|
+
this.pendingRequests.set(id, promise);
|
|
55
|
+
return promise;
|
|
43
56
|
});
|
|
44
57
|
}
|
|
45
58
|
set(id, { email, name }) {
|
|
@@ -47,6 +60,12 @@ class SlackUserCache {
|
|
|
47
60
|
}
|
|
48
61
|
}
|
|
49
62
|
/* ===================== Helpers ===================== */
|
|
63
|
+
function normalizeChannelOperand(ch) {
|
|
64
|
+
const s = ch.trim();
|
|
65
|
+
if (/^[CGD][A-Z0-9]/i.test(s))
|
|
66
|
+
return s;
|
|
67
|
+
return s.replace(/^#/, "");
|
|
68
|
+
}
|
|
50
69
|
function fmtDaysAgo(n) {
|
|
51
70
|
const d = new Date();
|
|
52
71
|
d.setDate(d.getDate() - n);
|
|
@@ -224,7 +243,7 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
|
|
|
224
243
|
throw new Error(MISSING_AUTH_TOKEN);
|
|
225
244
|
const client = new WebClient(authParams.authToken);
|
|
226
245
|
const cache = new SlackUserCache(client);
|
|
227
|
-
const { emails, topic, timeRange, limit = 20 } = params;
|
|
246
|
+
const { emails, topic, timeRange, limit = 20, channel } = params;
|
|
228
247
|
const { user_id: myUserId } = yield client.auth.test();
|
|
229
248
|
if (!myUserId)
|
|
230
249
|
throw new Error("Failed to get my user ID.");
|
|
@@ -232,41 +251,58 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
|
|
|
232
251
|
const targetIds = (emails === null || emails === void 0 ? void 0 : emails.length) ? yield lookupUserIdsByEmail(client, emails, cache) : [];
|
|
233
252
|
const filteredTargetIds = targetIds.filter(id => id !== myUserId);
|
|
234
253
|
const allMatches = [];
|
|
235
|
-
// ---
|
|
254
|
+
// --- Parallel search execution for better performance ---
|
|
255
|
+
const searchPromises = [];
|
|
256
|
+
// Scoped DM/MPIM searches
|
|
236
257
|
if (filteredTargetIds.length === 1) {
|
|
237
|
-
|
|
258
|
+
searchPromises.push(searchScoped({ client, scope: `<@${filteredTargetIds[0]}>`, topic, timeRange, limit }));
|
|
238
259
|
}
|
|
239
260
|
else if (filteredTargetIds.length >= 2) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
261
|
+
// Run MPIM lookup and individual DM searches in parallel
|
|
262
|
+
const searchMPIM = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
263
|
+
const mpimName = yield tryGetMPIMName(client, filteredTargetIds);
|
|
264
|
+
return mpimName ? searchScoped({ client, scope: mpimName, topic, timeRange, limit }) : [];
|
|
265
|
+
});
|
|
266
|
+
searchPromises.push(searchMPIM());
|
|
267
|
+
// Add individual DM searches
|
|
268
|
+
searchPromises.push(...filteredTargetIds.map(id => searchScoped({ client, scope: `<@${id}>`, topic, timeRange, limit })));
|
|
269
|
+
}
|
|
270
|
+
else if (channel) {
|
|
271
|
+
searchPromises.push(searchScoped({ client, scope: normalizeChannelOperand(channel), topic, timeRange, limit }));
|
|
247
272
|
}
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
273
|
+
// Topic-wide search in parallel
|
|
274
|
+
searchPromises.push(...(topic ? [searchByTopic({ client, topic, timeRange, limit })] : []));
|
|
275
|
+
// Execute all searches in parallel
|
|
276
|
+
const searchResults = yield Promise.all(searchPromises);
|
|
277
|
+
searchResults.forEach(matches => allMatches.push(...matches));
|
|
251
278
|
// --- Expand hits with context + filter overlap ---
|
|
279
|
+
// Create a channel info cache to avoid redundant API calls
|
|
280
|
+
const channelInfoCache = new Map();
|
|
252
281
|
const expanded = yield Promise.all(allMatches.map(m => limitHit(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
253
|
-
var _a, _b, _c, _d, _e, _f;
|
|
282
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
254
283
|
if (!m.ts || !((_a = m.channel) === null || _a === void 0 ? void 0 : _a.id))
|
|
255
284
|
return null;
|
|
256
285
|
const anchor = yield fetchOneMessage(client, m.channel.id, m.ts);
|
|
257
286
|
const rootTs = (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts) || m.ts;
|
|
258
287
|
let members = [];
|
|
259
|
-
// Check convo type (DM, MPIM, channel)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
288
|
+
// Check convo type (DM, MPIM, channel) with caching
|
|
289
|
+
let channelInfo = channelInfoCache.get(m.channel.id);
|
|
290
|
+
if (!channelInfo) {
|
|
291
|
+
const convoInfo = yield client.conversations.info({ channel: m.channel.id });
|
|
292
|
+
channelInfo = {
|
|
293
|
+
isIm: (_c = (_b = convoInfo.channel) === null || _b === void 0 ? void 0 : _b.is_im) !== null && _c !== void 0 ? _c : false,
|
|
294
|
+
isMpim: (_e = (_d = convoInfo.channel) === null || _d === void 0 ? void 0 : _d.is_mpim) !== null && _e !== void 0 ? _e : false,
|
|
295
|
+
};
|
|
296
|
+
channelInfoCache.set(m.channel.id, channelInfo);
|
|
297
|
+
}
|
|
298
|
+
const { isIm, isMpim } = channelInfo;
|
|
263
299
|
const [contextMsgs, permalink] = (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts)
|
|
264
300
|
? [yield fetchThread(client, m.channel.id, rootTs), yield getPermalink(client, m.channel.id, rootTs)]
|
|
265
301
|
: [yield fetchContextWindow(client, m.channel.id, m.ts), yield getPermalink(client, m.channel.id, m.ts)];
|
|
266
302
|
let passesFilter = false;
|
|
267
303
|
if (isIm || isMpim) {
|
|
268
304
|
// DM/MPIM: use members, not authorship
|
|
269
|
-
const membersRes = (
|
|
305
|
+
const membersRes = (_f = (yield client.conversations.members({ channel: m.channel.id })).members) !== null && _f !== void 0 ? _f : [];
|
|
270
306
|
members = yield Promise.all(membersRes.map((uid) => __awaiter(void 0, void 0, void 0, function* () {
|
|
271
307
|
const u = yield cache.get(uid);
|
|
272
308
|
return { userId: uid, userEmail: u === null || u === void 0 ? void 0 : u.email, userName: u === null || u === void 0 ? void 0 : u.name };
|
|
@@ -293,8 +329,8 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
|
|
|
293
329
|
channelId: m.channel.id,
|
|
294
330
|
ts: rootTs,
|
|
295
331
|
text: (anchor === null || anchor === void 0 ? void 0 : anchor.text) ? yield expandSlackEntities(client, cache, anchor.text) : undefined,
|
|
296
|
-
userEmail: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (
|
|
297
|
-
userName: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (
|
|
332
|
+
userEmail: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_g = (yield cache.get(anchor.user))) === null || _g === void 0 ? void 0 : _g.email : undefined,
|
|
333
|
+
userName: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_h = (yield cache.get(anchor.user))) === null || _h === void 0 ? void 0 : _h.name : undefined,
|
|
298
334
|
context,
|
|
299
335
|
permalink,
|
|
300
336
|
members,
|
package/package.json
CHANGED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const axios_1 = __importDefault(require("axios"));
|
|
16
|
-
function getConfluenceApi(baseUrl, username, apiToken) {
|
|
17
|
-
const api = axios_1.default.create({
|
|
18
|
-
baseURL: baseUrl,
|
|
19
|
-
headers: {
|
|
20
|
-
Accept: "application/json",
|
|
21
|
-
// Tokens are associated with a specific user.
|
|
22
|
-
Authorization: `Basic ${Buffer.from(`${username}:${apiToken}`).toString("base64")}`,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
return api;
|
|
26
|
-
}
|
|
27
|
-
const confluenceUpdatePage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
|
|
28
|
-
const { pageId, username, content, title } = params;
|
|
29
|
-
const { baseUrl, authToken } = authParams;
|
|
30
|
-
const api = getConfluenceApi(baseUrl, username, authToken);
|
|
31
|
-
// Get current version number
|
|
32
|
-
const response = yield api.get(`/api/v2/pages/${pageId}`);
|
|
33
|
-
const currVersion = response.data.version.number;
|
|
34
|
-
yield api.put(`/api/v2/pages/${pageId}`, {
|
|
35
|
-
id: pageId,
|
|
36
|
-
status: "current",
|
|
37
|
-
title,
|
|
38
|
-
body: {
|
|
39
|
-
representation: "storage",
|
|
40
|
-
value: content,
|
|
41
|
-
},
|
|
42
|
-
version: {
|
|
43
|
-
number: currVersion + 1,
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
exports.default = confluenceUpdatePage;
|