@commandable/integration-data 0.0.1 → 0.0.5
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/credentials-index.d.ts +4 -21
- package/dist/credentials-index.d.ts.map +1 -1
- package/dist/credentials-index.js +407 -215
- package/dist/credentials-index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +38 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +70 -16
- package/dist/loader.js.map +1 -1
- package/integrations/__tests__/liveHarness.ts +84 -0
- package/integrations/__tests__/usageParity.ts +54 -0
- package/integrations/airtable/__tests__/get_handlers.test.ts +43 -31
- package/integrations/airtable/__tests__/usage_parity.test.ts +3 -29
- package/integrations/airtable/__tests__/write_and_admin_handlers.test.ts +20 -17
- package/integrations/airtable/credentials.json +21 -16
- package/integrations/github/__tests__/get_handlers.test.ts +101 -108
- package/integrations/github/__tests__/usage_parity.test.ts +15 -27
- package/integrations/github/__tests__/write_handlers.test.ts +223 -306
- package/integrations/github/credentials.json +40 -15
- package/integrations/github/credentials_hint_classic_pat.md +8 -0
- package/integrations/github/credentials_hint_fine_grained_pat.md +9 -0
- package/integrations/github/handlers/create_commit.js +2 -17
- package/integrations/github/manifest.json +2 -2
- package/integrations/google-calendar/__tests__/get_handlers.test.ts +21 -13
- package/integrations/google-calendar/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +24 -17
- package/integrations/google-calendar/credentials.json +50 -29
- package/integrations/google-calendar/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-calendar/credentials_hint_service_account.md +10 -0
- package/integrations/google-docs/__tests__/get_handlers.test.ts +87 -61
- package/integrations/google-docs/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-docs/__tests__/write_handlers.test.ts +251 -245
- package/integrations/google-docs/credentials.json +50 -29
- package/integrations/google-docs/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-docs/credentials_hint_service_account.md +10 -0
- package/integrations/google-docs/handlers/insert_inline_image_after_first_match.js +1 -1
- package/integrations/google-docs/schemas/insert_inline_image_after_first_match.json +0 -1
- package/integrations/google-drive/__tests__/handlers.test.ts +102 -0
- package/integrations/google-drive/credentials.json +57 -0
- package/integrations/google-drive/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-drive/credentials_hint_service_account.md +10 -0
- package/integrations/google-drive/handlers/create_file.js +15 -0
- package/integrations/google-drive/handlers/create_folder.js +15 -0
- package/integrations/google-drive/handlers/delete_file.js +14 -0
- package/integrations/google-drive/handlers/get_file.js +7 -0
- package/integrations/google-drive/handlers/move_file.js +12 -0
- package/integrations/google-drive/manifest.json +42 -0
- package/integrations/google-drive/schemas/create_file.json +12 -0
- package/integrations/google-drive/schemas/create_folder.json +11 -0
- package/integrations/google-drive/schemas/delete_file.json +10 -0
- package/integrations/google-drive/schemas/get_file.json +10 -0
- package/integrations/google-drive/schemas/move_file.json +12 -0
- package/integrations/google-sheet/__tests__/get_handlers.test.ts +48 -55
- package/integrations/google-sheet/__tests__/usage_parity.test.ts +3 -29
- package/integrations/google-sheet/__tests__/write_handlers.test.ts +65 -63
- package/integrations/google-sheet/credentials.json +50 -29
- package/integrations/google-sheet/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-sheet/credentials_hint_service_account.md +10 -0
- package/integrations/google-slides/__tests__/get_handlers.test.ts +38 -36
- package/integrations/google-slides/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-slides/__tests__/write_handlers.test.ts +65 -59
- package/integrations/google-slides/credentials.json +50 -29
- package/integrations/google-slides/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-slides/credentials_hint_service_account.md +10 -0
- package/integrations/notion/__tests__/get_handlers.test.ts +18 -15
- package/integrations/notion/__tests__/usage_parity.test.ts +3 -28
- package/integrations/notion/__tests__/write_and_admin_handlers.test.ts +56 -60
- package/integrations/notion/credentials.json +22 -17
- package/integrations/trello/__tests__/get_handlers.test.ts +58 -73
- package/integrations/trello/__tests__/usage_parity.test.ts +3 -28
- package/integrations/trello/__tests__/write_and_admin_handlers.test.ts +49 -67
- package/integrations/trello/credentials.json +26 -21
- package/integrations/trello/handlers/close_board.js +6 -0
- package/integrations/trello/handlers/create_board.js +11 -0
- package/integrations/trello/handlers/delete_board.js +13 -0
- package/integrations/trello/manifest.json +21 -0
- package/integrations/trello/schemas/close_board.json +10 -0
- package/integrations/trello/schemas/create_board.json +12 -0
- package/integrations/trello/schemas/delete_board.json +10 -0
- package/package.json +1 -1
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"type": "
|
|
7
|
-
"
|
|
8
|
-
|
|
2
|
+
"variants": {
|
|
3
|
+
"internal_integration": {
|
|
4
|
+
"label": "Internal Integration Token",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"token": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Internal Integration Token",
|
|
11
|
+
"description": "Notion internal integration token (starts with \"secret_\")."
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["token"],
|
|
15
|
+
"additionalProperties": false
|
|
16
|
+
},
|
|
17
|
+
"injection": {
|
|
18
|
+
"headers": {
|
|
19
|
+
"Authorization": "Bearer {{token}}",
|
|
20
|
+
"Notion-Version": "2022-06-28"
|
|
21
|
+
}
|
|
9
22
|
}
|
|
10
|
-
},
|
|
11
|
-
"required": ["token"],
|
|
12
|
-
"additionalProperties": false
|
|
13
|
-
},
|
|
14
|
-
"injection": {
|
|
15
|
-
"headers": {
|
|
16
|
-
"Authorization": "Bearer {{token}}",
|
|
17
|
-
"Notion-Version": "2022-06-28"
|
|
18
23
|
}
|
|
19
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"default": "internal_integration"
|
|
20
26
|
}
|
|
21
|
-
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import { loadIntegrationTools } from '../../../../server/src/integrations/dataLoader.js'
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv, safeCleanup } from '../../__tests__/liveHarness.js'
|
|
4
3
|
|
|
5
|
-
// This is a LIVE integration test suite that hits Trello using
|
|
4
|
+
// This is a LIVE integration test suite that hits Trello using credentials.
|
|
6
5
|
// Required env vars:
|
|
7
|
-
// - COMMANDABLE_MANAGED_OAUTH_BASE_URL
|
|
8
|
-
// - COMMANDABLE_MANAGED_OAUTH_SECRET_KEY
|
|
9
6
|
// - TRELLO_API_KEY
|
|
10
|
-
// -
|
|
7
|
+
// - TRELLO_API_TOKEN
|
|
11
8
|
|
|
12
9
|
interface Ids {
|
|
13
10
|
boardId?: string
|
|
@@ -16,68 +13,56 @@ interface Ids {
|
|
|
16
13
|
orgId?: string
|
|
17
14
|
}
|
|
18
15
|
|
|
19
|
-
const env = process.env as Record<string, string>
|
|
20
|
-
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
21
16
|
const suite = hasEnv(
|
|
22
|
-
'COMMANDABLE_MANAGED_OAUTH_BASE_URL',
|
|
23
|
-
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
24
17
|
'TRELLO_API_KEY',
|
|
25
|
-
'
|
|
18
|
+
'TRELLO_API_TOKEN',
|
|
26
19
|
)
|
|
27
20
|
? describe
|
|
28
21
|
: describe.skip
|
|
29
22
|
|
|
30
23
|
suite('trello read handlers (live)', () => {
|
|
31
24
|
const ids: Ids = {}
|
|
25
|
+
let boardId: string | undefined
|
|
26
|
+
let listId: string | undefined
|
|
32
27
|
|
|
33
|
-
let
|
|
28
|
+
let trello: ReturnType<typeof createToolbox>
|
|
34
29
|
|
|
35
30
|
beforeAll(async () => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const proxy =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Discover a board, list, card, and org for subsequent tests
|
|
59
|
-
const get_member_boards = buildHandler('get_member_boards')
|
|
60
|
-
const boards = await get_member_boards({})
|
|
61
|
-
expect(Array.isArray(boards)).toBe(true)
|
|
62
|
-
ids.boardId = boards[0]?.id
|
|
63
|
-
|
|
64
|
-
if (ids.boardId) {
|
|
65
|
-
const get_board_lists = buildHandler('get_board_lists')
|
|
66
|
-
const lists = await get_board_lists({ boardId: ids.boardId })
|
|
67
|
-
ids.listId = lists[0]?.id
|
|
68
|
-
|
|
69
|
-
const get_board_cards = buildHandler('get_board_cards')
|
|
70
|
-
const cards = await get_board_cards({ boardId: ids.boardId })
|
|
71
|
-
ids.cardId = cards[0]?.id
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const get_member_organizations = buildHandler('get_member_organizations')
|
|
31
|
+
const env = process.env as Record<string, string | undefined>
|
|
32
|
+
const credentialStore = createCredentialStore(async () => ({ apiKey: env.TRELLO_API_KEY || '', apiToken: env.TRELLO_API_TOKEN || '' }))
|
|
33
|
+
const proxy = createProxy(credentialStore)
|
|
34
|
+
const node = createIntegrationNode('trello', { label: 'Trello', credentialId: 'trello-creds' })
|
|
35
|
+
trello = createToolbox('trello', proxy, node)
|
|
36
|
+
|
|
37
|
+
// Create an isolated board/list/card for this run so tests don’t touch random user boards.
|
|
38
|
+
const board = await trello.write('create_board')({ name: `CmdTest Trello Read ${Date.now()}`, defaultLists: false })
|
|
39
|
+
boardId = board?.id
|
|
40
|
+
ids.boardId = boardId
|
|
41
|
+
expect(ids.boardId).toBeTruthy()
|
|
42
|
+
|
|
43
|
+
const list = await trello.write('create_list')({ idBoard: boardId, name: 'CmdTest List' })
|
|
44
|
+
listId = list?.id
|
|
45
|
+
ids.listId = listId
|
|
46
|
+
expect(ids.listId).toBeTruthy()
|
|
47
|
+
|
|
48
|
+
const card = await trello.write('create_card')({ idList: listId, name: `CmdTest Card ${Date.now()}` })
|
|
49
|
+
ids.cardId = card?.id
|
|
50
|
+
expect(ids.cardId).toBeTruthy()
|
|
51
|
+
|
|
52
|
+
const get_member_organizations = trello.read('get_member_organizations')
|
|
75
53
|
const orgs = await get_member_organizations({})
|
|
76
54
|
ids.orgId = orgs[0]?.id
|
|
77
55
|
}, 60000)
|
|
78
56
|
|
|
57
|
+
afterAll(async () => {
|
|
58
|
+
if (!boardId)
|
|
59
|
+
return
|
|
60
|
+
await safeCleanup(async () => trello.write('close_board')({ boardId }))
|
|
61
|
+
await safeCleanup(async () => trello.write('delete_board')({ boardId }))
|
|
62
|
+
}, 60_000)
|
|
63
|
+
|
|
79
64
|
it('get_member returns current member', async () => {
|
|
80
|
-
const handler =
|
|
65
|
+
const handler = trello.read('get_member')
|
|
81
66
|
const result = await handler({})
|
|
82
67
|
expect(result).toBeTruthy()
|
|
83
68
|
expect(typeof result.id).toBe('string')
|
|
@@ -85,13 +70,13 @@ suite('trello read handlers (live)', () => {
|
|
|
85
70
|
}, 30000)
|
|
86
71
|
|
|
87
72
|
it('get_member_boards returns an array', async () => {
|
|
88
|
-
const handler =
|
|
73
|
+
const handler = trello.read('get_member_boards')
|
|
89
74
|
const result = await handler({})
|
|
90
75
|
expect(Array.isArray(result)).toBe(true)
|
|
91
76
|
}, 30000)
|
|
92
77
|
|
|
93
78
|
it('get_member_organizations returns an array', async () => {
|
|
94
|
-
const handler =
|
|
79
|
+
const handler = trello.read('get_member_organizations')
|
|
95
80
|
const result = await handler({})
|
|
96
81
|
expect(Array.isArray(result)).toBe(true)
|
|
97
82
|
}, 30000)
|
|
@@ -99,7 +84,7 @@ suite('trello read handlers (live)', () => {
|
|
|
99
84
|
it('get_board works with boardId', async () => {
|
|
100
85
|
if (!ids.boardId)
|
|
101
86
|
return expect(true).toBe(true)
|
|
102
|
-
const handler =
|
|
87
|
+
const handler = trello.read('get_board')
|
|
103
88
|
const result = await handler({ boardId: ids.boardId })
|
|
104
89
|
expect(result?.id).toBe(ids.boardId)
|
|
105
90
|
}, 30000)
|
|
@@ -107,7 +92,7 @@ suite('trello read handlers (live)', () => {
|
|
|
107
92
|
it('get_board_lists returns lists', async () => {
|
|
108
93
|
if (!ids.boardId)
|
|
109
94
|
return expect(true).toBe(true)
|
|
110
|
-
const handler =
|
|
95
|
+
const handler = trello.read('get_board_lists')
|
|
111
96
|
const result = await handler({ boardId: ids.boardId })
|
|
112
97
|
expect(Array.isArray(result)).toBe(true)
|
|
113
98
|
}, 30000)
|
|
@@ -115,7 +100,7 @@ suite('trello read handlers (live)', () => {
|
|
|
115
100
|
it('get_board_cards returns cards', async () => {
|
|
116
101
|
if (!ids.boardId)
|
|
117
102
|
return expect(true).toBe(true)
|
|
118
|
-
const handler =
|
|
103
|
+
const handler = trello.read('get_board_cards')
|
|
119
104
|
const result = await handler({ boardId: ids.boardId })
|
|
120
105
|
expect(Array.isArray(result)).toBe(true)
|
|
121
106
|
}, 30000)
|
|
@@ -123,7 +108,7 @@ suite('trello read handlers (live)', () => {
|
|
|
123
108
|
it('get_board_members returns members', async () => {
|
|
124
109
|
if (!ids.boardId)
|
|
125
110
|
return expect(true).toBe(true)
|
|
126
|
-
const handler =
|
|
111
|
+
const handler = trello.read('get_board_members')
|
|
127
112
|
const result = await handler({ boardId: ids.boardId })
|
|
128
113
|
expect(Array.isArray(result)).toBe(true)
|
|
129
114
|
}, 30000)
|
|
@@ -131,7 +116,7 @@ suite('trello read handlers (live)', () => {
|
|
|
131
116
|
it('get_board_labels returns labels', async () => {
|
|
132
117
|
if (!ids.boardId)
|
|
133
118
|
return expect(true).toBe(true)
|
|
134
|
-
const handler =
|
|
119
|
+
const handler = trello.read('get_board_labels')
|
|
135
120
|
const result = await handler({ boardId: ids.boardId })
|
|
136
121
|
expect(Array.isArray(result)).toBe(true)
|
|
137
122
|
}, 30000)
|
|
@@ -139,7 +124,7 @@ suite('trello read handlers (live)', () => {
|
|
|
139
124
|
it('get_board_custom_fields returns custom fields', async () => {
|
|
140
125
|
if (!ids.boardId)
|
|
141
126
|
return expect(true).toBe(true)
|
|
142
|
-
const handler =
|
|
127
|
+
const handler = trello.read('get_board_custom_fields')
|
|
143
128
|
const result = await handler({ boardId: ids.boardId })
|
|
144
129
|
expect(Array.isArray(result)).toBe(true)
|
|
145
130
|
}, 30000)
|
|
@@ -147,7 +132,7 @@ suite('trello read handlers (live)', () => {
|
|
|
147
132
|
it('get_board_memberships returns memberships', async () => {
|
|
148
133
|
if (!ids.boardId)
|
|
149
134
|
return expect(true).toBe(true)
|
|
150
|
-
const handler =
|
|
135
|
+
const handler = trello.read('get_board_memberships')
|
|
151
136
|
const result = await handler({ boardId: ids.boardId })
|
|
152
137
|
expect(Array.isArray(result)).toBe(true)
|
|
153
138
|
}, 30000)
|
|
@@ -155,7 +140,7 @@ suite('trello read handlers (live)', () => {
|
|
|
155
140
|
it('get_list returns a list', async () => {
|
|
156
141
|
if (!ids.listId)
|
|
157
142
|
return expect(true).toBe(true)
|
|
158
|
-
const handler =
|
|
143
|
+
const handler = trello.read('get_list')
|
|
159
144
|
const result = await handler({ listId: ids.listId })
|
|
160
145
|
expect(result?.id).toBe(ids.listId)
|
|
161
146
|
}, 30000)
|
|
@@ -163,7 +148,7 @@ suite('trello read handlers (live)', () => {
|
|
|
163
148
|
it('get_list_cards returns cards in a list', async () => {
|
|
164
149
|
if (!ids.listId)
|
|
165
150
|
return expect(true).toBe(true)
|
|
166
|
-
const handler =
|
|
151
|
+
const handler = trello.read('get_list_cards')
|
|
167
152
|
const result = await handler({ listId: ids.listId })
|
|
168
153
|
expect(Array.isArray(result)).toBe(true)
|
|
169
154
|
}, 30000)
|
|
@@ -171,7 +156,7 @@ suite('trello read handlers (live)', () => {
|
|
|
171
156
|
it('get_card returns a card', async () => {
|
|
172
157
|
if (!ids.cardId)
|
|
173
158
|
return expect(true).toBe(true)
|
|
174
|
-
const handler =
|
|
159
|
+
const handler = trello.read('get_card')
|
|
175
160
|
const result = await handler({ cardId: ids.cardId })
|
|
176
161
|
expect(result?.id).toBe(ids.cardId)
|
|
177
162
|
}, 30000)
|
|
@@ -179,7 +164,7 @@ suite('trello read handlers (live)', () => {
|
|
|
179
164
|
it('get_card_members returns members for a card', async () => {
|
|
180
165
|
if (!ids.cardId)
|
|
181
166
|
return expect(true).toBe(true)
|
|
182
|
-
const handler =
|
|
167
|
+
const handler = trello.read('get_card_members')
|
|
183
168
|
const result = await handler({ cardId: ids.cardId })
|
|
184
169
|
expect(Array.isArray(result)).toBe(true)
|
|
185
170
|
}, 30000)
|
|
@@ -187,7 +172,7 @@ suite('trello read handlers (live)', () => {
|
|
|
187
172
|
it('get_card_attachments returns attachments for a card', async () => {
|
|
188
173
|
if (!ids.cardId)
|
|
189
174
|
return expect(true).toBe(true)
|
|
190
|
-
const handler =
|
|
175
|
+
const handler = trello.read('get_card_attachments')
|
|
191
176
|
const result = await handler({ cardId: ids.cardId })
|
|
192
177
|
expect(Array.isArray(result)).toBe(true)
|
|
193
178
|
}, 30000)
|
|
@@ -195,7 +180,7 @@ suite('trello read handlers (live)', () => {
|
|
|
195
180
|
it('get_card_actions returns actions for a card', async () => {
|
|
196
181
|
if (!ids.cardId)
|
|
197
182
|
return expect(true).toBe(true)
|
|
198
|
-
const handler =
|
|
183
|
+
const handler = trello.read('get_card_actions')
|
|
199
184
|
const result = await handler({ cardId: ids.cardId })
|
|
200
185
|
expect(Array.isArray(result)).toBe(true)
|
|
201
186
|
}, 30000)
|
|
@@ -203,7 +188,7 @@ suite('trello read handlers (live)', () => {
|
|
|
203
188
|
it('get_card_checklists returns checklists for a card', async () => {
|
|
204
189
|
if (!ids.cardId)
|
|
205
190
|
return expect(true).toBe(true)
|
|
206
|
-
const handler =
|
|
191
|
+
const handler = trello.read('get_card_checklists')
|
|
207
192
|
const result = await handler({ cardId: ids.cardId })
|
|
208
193
|
expect(Array.isArray(result)).toBe(true)
|
|
209
194
|
}, 30000)
|
|
@@ -211,7 +196,7 @@ suite('trello read handlers (live)', () => {
|
|
|
211
196
|
it('get_card_custom_field_items returns custom field items', async () => {
|
|
212
197
|
if (!ids.cardId)
|
|
213
198
|
return expect(true).toBe(true)
|
|
214
|
-
const handler =
|
|
199
|
+
const handler = trello.read('get_card_custom_field_items')
|
|
215
200
|
const result = await handler({ cardId: ids.cardId })
|
|
216
201
|
expect(Array.isArray(result)).toBe(true)
|
|
217
202
|
}, 30000)
|
|
@@ -219,7 +204,7 @@ suite('trello read handlers (live)', () => {
|
|
|
219
204
|
it('get_organization returns an organization', async () => {
|
|
220
205
|
if (!ids.orgId)
|
|
221
206
|
return expect(true).toBe(true)
|
|
222
|
-
const handler =
|
|
207
|
+
const handler = trello.read('get_organization')
|
|
223
208
|
const result = await handler({ orgId: ids.orgId })
|
|
224
209
|
expect(result?.id).toBe(ids.orgId)
|
|
225
210
|
}, 30000)
|
|
@@ -227,13 +212,13 @@ suite('trello read handlers (live)', () => {
|
|
|
227
212
|
it('get_organization_boards returns boards in an org', async () => {
|
|
228
213
|
if (!ids.orgId)
|
|
229
214
|
return expect(true).toBe(true)
|
|
230
|
-
const handler =
|
|
215
|
+
const handler = trello.read('get_organization_boards')
|
|
231
216
|
const result = await handler({ orgId: ids.orgId })
|
|
232
217
|
expect(Array.isArray(result)).toBe(true)
|
|
233
218
|
}, 30000)
|
|
234
219
|
|
|
235
220
|
it('search returns results for a generic query', async () => {
|
|
236
|
-
const handler =
|
|
221
|
+
const handler = trello.read('search')
|
|
237
222
|
const result = await handler({ query: 'test' })
|
|
238
223
|
expect(result).toBeTruthy()
|
|
239
224
|
}, 30000)
|
|
@@ -1,34 +1,9 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
1
|
import { describe, expect, it } from 'vitest'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function escapeRegExp(str: string): string {
|
|
8
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
9
|
-
}
|
|
2
|
+
import { getMissingToolUsages } from '../../__tests__/usageParity.js'
|
|
10
3
|
|
|
11
4
|
describe('trello static usage parity', () => {
|
|
12
|
-
it('every manifest tool is referenced in tests
|
|
13
|
-
const
|
|
14
|
-
const toolNames = (manifest.tools as any[]).map(t => t.name)
|
|
15
|
-
|
|
16
|
-
const testsDir = fileURLToPath(new URL('.', import.meta.url))
|
|
17
|
-
expect(existsSync(testsDir)).toBe(true)
|
|
18
|
-
const testFiles = readdirSync(testsDir)
|
|
19
|
-
.filter(f => /\.test\.(t|j)s$/.test(f) && !f.includes('usage_parity.test'))
|
|
20
|
-
.map(f => resolve(testsDir, f))
|
|
21
|
-
|
|
22
|
-
const fileContents = testFiles.map(f => readFileSync(f, 'utf8'))
|
|
23
|
-
|
|
24
|
-
const missing: string[] = []
|
|
25
|
-
for (const name of toolNames) {
|
|
26
|
-
const nameRe = new RegExp(`build(?:Read|Write|Admin)?(?:Handler)?\\(\\s*['\"\`]${escapeRegExp(name)}['\"\`]\\s*\\)`, 'm')
|
|
27
|
-
const found = fileContents.some(src => nameRe.test(src))
|
|
28
|
-
if (!found)
|
|
29
|
-
missing.push(name)
|
|
30
|
-
}
|
|
31
|
-
|
|
5
|
+
it('every manifest tool is referenced in tests', () => {
|
|
6
|
+
const missing = getMissingToolUsages({ integrationName: 'trello', importMetaUrl: import.meta.url })
|
|
32
7
|
expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
|
|
33
8
|
})
|
|
34
9
|
})
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import { loadIntegrationTools } from '../../../src/integrations/dataLoader.js'
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv, safeCleanup } from '../../__tests__/liveHarness.js'
|
|
4
3
|
|
|
5
4
|
interface Ctx {
|
|
6
5
|
boardId?: string
|
|
@@ -10,86 +9,69 @@ interface Ctx {
|
|
|
10
9
|
memberId?: string
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
const env = process.env as Record<string, string>
|
|
14
|
-
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
15
12
|
const suite = hasEnv(
|
|
16
|
-
'COMMANDABLE_MANAGED_OAUTH_BASE_URL',
|
|
17
|
-
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
18
13
|
'TRELLO_API_KEY',
|
|
19
|
-
'
|
|
14
|
+
'TRELLO_API_TOKEN',
|
|
20
15
|
)
|
|
21
16
|
? describe
|
|
22
17
|
: describe.skip
|
|
23
18
|
|
|
24
19
|
suite('trello write handlers (live)', () => {
|
|
25
20
|
const ctx: Ctx = {}
|
|
26
|
-
let
|
|
27
|
-
let buildRead: (name: string) => ((input: any) => Promise<any>)
|
|
21
|
+
let trello: ReturnType<typeof createToolbox>
|
|
28
22
|
|
|
29
23
|
beforeAll(async () => {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const proxy =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
expect(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
buildRead = (name: string) => {
|
|
51
|
-
const tool = tools!.read.find(t => t.name === name)
|
|
52
|
-
expect(tool, `read tool ${name} exists`).toBeTruthy()
|
|
53
|
-
const integration = { fetch: (path: string, init?: RequestInit) => proxy.call(integrationNode, path, init) }
|
|
54
|
-
const build = new Function('integration', `return (${tool!.handlerCode});`)
|
|
55
|
-
return build(integration) as (input: any) => Promise<any>
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Discover a board and list for tests
|
|
59
|
-
const get_member_boards = buildRead('get_member_boards')
|
|
60
|
-
const boards = await get_member_boards({})
|
|
61
|
-
ctx.boardId = boards?.[0]?.id
|
|
62
|
-
if (ctx.boardId) {
|
|
63
|
-
const get_board_lists = buildRead('get_board_lists')
|
|
64
|
-
const lists = await get_board_lists({ boardId: ctx.boardId })
|
|
65
|
-
ctx.listId = lists?.[0]?.id
|
|
66
|
-
ctx.listId2 = lists?.[1]?.id || ctx.listId
|
|
67
|
-
}
|
|
24
|
+
const env = process.env as Record<string, string | undefined>
|
|
25
|
+
const credentialStore = createCredentialStore(async () => ({ apiKey: env.TRELLO_API_KEY || '', apiToken: env.TRELLO_API_TOKEN || '' }))
|
|
26
|
+
const proxy = createProxy(credentialStore)
|
|
27
|
+
const node = createIntegrationNode('trello', { label: 'Trello', credentialId: 'trello-creds' })
|
|
28
|
+
trello = createToolbox('trello', proxy, node)
|
|
29
|
+
|
|
30
|
+
// Create an isolated board + two lists for this test run
|
|
31
|
+
const create_board = trello.write('create_board')
|
|
32
|
+
const board = await create_board({ name: `CmdTest Trello ${Date.now()}`, defaultLists: false })
|
|
33
|
+
ctx.boardId = board?.id
|
|
34
|
+
expect(ctx.boardId).toBeTruthy()
|
|
35
|
+
|
|
36
|
+
const create_list = trello.write('create_list')
|
|
37
|
+
const list1 = await create_list({ idBoard: ctx.boardId, name: 'CmdTest List A' })
|
|
38
|
+
const list2 = await create_list({ idBoard: ctx.boardId, name: 'CmdTest List B' })
|
|
39
|
+
ctx.listId = list1?.id
|
|
40
|
+
ctx.listId2 = list2?.id
|
|
41
|
+
expect(ctx.listId).toBeTruthy()
|
|
42
|
+
expect(ctx.listId2).toBeTruthy()
|
|
68
43
|
|
|
69
44
|
// Discover a member to add to card (self)
|
|
70
|
-
const get_member =
|
|
45
|
+
const get_member = trello.read('get_member')
|
|
71
46
|
const me = await get_member({})
|
|
72
47
|
ctx.memberId = me?.id
|
|
73
48
|
}, 60000)
|
|
74
49
|
|
|
50
|
+
afterAll(async () => {
|
|
51
|
+
if (!ctx.boardId)
|
|
52
|
+
return
|
|
53
|
+
await safeCleanup(async () => trello.write('close_board')({ boardId: ctx.boardId }))
|
|
54
|
+
await safeCleanup(async () => trello.write('delete_board')({ boardId: ctx.boardId }))
|
|
55
|
+
}, 60_000)
|
|
56
|
+
|
|
75
57
|
it('create_card -> get_card -> update_card -> move_card_to_list -> delete_card', async () => {
|
|
76
58
|
if (!ctx.boardId || !ctx.listId || !ctx.memberId)
|
|
77
59
|
return expect(true).toBe(true)
|
|
78
60
|
|
|
79
61
|
// Create card
|
|
80
|
-
const create_card =
|
|
62
|
+
const create_card = trello.write('create_card')
|
|
81
63
|
const created = await create_card({ idList: ctx.listId, name: `CmdCard ${Date.now()}`, desc: 'Initial desc' })
|
|
82
64
|
const cardId = created?.id
|
|
83
65
|
expect(cardId).toBeTruthy()
|
|
84
66
|
ctx.cardId = cardId
|
|
85
67
|
|
|
86
68
|
// Read card
|
|
87
|
-
const get_card =
|
|
69
|
+
const get_card = trello.read('get_card')
|
|
88
70
|
const got = await get_card({ cardId })
|
|
89
71
|
expect(got?.id).toBe(cardId)
|
|
90
72
|
|
|
91
73
|
// Update card
|
|
92
|
-
const update_card =
|
|
74
|
+
const update_card = trello.write('update_card')
|
|
93
75
|
const updated = await update_card({ cardId, name: 'Updated Name', desc: 'Updated desc' })
|
|
94
76
|
expect(updated?.id).toBe(cardId)
|
|
95
77
|
|
|
@@ -99,7 +81,7 @@ suite('trello write handlers (live)', () => {
|
|
|
99
81
|
|
|
100
82
|
// Move card
|
|
101
83
|
if (ctx.listId2 && ctx.listId2 !== ctx.listId) {
|
|
102
|
-
const move_card_to_list =
|
|
84
|
+
const move_card_to_list = trello.write('move_card_to_list')
|
|
103
85
|
const moved = await move_card_to_list({ cardId, listId: ctx.listId2 })
|
|
104
86
|
expect(moved?.id).toBe(cardId)
|
|
105
87
|
const got3 = await get_card({ cardId })
|
|
@@ -107,7 +89,7 @@ suite('trello write handlers (live)', () => {
|
|
|
107
89
|
}
|
|
108
90
|
|
|
109
91
|
// Delete card
|
|
110
|
-
const delete_card =
|
|
92
|
+
const delete_card = trello.write('delete_card')
|
|
111
93
|
const del = await delete_card({ cardId })
|
|
112
94
|
expect(Boolean(del === '' || del?.limits || del?.id === cardId || (del && typeof del === 'object'))).toBe(true)
|
|
113
95
|
}, 120000)
|
|
@@ -117,26 +99,26 @@ suite('trello write handlers (live)', () => {
|
|
|
117
99
|
return expect(true).toBe(true)
|
|
118
100
|
|
|
119
101
|
// Create an isolated card for this test
|
|
120
|
-
const create_card =
|
|
102
|
+
const create_card = trello.write('create_card')
|
|
121
103
|
const created = await create_card({ idList: ctx.listId, name: `CmdCard Members ${Date.now()}` })
|
|
122
104
|
const cardId = created?.id
|
|
123
105
|
expect(cardId).toBeTruthy()
|
|
124
106
|
|
|
125
|
-
const add_member_to_card =
|
|
107
|
+
const add_member_to_card = trello.write('add_member_to_card')
|
|
126
108
|
const added = await add_member_to_card({ cardId, memberId: ctx.memberId })
|
|
127
109
|
expect(added).toBeTruthy()
|
|
128
110
|
|
|
129
|
-
const get_card_members =
|
|
111
|
+
const get_card_members = trello.read('get_card_members')
|
|
130
112
|
const members = await get_card_members({ cardId })
|
|
131
113
|
const hasMember = (members || []).some((m: any) => m?.id === ctx.memberId)
|
|
132
114
|
expect(hasMember).toBe(true)
|
|
133
115
|
|
|
134
|
-
const remove_member_from_card =
|
|
116
|
+
const remove_member_from_card = trello.write('remove_member_from_card')
|
|
135
117
|
const removed = await remove_member_from_card({ cardId, memberId: ctx.memberId })
|
|
136
118
|
expect(removed === '' || (removed && typeof removed === 'object')).toBe(true)
|
|
137
119
|
|
|
138
120
|
// Cleanup
|
|
139
|
-
const delete_card =
|
|
121
|
+
const delete_card = trello.write('delete_card')
|
|
140
122
|
await delete_card({ cardId })
|
|
141
123
|
}, 90000)
|
|
142
124
|
|
|
@@ -145,44 +127,44 @@ suite('trello write handlers (live)', () => {
|
|
|
145
127
|
return expect(true).toBe(true)
|
|
146
128
|
|
|
147
129
|
// Create an isolated card for this test
|
|
148
|
-
const create_card =
|
|
130
|
+
const create_card = trello.write('create_card')
|
|
149
131
|
const createdCard = await create_card({ idList: ctx.listId, name: `CmdCard Checklist ${Date.now()}` })
|
|
150
132
|
const cardId = createdCard?.id
|
|
151
133
|
expect(cardId).toBeTruthy()
|
|
152
134
|
|
|
153
|
-
const add_checklist_to_card =
|
|
135
|
+
const add_checklist_to_card = trello.write('add_checklist_to_card')
|
|
154
136
|
const created = await add_checklist_to_card({ cardId, name: `Checklist ${Date.now()}` })
|
|
155
137
|
expect(created?.id).toBeTruthy()
|
|
156
138
|
|
|
157
|
-
const get_card_checklists =
|
|
139
|
+
const get_card_checklists = trello.read('get_card_checklists')
|
|
158
140
|
const lists = await get_card_checklists({ cardId })
|
|
159
141
|
expect(Array.isArray(lists)).toBe(true)
|
|
160
142
|
|
|
161
143
|
// Cleanup
|
|
162
|
-
const delete_card =
|
|
144
|
+
const delete_card = trello.write('delete_card')
|
|
163
145
|
await delete_card({ cardId })
|
|
164
146
|
}, 60000)
|
|
165
147
|
|
|
166
148
|
it('create_list -> get_list -> update_list -> archive_list', async () => {
|
|
167
149
|
if (!ctx.boardId)
|
|
168
150
|
return expect(true).toBe(true)
|
|
169
|
-
const create_list =
|
|
151
|
+
const create_list = trello.write('create_list')
|
|
170
152
|
const created = await create_list({ idBoard: ctx.boardId, name: `CmdList ${Date.now()}` })
|
|
171
153
|
const listId = created?.id
|
|
172
154
|
expect(listId).toBeTruthy()
|
|
173
155
|
|
|
174
|
-
const get_list =
|
|
156
|
+
const get_list = trello.read('get_list')
|
|
175
157
|
const got = await get_list({ listId })
|
|
176
158
|
expect(got?.id).toBe(listId)
|
|
177
159
|
|
|
178
|
-
const update_list =
|
|
160
|
+
const update_list = trello.write('update_list')
|
|
179
161
|
const updated = await update_list({ listId, name: 'Updated List Name' })
|
|
180
162
|
expect(updated?.id).toBe(listId)
|
|
181
163
|
|
|
182
164
|
const got2 = await get_list({ listId })
|
|
183
165
|
expect(got2?.name).toBe('Updated List Name')
|
|
184
166
|
|
|
185
|
-
const archive_list =
|
|
167
|
+
const archive_list = trello.write('archive_list')
|
|
186
168
|
const archived = await archive_list({ listId })
|
|
187
169
|
expect(archived?.closed === true).toBe(true)
|
|
188
170
|
}, 120000)
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"type": "
|
|
7
|
-
"
|
|
8
|
-
|
|
2
|
+
"variants": {
|
|
3
|
+
"api_key_token": {
|
|
4
|
+
"label": "API Key + Token",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"apiKey": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "API Key",
|
|
11
|
+
"description": "Your Trello API key from https://trello.com/power-ups/admin"
|
|
12
|
+
},
|
|
13
|
+
"apiToken": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"title": "API Token",
|
|
16
|
+
"description": "Your Trello API token (\"token\" param). Generate one via Trello's authorize flow."
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["apiKey", "apiToken"],
|
|
20
|
+
"additionalProperties": false
|
|
9
21
|
},
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
"injection": {
|
|
23
|
+
"query": {
|
|
24
|
+
"key": "{{apiKey}}",
|
|
25
|
+
"token": "{{apiToken}}"
|
|
26
|
+
}
|
|
14
27
|
}
|
|
15
|
-
},
|
|
16
|
-
"required": ["apiKey", "apiToken"],
|
|
17
|
-
"additionalProperties": false
|
|
18
|
-
},
|
|
19
|
-
"injection": {
|
|
20
|
-
"query": {
|
|
21
|
-
"key": "{{apiKey}}",
|
|
22
|
-
"token": "{{apiToken}}"
|
|
23
28
|
}
|
|
24
|
-
}
|
|
29
|
+
},
|
|
30
|
+
"default": "api_key_token"
|
|
25
31
|
}
|
|
26
|
-
|