Skip to content

Commit 4724422

Browse files
committed
feat(knowledge): enable per-member access on every permission-scoped connector
Google Slides, Docs, Forms, Calendar, Gmail, Notion, Jira, Jira Service Management, Box, Dropbox, monday, ClickUp, Asana, Salesforce, Linear, DocuSign, and Zoom list only what the caller's own account can read, so each now declares its listing caps and can sync per member. A shared listing-scope error lets a connector report a folder, space, board, or calendar the member cannot reach as a complete listing of nothing; Notion and Asana report it from their typed errors, Dropbox from its 409, and the Atlassian connectors also from an unreachable site. Google Docs and Forms join the credential-group providers so their accounts can be collected per person.
1 parent 37db0a2 commit 4724422

31 files changed

Lines changed: 156 additions & 14 deletions

File tree

‎apps/sim/connectors/asana/asana.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ async function listWorkspaceProjects(
314314
export const asanaConnector: ConnectorConfig = {
315315
...asanaConnectorMeta,
316316

317+
isListingScopeUnavailableError: (error) => error instanceof AsanaApiError && error.status === 404,
318+
317319
listDocuments: async (
318320
accessToken: string,
319321
sourceConfig: Record<string, unknown>,

‎apps/sim/connectors/asana/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const asanaConnectorMeta: ConnectorMeta = {
1010

1111
auth: { mode: 'oauth', provider: 'asana', requiredScopes: ['default'] },
1212

13+
permissionScopedListing: { capFieldIds: ['maxTasks'] },
1314
configFields: [
1415
{
1516
id: 'workspaceSelector',

‎apps/sim/connectors/box/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const boxConnectorMeta: ConnectorMeta = {
1414
requiredScopes: ['root_readwrite'],
1515
},
1616

17+
permissionScopedListing: { capFieldIds: ['maxFiles'] },
1718
configFields: [
1819
{
1920
id: 'folderId',

‎apps/sim/connectors/clickup/clickup.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { isRecordLike } from '@sim/utils/object'
44
import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils'
55
import { clickupConnectorMeta } from '@/connectors/clickup/meta'
66
import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types'
7-
import { parseTagDate } from '@/connectors/utils'
7+
import {
8+
isListingScopeUnavailableError,
9+
listingRequestError,
10+
parseTagDate,
11+
} from '@/connectors/utils'
812
import { clickupAuthorizationHeader, extractClickUpErrorMessage } from '@/tools/clickup/shared'
913

1014
const logger = createLogger('ClickUpConnector')
@@ -159,6 +163,8 @@ function getRequiredWorkspaceId(sourceConfig: Record<string, unknown>): string {
159163
export const clickupConnector: ConnectorConfig = {
160164
...clickupConnectorMeta,
161165

166+
isListingScopeUnavailableError: isListingScopeUnavailableError,
167+
162168
listDocuments: async (
163169
accessToken: string,
164170
sourceConfig: Record<string, unknown>,
@@ -181,7 +187,7 @@ export const clickupConnector: ConnectorConfig = {
181187
if (!response.ok) {
182188
const errorText = await response.text()
183189
logger.error('Failed to list ClickUp Docs', { status: response.status, error: errorText })
184-
throw new Error(`Failed to list ClickUp Docs: ${response.status}`)
190+
throw listingRequestError('Failed to list ClickUp Docs', response.status)
185191
}
186192

187193
const data = (await response.json()) as Record<string, unknown>

‎apps/sim/connectors/clickup/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const clickupConnectorMeta: ConnectorMeta = {
1313
provider: 'clickup',
1414
},
1515

16+
permissionScopedListing: { capFieldIds: ['maxDocs'] },
1617
configFields: [
1718
{
1819
id: 'workspaceSelector',

‎apps/sim/connectors/docusign/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const docusignConnectorMeta: ConnectorMeta = {
1616

1717
supportsIncrementalSync: true,
1818

19+
permissionScopedListing: { capFieldIds: ['maxEnvelopes'] },
1920
configFields: [
2021
{
2122
id: 'lookback',

‎apps/sim/connectors/dropbox/dropbox.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/
66
import {
77
CONNECTOR_MAX_FILE_BYTES,
88
ConnectorFileTooLargeError,
9+
ConnectorListingScopeUnavailableError,
910
htmlToPlainText,
11+
isListingScopeUnavailableError,
1012
isSkippedDocument,
1113
markSkipped,
1214
parseTagDate,
@@ -170,6 +172,8 @@ function fileToStub(entry: DropboxFileMetadata): ExternalDocument {
170172
export const dropboxConnector: ConnectorConfig = {
171173
...dropboxConnectorMeta,
172174

175+
isListingScopeUnavailableError: isListingScopeUnavailableError,
176+
173177
listDocuments: async (
174178
accessToken: string,
175179
sourceConfig: Record<string, unknown>,
@@ -227,7 +231,13 @@ export const dropboxConnector: ConnectorConfig = {
227231
status: response.status,
228232
error: errorText,
229233
})
230-
throw new Error(`Failed to list Dropbox folder: ${response.status}`)
234+
/** Dropbox reports a path the caller cannot reach as 409 path/not_found. */
235+
throw response.status === 409
236+
? new ConnectorListingScopeUnavailableError(
237+
`Failed to list Dropbox folder: ${response.status}`,
238+
response.status
239+
)
240+
: new Error(`Failed to list Dropbox folder: ${response.status}`)
231241
}
232242

233243
data = await response.json()

‎apps/sim/connectors/dropbox/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const dropboxConnectorMeta: ConnectorMeta = {
1414
requiredScopes: ['files.metadata.read', 'files.content.read'],
1515
},
1616

17+
permissionScopedListing: { capFieldIds: ['maxFiles'] },
1718
configFields: [
1819
{
1920
id: 'folderPath',

‎apps/sim/connectors/gmail/meta.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const gmailConnectorMeta: ConnectorMeta = {
1616
requiredScopes: ['https://www.googleapis.com/auth/gmail.modify'],
1717
},
1818

19+
permissionScopedListing: { capFieldIds: ['maxThreads'] },
1920
configFields: [
2021
{
2122
id: 'labelSelector',

‎apps/sim/connectors/google-calendar/google-calendar.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { getErrorMessage } from '@sim/utils/errors'
33
import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils'
44
import { DEFAULT_MAX_EVENTS, googleCalendarConnectorMeta } from '@/connectors/google-calendar/meta'
55
import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types'
6-
import { parseMultiValue, parseTagDate } from '@/connectors/utils'
6+
import {
7+
isListingScopeUnavailableError,
8+
listingRequestError,
9+
parseMultiValue,
10+
parseTagDate,
11+
} from '@/connectors/utils'
712

813
const logger = createLogger('GoogleCalendarConnector')
914

@@ -301,6 +306,8 @@ function eventToDocument(
301306
export const googleCalendarConnector: ConnectorConfig = {
302307
...googleCalendarConnectorMeta,
303308

309+
isListingScopeUnavailableError: isListingScopeUnavailableError,
310+
304311
listDocuments: async (
305312
accessToken: string,
306313
sourceConfig: Record<string, unknown>,
@@ -397,7 +404,7 @@ export const googleCalendarConnector: ConnectorConfig = {
397404
calendarId,
398405
error: errorText,
399406
})
400-
throw new Error(`Failed to list Google Calendar events: ${response.status}`)
407+
throw listingRequestError('Failed to list Google Calendar events', response.status)
401408
}
402409

403410
const data = await response.json()

0 commit comments

Comments
 (0)