@inkeep/agents-work-apps 0.0.0-dev-20260204182014 → 0.0.0-dev-20260204210021
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/db/index.d.ts +1 -2
- package/dist/db/index.js +1 -2
- package/dist/db/runDbClient.d.ts +2 -2
- package/dist/env.d.ts +2 -24
- package/dist/env.js +1 -12
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/package.json +2 -10
- package/dist/db/manageDbClient.d.ts +0 -7
- package/dist/db/manageDbClient.js +0 -16
- package/dist/slack/index.d.ts +0 -19
- package/dist/slack/index.js +0 -29
- package/dist/slack/middleware/permissions.d.ts +0 -16
- package/dist/slack/middleware/permissions.js +0 -49
- package/dist/slack/routes/events.d.ts +0 -10
- package/dist/slack/routes/events.js +0 -319
- package/dist/slack/routes/index.d.ts +0 -11
- package/dist/slack/routes/index.js +0 -64
- package/dist/slack/routes/internal.d.ts +0 -10
- package/dist/slack/routes/internal.js +0 -107
- package/dist/slack/routes/oauth.d.ts +0 -12
- package/dist/slack/routes/oauth.js +0 -218
- package/dist/slack/routes/resources.d.ts +0 -10
- package/dist/slack/routes/resources.js +0 -163
- package/dist/slack/routes/users.d.ts +0 -15
- package/dist/slack/routes/users.js +0 -430
- package/dist/slack/routes/workspaces.d.ts +0 -10
- package/dist/slack/routes/workspaces.js +0 -828
- package/dist/slack/routes.d.ts +0 -7
- package/dist/slack/routes.js +0 -12
- package/dist/slack/services/agent-resolution.d.ts +0 -49
- package/dist/slack/services/agent-resolution.js +0 -135
- package/dist/slack/services/api-client.d.ts +0 -161
- package/dist/slack/services/api-client.js +0 -248
- package/dist/slack/services/auth/index.d.ts +0 -61
- package/dist/slack/services/auth/index.js +0 -164
- package/dist/slack/services/blocks/index.d.ts +0 -60
- package/dist/slack/services/blocks/index.js +0 -143
- package/dist/slack/services/client.d.ts +0 -78
- package/dist/slack/services/client.js +0 -152
- package/dist/slack/services/commands/index.d.ts +0 -15
- package/dist/slack/services/commands/index.js +0 -556
- package/dist/slack/services/events/app-mention.d.ts +0 -41
- package/dist/slack/services/events/app-mention.js +0 -212
- package/dist/slack/services/events/block-actions.d.ts +0 -47
- package/dist/slack/services/events/block-actions.js +0 -287
- package/dist/slack/services/events/index.d.ts +0 -6
- package/dist/slack/services/events/index.js +0 -7
- package/dist/slack/services/events/modal-submission.d.ts +0 -12
- package/dist/slack/services/events/modal-submission.js +0 -279
- package/dist/slack/services/events/streaming.d.ts +0 -27
- package/dist/slack/services/events/streaming.js +0 -285
- package/dist/slack/services/events/utils.d.ts +0 -129
- package/dist/slack/services/events/utils.js +0 -315
- package/dist/slack/services/index.d.ts +0 -18
- package/dist/slack/services/index.js +0 -18
- package/dist/slack/services/modals.d.ts +0 -67
- package/dist/slack/services/modals.js +0 -203
- package/dist/slack/services/nango.d.ts +0 -82
- package/dist/slack/services/nango.js +0 -326
- package/dist/slack/services/security.d.ts +0 -35
- package/dist/slack/services/security.js +0 -65
- package/dist/slack/services/types.d.ts +0 -26
- package/dist/slack/services/types.js +0 -1
- package/dist/slack/services/workspace-tokens.d.ts +0 -37
- package/dist/slack/services/workspace-tokens.js +0 -39
- package/dist/slack/types.d.ts +0 -10
- package/dist/slack/types.js +0 -1
|
@@ -1,828 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../logger.js";
|
|
2
|
-
import runDbClient_default from "../../db/runDbClient.js";
|
|
3
|
-
import { computeWorkspaceConnectionId, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent } from "../services/nango.js";
|
|
4
|
-
import { getSlackChannels, getSlackClient } from "../services/client.js";
|
|
5
|
-
import "../services/index.js";
|
|
6
|
-
import { requireWorkspaceAdmin } from "../middleware/permissions.js";
|
|
7
|
-
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
|
|
8
|
-
import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
|
|
9
|
-
|
|
10
|
-
//#region src/slack/routes/workspaces.ts
|
|
11
|
-
/**
|
|
12
|
-
* Slack Workspace Routes
|
|
13
|
-
*
|
|
14
|
-
* RESTful endpoints for managing Slack workspaces and their configurations:
|
|
15
|
-
* - GET /workspaces - List all installed workspaces
|
|
16
|
-
* - GET /workspaces/:teamId - Get workspace details
|
|
17
|
-
* - PUT /workspaces/:teamId/settings - Update workspace settings (default agent) [ADMIN ONLY]
|
|
18
|
-
* - DELETE /workspaces/:teamId - Uninstall workspace [ADMIN ONLY]
|
|
19
|
-
* - GET /workspaces/:teamId/channels - List channels
|
|
20
|
-
* - GET /workspaces/:teamId/channels/:channelId/settings - Get channel config
|
|
21
|
-
* - PUT /workspaces/:teamId/channels/:channelId/settings - Set channel default agent [ADMIN ONLY]
|
|
22
|
-
* - DELETE /workspaces/:teamId/channels/:channelId/settings - Remove channel config [ADMIN ONLY]
|
|
23
|
-
* - GET /workspaces/:teamId/users - List linked users
|
|
24
|
-
*
|
|
25
|
-
* Permission Model:
|
|
26
|
-
* - Read operations (GET): Any authenticated user
|
|
27
|
-
* - Write operations for workspace/channel configs (PUT/DELETE): Org admin/owner only
|
|
28
|
-
* - User personal settings: Any authenticated user (handled in users router)
|
|
29
|
-
*/
|
|
30
|
-
const logger = getLogger("slack-workspaces");
|
|
31
|
-
const app = new OpenAPIHono();
|
|
32
|
-
app.use("/:teamId/settings", async (c, next) => {
|
|
33
|
-
if (c.req.method === "PUT") return requireWorkspaceAdmin()(c, next);
|
|
34
|
-
return next();
|
|
35
|
-
});
|
|
36
|
-
app.use("/:workspaceId", async (c, next) => {
|
|
37
|
-
if (c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
|
|
38
|
-
return next();
|
|
39
|
-
});
|
|
40
|
-
app.use("/:teamId/channels/:channelId/settings", async (c, next) => {
|
|
41
|
-
if (c.req.method === "PUT" || c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
|
|
42
|
-
return next();
|
|
43
|
-
});
|
|
44
|
-
const ChannelAgentConfigSchema = z.object({
|
|
45
|
-
projectId: z.string(),
|
|
46
|
-
agentId: z.string(),
|
|
47
|
-
agentName: z.string().optional()
|
|
48
|
-
});
|
|
49
|
-
const WorkspaceSettingsSchema = z.object({ defaultAgent: ChannelAgentConfigSchema.optional() });
|
|
50
|
-
app.openapi(createRoute({
|
|
51
|
-
method: "get",
|
|
52
|
-
path: "/",
|
|
53
|
-
summary: "List Workspaces",
|
|
54
|
-
description: "List all installed Slack workspaces for the tenant",
|
|
55
|
-
operationId: "slack-list-workspaces",
|
|
56
|
-
tags: [
|
|
57
|
-
"Work Apps",
|
|
58
|
-
"Slack",
|
|
59
|
-
"Workspaces"
|
|
60
|
-
],
|
|
61
|
-
responses: { 200: {
|
|
62
|
-
description: "List of workspaces",
|
|
63
|
-
content: { "application/json": { schema: z.object({ workspaces: z.array(z.object({
|
|
64
|
-
connectionId: z.string(),
|
|
65
|
-
teamId: z.string(),
|
|
66
|
-
teamName: z.string().optional(),
|
|
67
|
-
tenantId: z.string(),
|
|
68
|
-
hasDefaultAgent: z.boolean(),
|
|
69
|
-
defaultAgentName: z.string().optional()
|
|
70
|
-
})) }) } }
|
|
71
|
-
} }
|
|
72
|
-
}), async (c) => {
|
|
73
|
-
try {
|
|
74
|
-
const workspaces = await listWorkspaceInstallations();
|
|
75
|
-
logger.info({ count: workspaces.length }, "Listed workspace installations");
|
|
76
|
-
return c.json({ workspaces: workspaces.map((w) => ({
|
|
77
|
-
connectionId: w.connectionId,
|
|
78
|
-
teamId: w.teamId,
|
|
79
|
-
teamName: w.teamName,
|
|
80
|
-
tenantId: w.tenantId,
|
|
81
|
-
hasDefaultAgent: !!w.defaultAgent,
|
|
82
|
-
defaultAgentName: w.defaultAgent?.agentName
|
|
83
|
-
})) });
|
|
84
|
-
} catch (error) {
|
|
85
|
-
logger.error({ error }, "Failed to list workspaces");
|
|
86
|
-
return c.json({ workspaces: [] });
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
app.openapi(createRoute({
|
|
90
|
-
method: "get",
|
|
91
|
-
path: "/:teamId",
|
|
92
|
-
summary: "Get Workspace",
|
|
93
|
-
description: "Get details of a specific Slack workspace",
|
|
94
|
-
operationId: "slack-get-workspace",
|
|
95
|
-
tags: [
|
|
96
|
-
"Work Apps",
|
|
97
|
-
"Slack",
|
|
98
|
-
"Workspaces"
|
|
99
|
-
],
|
|
100
|
-
request: { params: z.object({ teamId: z.string() }) },
|
|
101
|
-
responses: {
|
|
102
|
-
200: {
|
|
103
|
-
description: "Workspace details",
|
|
104
|
-
content: { "application/json": { schema: z.object({
|
|
105
|
-
teamId: z.string(),
|
|
106
|
-
teamName: z.string().optional(),
|
|
107
|
-
tenantId: z.string(),
|
|
108
|
-
connectionId: z.string(),
|
|
109
|
-
defaultAgent: ChannelAgentConfigSchema.optional()
|
|
110
|
-
}) } }
|
|
111
|
-
},
|
|
112
|
-
404: { description: "Workspace not found" }
|
|
113
|
-
}
|
|
114
|
-
}), async (c) => {
|
|
115
|
-
const { teamId } = c.req.valid("param");
|
|
116
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
117
|
-
if (!workspace) return c.json({ error: "Workspace not found" }, 404);
|
|
118
|
-
let defaultAgent;
|
|
119
|
-
const nangoDefault = await getWorkspaceDefaultAgentFromNango(teamId);
|
|
120
|
-
if (nangoDefault) defaultAgent = {
|
|
121
|
-
projectId: nangoDefault.projectId,
|
|
122
|
-
agentId: nangoDefault.agentId,
|
|
123
|
-
agentName: nangoDefault.agentName
|
|
124
|
-
};
|
|
125
|
-
return c.json({
|
|
126
|
-
teamId: workspace.teamId,
|
|
127
|
-
teamName: workspace.teamName,
|
|
128
|
-
tenantId: workspace.tenantId,
|
|
129
|
-
connectionId: workspace.connectionId,
|
|
130
|
-
defaultAgent
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
app.openapi(createRoute({
|
|
134
|
-
method: "get",
|
|
135
|
-
path: "/:teamId/settings",
|
|
136
|
-
summary: "Get Workspace Settings",
|
|
137
|
-
description: "Get settings for a Slack workspace including default agent",
|
|
138
|
-
operationId: "slack-get-workspace-settings",
|
|
139
|
-
tags: [
|
|
140
|
-
"Work Apps",
|
|
141
|
-
"Slack",
|
|
142
|
-
"Workspaces"
|
|
143
|
-
],
|
|
144
|
-
request: { params: z.object({ teamId: z.string() }) },
|
|
145
|
-
responses: { 200: {
|
|
146
|
-
description: "Workspace settings",
|
|
147
|
-
content: { "application/json": { schema: WorkspaceSettingsSchema } }
|
|
148
|
-
} }
|
|
149
|
-
}), async (c) => {
|
|
150
|
-
const { teamId } = c.req.valid("param");
|
|
151
|
-
let defaultAgent;
|
|
152
|
-
const nangoDefault = await getWorkspaceDefaultAgentFromNango(teamId);
|
|
153
|
-
if (nangoDefault) defaultAgent = {
|
|
154
|
-
projectId: nangoDefault.projectId,
|
|
155
|
-
agentId: nangoDefault.agentId,
|
|
156
|
-
agentName: nangoDefault.agentName
|
|
157
|
-
};
|
|
158
|
-
return c.json({ defaultAgent });
|
|
159
|
-
});
|
|
160
|
-
app.openapi(createRoute({
|
|
161
|
-
method: "put",
|
|
162
|
-
path: "/:teamId/settings",
|
|
163
|
-
summary: "Update Workspace Settings",
|
|
164
|
-
description: "Update workspace settings including default agent",
|
|
165
|
-
operationId: "slack-update-workspace-settings",
|
|
166
|
-
tags: [
|
|
167
|
-
"Work Apps",
|
|
168
|
-
"Slack",
|
|
169
|
-
"Workspaces"
|
|
170
|
-
],
|
|
171
|
-
request: {
|
|
172
|
-
params: z.object({ teamId: z.string() }),
|
|
173
|
-
body: { content: { "application/json": { schema: WorkspaceSettingsSchema } } }
|
|
174
|
-
},
|
|
175
|
-
responses: {
|
|
176
|
-
200: {
|
|
177
|
-
description: "Settings updated",
|
|
178
|
-
content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
|
|
179
|
-
},
|
|
180
|
-
500: {
|
|
181
|
-
description: "Failed to update settings",
|
|
182
|
-
content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}), async (c) => {
|
|
186
|
-
const { teamId } = c.req.valid("param");
|
|
187
|
-
const body = c.req.valid("json");
|
|
188
|
-
if (body.defaultAgent) {
|
|
189
|
-
if (!await setWorkspaceDefaultAgent(teamId, body.defaultAgent)) {
|
|
190
|
-
logger.warn({ teamId }, "Failed to persist workspace settings to Nango");
|
|
191
|
-
return c.json({ success: false }, 500);
|
|
192
|
-
}
|
|
193
|
-
logger.info({
|
|
194
|
-
teamId,
|
|
195
|
-
agentId: body.defaultAgent.agentId,
|
|
196
|
-
agentName: body.defaultAgent.agentName
|
|
197
|
-
}, "Saved workspace default agent to Nango");
|
|
198
|
-
} else {
|
|
199
|
-
await setWorkspaceDefaultAgent(teamId, null);
|
|
200
|
-
logger.info({ teamId }, "Cleared workspace default agent");
|
|
201
|
-
}
|
|
202
|
-
return c.json({ success: true });
|
|
203
|
-
});
|
|
204
|
-
app.openapi(createRoute({
|
|
205
|
-
method: "delete",
|
|
206
|
-
path: "/:workspaceId",
|
|
207
|
-
summary: "Uninstall Workspace",
|
|
208
|
-
description: "Uninstall Slack app from workspace. Accepts either teamId or connectionId.",
|
|
209
|
-
operationId: "slack-delete-workspace",
|
|
210
|
-
tags: [
|
|
211
|
-
"Work Apps",
|
|
212
|
-
"Slack",
|
|
213
|
-
"Workspaces"
|
|
214
|
-
],
|
|
215
|
-
request: { params: z.object({ workspaceId: z.string() }) },
|
|
216
|
-
responses: {
|
|
217
|
-
200: {
|
|
218
|
-
description: "Workspace uninstalled",
|
|
219
|
-
content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
|
|
220
|
-
},
|
|
221
|
-
400: { description: "Invalid connectionId format" },
|
|
222
|
-
404: { description: "Workspace not found" },
|
|
223
|
-
500: { description: "Failed to uninstall workspace" }
|
|
224
|
-
}
|
|
225
|
-
}), async (c) => {
|
|
226
|
-
const { workspaceId } = c.req.valid("param");
|
|
227
|
-
let teamId;
|
|
228
|
-
let connectionId;
|
|
229
|
-
try {
|
|
230
|
-
if (workspaceId.includes(":")) {
|
|
231
|
-
connectionId = workspaceId;
|
|
232
|
-
const teamMatch = workspaceId.match(/T:([A-Z0-9]+)/);
|
|
233
|
-
if (!teamMatch) return c.json({ error: "Invalid connectionId format" }, 400);
|
|
234
|
-
teamId = teamMatch[1];
|
|
235
|
-
} else {
|
|
236
|
-
teamId = workspaceId;
|
|
237
|
-
connectionId = computeWorkspaceConnectionId({
|
|
238
|
-
teamId,
|
|
239
|
-
enterpriseId: void 0
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
243
|
-
if (!workspace) return c.json({ error: "Workspace not found" }, 404);
|
|
244
|
-
if (!await deleteWorkspaceInstallation(connectionId)) {
|
|
245
|
-
logger.error({ connectionId }, "deleteWorkspaceInstallation returned false");
|
|
246
|
-
return c.json({ error: "Failed to delete workspace from Nango" }, 500);
|
|
247
|
-
}
|
|
248
|
-
if (await deleteWorkAppSlackWorkspaceByNangoConnectionId(runDbClient_default)(connectionId)) logger.info({ connectionId }, "Deleted workspace from database");
|
|
249
|
-
const tenantId = workspace.tenantId || "default";
|
|
250
|
-
const deletedMappings = await deleteAllWorkAppSlackUserMappingsByTeam(runDbClient_default)(tenantId, teamId);
|
|
251
|
-
if (deletedMappings > 0) logger.info({
|
|
252
|
-
teamId,
|
|
253
|
-
deletedMappings
|
|
254
|
-
}, "Deleted user mappings for uninstalled workspace");
|
|
255
|
-
const deletedChannelConfigs = await deleteAllWorkAppSlackChannelAgentConfigsByTeam(runDbClient_default)(tenantId, teamId);
|
|
256
|
-
if (deletedChannelConfigs > 0) logger.info({
|
|
257
|
-
teamId,
|
|
258
|
-
deletedChannelConfigs
|
|
259
|
-
}, "Deleted channel configs for uninstalled workspace");
|
|
260
|
-
logger.info({ connectionId }, "Deleted workspace installation");
|
|
261
|
-
return c.json({ success: true });
|
|
262
|
-
} catch (error) {
|
|
263
|
-
logger.error({
|
|
264
|
-
error,
|
|
265
|
-
workspaceId
|
|
266
|
-
}, "Failed to uninstall workspace");
|
|
267
|
-
return c.json({ error: "Failed to uninstall workspace" }, 500);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
app.openapi(createRoute({
|
|
271
|
-
method: "get",
|
|
272
|
-
path: "/:teamId/channels",
|
|
273
|
-
summary: "List Channels",
|
|
274
|
-
description: "List Slack channels in the workspace that the bot can see",
|
|
275
|
-
operationId: "slack-list-channels",
|
|
276
|
-
tags: [
|
|
277
|
-
"Work Apps",
|
|
278
|
-
"Slack",
|
|
279
|
-
"Channels"
|
|
280
|
-
],
|
|
281
|
-
request: {
|
|
282
|
-
params: z.object({ teamId: z.string() }),
|
|
283
|
-
query: z.object({
|
|
284
|
-
limit: z.coerce.number().optional().default(100),
|
|
285
|
-
cursor: z.string().optional(),
|
|
286
|
-
types: z.string().optional()
|
|
287
|
-
})
|
|
288
|
-
},
|
|
289
|
-
responses: {
|
|
290
|
-
200: {
|
|
291
|
-
description: "List of channels",
|
|
292
|
-
content: { "application/json": { schema: z.object({
|
|
293
|
-
channels: z.array(z.object({
|
|
294
|
-
id: z.string(),
|
|
295
|
-
name: z.string(),
|
|
296
|
-
isPrivate: z.boolean(),
|
|
297
|
-
memberCount: z.number().optional(),
|
|
298
|
-
hasAgentConfig: z.boolean(),
|
|
299
|
-
agentConfig: ChannelAgentConfigSchema.optional()
|
|
300
|
-
})),
|
|
301
|
-
nextCursor: z.string().optional()
|
|
302
|
-
}) } }
|
|
303
|
-
},
|
|
304
|
-
404: { description: "Workspace not found" }
|
|
305
|
-
}
|
|
306
|
-
}), async (c) => {
|
|
307
|
-
const { teamId } = c.req.valid("param");
|
|
308
|
-
const { limit } = c.req.valid("query");
|
|
309
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
310
|
-
if (!workspace?.botToken) return c.json({ error: "Workspace not found or no bot token" }, 404);
|
|
311
|
-
const tenantId = workspace.tenantId || "default";
|
|
312
|
-
const slackClient = getSlackClient(workspace.botToken);
|
|
313
|
-
try {
|
|
314
|
-
const channels = await getSlackChannels(slackClient, limit);
|
|
315
|
-
let channelConfigs = [];
|
|
316
|
-
try {
|
|
317
|
-
channelConfigs = await listWorkAppSlackChannelAgentConfigsByTeam(runDbClient_default)(tenantId, teamId);
|
|
318
|
-
} catch (configError) {
|
|
319
|
-
logger.warn({
|
|
320
|
-
error: configError,
|
|
321
|
-
teamId
|
|
322
|
-
}, "Failed to fetch channel configs, table may not exist yet");
|
|
323
|
-
}
|
|
324
|
-
const configMap = new Map(channelConfigs.map((c$1) => [c$1.slackChannelId, c$1]));
|
|
325
|
-
const channelsWithConfig = channels.map((channel) => {
|
|
326
|
-
const config = channel.id ? configMap.get(channel.id) : void 0;
|
|
327
|
-
return {
|
|
328
|
-
id: channel.id || "",
|
|
329
|
-
name: channel.name || "",
|
|
330
|
-
isPrivate: false,
|
|
331
|
-
memberCount: channel.memberCount,
|
|
332
|
-
hasAgentConfig: !!config,
|
|
333
|
-
agentConfig: config ? {
|
|
334
|
-
projectId: config.projectId,
|
|
335
|
-
agentId: config.agentId,
|
|
336
|
-
agentName: config.agentName || void 0
|
|
337
|
-
} : void 0
|
|
338
|
-
};
|
|
339
|
-
});
|
|
340
|
-
return c.json({
|
|
341
|
-
channels: channelsWithConfig,
|
|
342
|
-
nextCursor: void 0
|
|
343
|
-
});
|
|
344
|
-
} catch (error) {
|
|
345
|
-
logger.error({
|
|
346
|
-
error,
|
|
347
|
-
teamId
|
|
348
|
-
}, "Failed to list channels");
|
|
349
|
-
return c.json({ error: "Failed to list channels" }, 500);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
app.openapi(createRoute({
|
|
353
|
-
method: "get",
|
|
354
|
-
path: "/:teamId/channels/:channelId/settings",
|
|
355
|
-
summary: "Get Channel Settings",
|
|
356
|
-
description: "Get default agent configuration for a specific channel",
|
|
357
|
-
operationId: "slack-get-channel-settings",
|
|
358
|
-
tags: [
|
|
359
|
-
"Work Apps",
|
|
360
|
-
"Slack",
|
|
361
|
-
"Channels"
|
|
362
|
-
],
|
|
363
|
-
request: { params: z.object({
|
|
364
|
-
teamId: z.string(),
|
|
365
|
-
channelId: z.string()
|
|
366
|
-
}) },
|
|
367
|
-
responses: { 200: {
|
|
368
|
-
description: "Channel settings",
|
|
369
|
-
content: { "application/json": { schema: z.object({
|
|
370
|
-
channelId: z.string(),
|
|
371
|
-
agentConfig: ChannelAgentConfigSchema.optional()
|
|
372
|
-
}) } }
|
|
373
|
-
} }
|
|
374
|
-
}), async (c) => {
|
|
375
|
-
const { teamId, channelId } = c.req.valid("param");
|
|
376
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
377
|
-
const config = await findWorkAppSlackChannelAgentConfig(runDbClient_default)(tenantId, teamId, channelId);
|
|
378
|
-
return c.json({
|
|
379
|
-
channelId,
|
|
380
|
-
agentConfig: config ? {
|
|
381
|
-
projectId: config.projectId,
|
|
382
|
-
agentId: config.agentId,
|
|
383
|
-
agentName: config.agentName || void 0
|
|
384
|
-
} : void 0
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
app.openapi(createRoute({
|
|
388
|
-
method: "put",
|
|
389
|
-
path: "/:teamId/channels/:channelId/settings",
|
|
390
|
-
summary: "Set Channel Default Agent",
|
|
391
|
-
description: "Set or update the default agent for a specific channel",
|
|
392
|
-
operationId: "slack-set-channel-settings",
|
|
393
|
-
tags: [
|
|
394
|
-
"Work Apps",
|
|
395
|
-
"Slack",
|
|
396
|
-
"Channels"
|
|
397
|
-
],
|
|
398
|
-
request: {
|
|
399
|
-
params: z.object({
|
|
400
|
-
teamId: z.string(),
|
|
401
|
-
channelId: z.string()
|
|
402
|
-
}),
|
|
403
|
-
body: { content: { "application/json": { schema: z.object({
|
|
404
|
-
agentConfig: ChannelAgentConfigSchema,
|
|
405
|
-
channelName: z.string().optional(),
|
|
406
|
-
channelType: z.string().optional()
|
|
407
|
-
}) } } }
|
|
408
|
-
},
|
|
409
|
-
responses: { 200: {
|
|
410
|
-
description: "Channel settings updated",
|
|
411
|
-
content: { "application/json": { schema: z.object({
|
|
412
|
-
success: z.boolean(),
|
|
413
|
-
configId: z.string()
|
|
414
|
-
}) } }
|
|
415
|
-
} }
|
|
416
|
-
}), async (c) => {
|
|
417
|
-
const { teamId, channelId } = c.req.valid("param");
|
|
418
|
-
const body = c.req.valid("json");
|
|
419
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
420
|
-
const config = await upsertWorkAppSlackChannelAgentConfig(runDbClient_default)({
|
|
421
|
-
tenantId,
|
|
422
|
-
slackTeamId: teamId,
|
|
423
|
-
slackChannelId: channelId,
|
|
424
|
-
slackChannelName: body.channelName,
|
|
425
|
-
slackChannelType: body.channelType,
|
|
426
|
-
projectId: body.agentConfig.projectId,
|
|
427
|
-
agentId: body.agentConfig.agentId,
|
|
428
|
-
agentName: body.agentConfig.agentName,
|
|
429
|
-
enabled: true
|
|
430
|
-
});
|
|
431
|
-
logger.info({
|
|
432
|
-
teamId,
|
|
433
|
-
channelId,
|
|
434
|
-
agentId: body.agentConfig.agentId
|
|
435
|
-
}, "Set channel default agent");
|
|
436
|
-
return c.json({
|
|
437
|
-
success: true,
|
|
438
|
-
configId: config.id
|
|
439
|
-
});
|
|
440
|
-
});
|
|
441
|
-
app.use("/:teamId/channels/bulk", async (c, next) => {
|
|
442
|
-
if (c.req.method === "PUT" || c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
|
|
443
|
-
return next();
|
|
444
|
-
});
|
|
445
|
-
app.openapi(createRoute({
|
|
446
|
-
method: "put",
|
|
447
|
-
path: "/:teamId/channels/bulk",
|
|
448
|
-
summary: "Bulk Set Channel Agents",
|
|
449
|
-
description: "Apply the same agent configuration to multiple channels at once",
|
|
450
|
-
operationId: "slack-bulk-set-channel-agents",
|
|
451
|
-
tags: [
|
|
452
|
-
"Work Apps",
|
|
453
|
-
"Slack",
|
|
454
|
-
"Channels"
|
|
455
|
-
],
|
|
456
|
-
request: {
|
|
457
|
-
params: z.object({ teamId: z.string() }),
|
|
458
|
-
body: { content: { "application/json": { schema: z.object({
|
|
459
|
-
channelIds: z.array(z.string()).min(1),
|
|
460
|
-
agentConfig: ChannelAgentConfigSchema
|
|
461
|
-
}) } } }
|
|
462
|
-
},
|
|
463
|
-
responses: {
|
|
464
|
-
200: {
|
|
465
|
-
description: "Channels updated",
|
|
466
|
-
content: { "application/json": { schema: z.object({
|
|
467
|
-
success: z.boolean(),
|
|
468
|
-
updated: z.number(),
|
|
469
|
-
failed: z.number(),
|
|
470
|
-
errors: z.array(z.object({
|
|
471
|
-
channelId: z.string(),
|
|
472
|
-
error: z.string()
|
|
473
|
-
})).optional()
|
|
474
|
-
}) } }
|
|
475
|
-
},
|
|
476
|
-
400: { description: "Invalid request" },
|
|
477
|
-
404: { description: "Workspace not found" }
|
|
478
|
-
}
|
|
479
|
-
}), async (c) => {
|
|
480
|
-
const { teamId } = c.req.valid("param");
|
|
481
|
-
const body = c.req.valid("json");
|
|
482
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
483
|
-
if (!workspace?.botToken) return c.json({ error: "Workspace not found or no bot token" }, 404);
|
|
484
|
-
const tenantId = workspace.tenantId || "default";
|
|
485
|
-
const channels = await getSlackChannels(getSlackClient(workspace.botToken), 500);
|
|
486
|
-
const channelMap = new Map(channels.map((ch) => [ch.id, ch]));
|
|
487
|
-
let updated = 0;
|
|
488
|
-
const errors = [];
|
|
489
|
-
await Promise.all(body.channelIds.map(async (channelId) => {
|
|
490
|
-
try {
|
|
491
|
-
const channel = channelMap.get(channelId);
|
|
492
|
-
if (!channel) {
|
|
493
|
-
errors.push({
|
|
494
|
-
channelId,
|
|
495
|
-
error: "Channel not found"
|
|
496
|
-
});
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
await upsertWorkAppSlackChannelAgentConfig(runDbClient_default)({
|
|
500
|
-
tenantId,
|
|
501
|
-
slackTeamId: teamId,
|
|
502
|
-
slackChannelId: channelId,
|
|
503
|
-
slackChannelName: channel.name || channelId,
|
|
504
|
-
slackChannelType: "public",
|
|
505
|
-
projectId: body.agentConfig.projectId,
|
|
506
|
-
agentId: body.agentConfig.agentId,
|
|
507
|
-
agentName: body.agentConfig.agentName,
|
|
508
|
-
enabled: true
|
|
509
|
-
});
|
|
510
|
-
updated++;
|
|
511
|
-
} catch (error) {
|
|
512
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
513
|
-
errors.push({
|
|
514
|
-
channelId,
|
|
515
|
-
error: errorMessage
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
}));
|
|
519
|
-
logger.info({
|
|
520
|
-
teamId,
|
|
521
|
-
agentId: body.agentConfig.agentId,
|
|
522
|
-
updated,
|
|
523
|
-
failed: errors.length
|
|
524
|
-
}, "Bulk set channel agents");
|
|
525
|
-
return c.json({
|
|
526
|
-
success: errors.length === 0,
|
|
527
|
-
updated,
|
|
528
|
-
failed: errors.length,
|
|
529
|
-
errors: errors.length > 0 ? errors : void 0
|
|
530
|
-
});
|
|
531
|
-
});
|
|
532
|
-
app.openapi(createRoute({
|
|
533
|
-
method: "delete",
|
|
534
|
-
path: "/:teamId/channels/bulk",
|
|
535
|
-
summary: "Bulk Remove Channel Configs",
|
|
536
|
-
description: "Remove agent configuration from multiple channels at once",
|
|
537
|
-
operationId: "slack-bulk-delete-channel-agents",
|
|
538
|
-
tags: [
|
|
539
|
-
"Work Apps",
|
|
540
|
-
"Slack",
|
|
541
|
-
"Channels"
|
|
542
|
-
],
|
|
543
|
-
request: {
|
|
544
|
-
params: z.object({ teamId: z.string() }),
|
|
545
|
-
body: { content: { "application/json": { schema: z.object({ channelIds: z.array(z.string()).min(1) }) } } }
|
|
546
|
-
},
|
|
547
|
-
responses: { 200: {
|
|
548
|
-
description: "Configs removed",
|
|
549
|
-
content: { "application/json": { schema: z.object({
|
|
550
|
-
success: z.boolean(),
|
|
551
|
-
removed: z.number()
|
|
552
|
-
}) } }
|
|
553
|
-
} }
|
|
554
|
-
}), async (c) => {
|
|
555
|
-
const { teamId } = c.req.valid("param");
|
|
556
|
-
const body = c.req.valid("json");
|
|
557
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
558
|
-
let removed = 0;
|
|
559
|
-
await Promise.all(body.channelIds.map(async (channelId) => {
|
|
560
|
-
if (await deleteWorkAppSlackChannelAgentConfig(runDbClient_default)(tenantId, teamId, channelId)) removed++;
|
|
561
|
-
}));
|
|
562
|
-
logger.info({
|
|
563
|
-
teamId,
|
|
564
|
-
removed
|
|
565
|
-
}, "Bulk removed channel agent configs");
|
|
566
|
-
return c.json({
|
|
567
|
-
success: true,
|
|
568
|
-
removed
|
|
569
|
-
});
|
|
570
|
-
});
|
|
571
|
-
app.openapi(createRoute({
|
|
572
|
-
method: "delete",
|
|
573
|
-
path: "/:teamId/channels/:channelId/settings",
|
|
574
|
-
summary: "Remove Channel Config",
|
|
575
|
-
description: "Remove the default agent configuration for a channel",
|
|
576
|
-
operationId: "slack-delete-channel-settings",
|
|
577
|
-
tags: [
|
|
578
|
-
"Work Apps",
|
|
579
|
-
"Slack",
|
|
580
|
-
"Channels"
|
|
581
|
-
],
|
|
582
|
-
request: { params: z.object({
|
|
583
|
-
teamId: z.string(),
|
|
584
|
-
channelId: z.string()
|
|
585
|
-
}) },
|
|
586
|
-
responses: { 200: {
|
|
587
|
-
description: "Channel config removed",
|
|
588
|
-
content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
|
|
589
|
-
} }
|
|
590
|
-
}), async (c) => {
|
|
591
|
-
const { teamId, channelId } = c.req.valid("param");
|
|
592
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
593
|
-
const deleted = await deleteWorkAppSlackChannelAgentConfig(runDbClient_default)(tenantId, teamId, channelId);
|
|
594
|
-
logger.info({
|
|
595
|
-
teamId,
|
|
596
|
-
channelId,
|
|
597
|
-
deleted
|
|
598
|
-
}, "Removed channel agent config");
|
|
599
|
-
return c.json({ success: deleted });
|
|
600
|
-
});
|
|
601
|
-
app.openapi(createRoute({
|
|
602
|
-
method: "get",
|
|
603
|
-
path: "/:teamId/users",
|
|
604
|
-
summary: "List Linked Users",
|
|
605
|
-
description: "List all users linked to Inkeep in this workspace",
|
|
606
|
-
operationId: "slack-list-linked-users",
|
|
607
|
-
tags: [
|
|
608
|
-
"Work Apps",
|
|
609
|
-
"Slack",
|
|
610
|
-
"Users"
|
|
611
|
-
],
|
|
612
|
-
request: { params: z.object({ teamId: z.string() }) },
|
|
613
|
-
responses: { 200: {
|
|
614
|
-
description: "List of linked users",
|
|
615
|
-
content: { "application/json": { schema: z.object({ linkedUsers: z.array(z.object({
|
|
616
|
-
id: z.string(),
|
|
617
|
-
slackUserId: z.string(),
|
|
618
|
-
slackTeamId: z.string(),
|
|
619
|
-
slackUsername: z.string().optional(),
|
|
620
|
-
slackEmail: z.string().optional(),
|
|
621
|
-
userId: z.string(),
|
|
622
|
-
linkedAt: z.string(),
|
|
623
|
-
lastUsedAt: z.string().optional()
|
|
624
|
-
})) }) } }
|
|
625
|
-
} }
|
|
626
|
-
}), async (c) => {
|
|
627
|
-
const { teamId } = c.req.valid("param");
|
|
628
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
629
|
-
const linkedUsers = await listWorkAppSlackUserMappingsByTeam(runDbClient_default)(tenantId, teamId);
|
|
630
|
-
logger.info({
|
|
631
|
-
teamId,
|
|
632
|
-
tenantId,
|
|
633
|
-
count: linkedUsers.length
|
|
634
|
-
}, "Fetched linked users");
|
|
635
|
-
return c.json({ linkedUsers: linkedUsers.map((link) => ({
|
|
636
|
-
id: link.id,
|
|
637
|
-
slackUserId: link.slackUserId,
|
|
638
|
-
slackTeamId: link.slackTeamId,
|
|
639
|
-
slackUsername: link.slackUsername || void 0,
|
|
640
|
-
slackEmail: link.slackEmail || void 0,
|
|
641
|
-
userId: link.inkeepUserId,
|
|
642
|
-
linkedAt: link.linkedAt,
|
|
643
|
-
lastUsedAt: link.lastUsedAt || void 0
|
|
644
|
-
})) });
|
|
645
|
-
});
|
|
646
|
-
app.openapi(createRoute({
|
|
647
|
-
method: "get",
|
|
648
|
-
path: "/:teamId/health",
|
|
649
|
-
summary: "Check Workspace Health",
|
|
650
|
-
description: "Verify the bot token is valid and check permissions. Returns bot info and permission status.",
|
|
651
|
-
operationId: "slack-workspace-health",
|
|
652
|
-
tags: [
|
|
653
|
-
"Work Apps",
|
|
654
|
-
"Slack",
|
|
655
|
-
"Workspaces"
|
|
656
|
-
],
|
|
657
|
-
request: { params: z.object({ teamId: z.string() }) },
|
|
658
|
-
responses: {
|
|
659
|
-
200: {
|
|
660
|
-
description: "Health check result",
|
|
661
|
-
content: { "application/json": { schema: z.object({
|
|
662
|
-
healthy: z.boolean(),
|
|
663
|
-
botId: z.string().optional(),
|
|
664
|
-
botName: z.string().optional(),
|
|
665
|
-
teamId: z.string().optional(),
|
|
666
|
-
teamName: z.string().optional(),
|
|
667
|
-
permissions: z.object({
|
|
668
|
-
canPostMessages: z.boolean(),
|
|
669
|
-
canReadChannels: z.boolean(),
|
|
670
|
-
canReadHistory: z.boolean()
|
|
671
|
-
}),
|
|
672
|
-
error: z.string().optional()
|
|
673
|
-
}) } }
|
|
674
|
-
},
|
|
675
|
-
404: { description: "Workspace not found" }
|
|
676
|
-
}
|
|
677
|
-
}), async (c) => {
|
|
678
|
-
const { teamId } = c.req.valid("param");
|
|
679
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
680
|
-
if (!workspace?.botToken) return c.json({
|
|
681
|
-
healthy: false,
|
|
682
|
-
permissions: {
|
|
683
|
-
canPostMessages: false,
|
|
684
|
-
canReadChannels: false,
|
|
685
|
-
canReadHistory: false
|
|
686
|
-
},
|
|
687
|
-
error: "Workspace not found or no bot token available"
|
|
688
|
-
});
|
|
689
|
-
try {
|
|
690
|
-
const slackClient = getSlackClient(workspace.botToken);
|
|
691
|
-
const authResult = await slackClient.auth.test();
|
|
692
|
-
if (!authResult.ok) return c.json({
|
|
693
|
-
healthy: false,
|
|
694
|
-
permissions: {
|
|
695
|
-
canPostMessages: false,
|
|
696
|
-
canReadChannels: false,
|
|
697
|
-
canReadHistory: false
|
|
698
|
-
},
|
|
699
|
-
error: "Bot token is invalid or revoked"
|
|
700
|
-
});
|
|
701
|
-
const permissions = {
|
|
702
|
-
canPostMessages: true,
|
|
703
|
-
canReadChannels: true,
|
|
704
|
-
canReadHistory: true
|
|
705
|
-
};
|
|
706
|
-
try {
|
|
707
|
-
await slackClient.conversations.list({ limit: 1 });
|
|
708
|
-
} catch {
|
|
709
|
-
permissions.canReadChannels = false;
|
|
710
|
-
}
|
|
711
|
-
logger.info({
|
|
712
|
-
teamId,
|
|
713
|
-
botId: authResult.user_id,
|
|
714
|
-
permissions
|
|
715
|
-
}, "Workspace health check completed");
|
|
716
|
-
return c.json({
|
|
717
|
-
healthy: true,
|
|
718
|
-
botId: authResult.user_id,
|
|
719
|
-
botName: authResult.user,
|
|
720
|
-
teamId: authResult.team_id,
|
|
721
|
-
teamName: authResult.team,
|
|
722
|
-
permissions
|
|
723
|
-
});
|
|
724
|
-
} catch (error) {
|
|
725
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
726
|
-
logger.error({
|
|
727
|
-
error: errorMessage,
|
|
728
|
-
teamId
|
|
729
|
-
}, "Health check failed");
|
|
730
|
-
return c.json({
|
|
731
|
-
healthy: false,
|
|
732
|
-
permissions: {
|
|
733
|
-
canPostMessages: false,
|
|
734
|
-
canReadChannels: false,
|
|
735
|
-
canReadHistory: false
|
|
736
|
-
},
|
|
737
|
-
error: errorMessage
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
app.openapi(createRoute({
|
|
742
|
-
method: "post",
|
|
743
|
-
path: "/:teamId/test-message",
|
|
744
|
-
summary: "Send Test Message",
|
|
745
|
-
description: "Send a test message to verify the bot is working correctly.",
|
|
746
|
-
operationId: "slack-test-message",
|
|
747
|
-
tags: [
|
|
748
|
-
"Work Apps",
|
|
749
|
-
"Slack",
|
|
750
|
-
"Workspaces"
|
|
751
|
-
],
|
|
752
|
-
request: {
|
|
753
|
-
params: z.object({ teamId: z.string() }),
|
|
754
|
-
body: { content: { "application/json": { schema: z.object({
|
|
755
|
-
channelId: z.string(),
|
|
756
|
-
message: z.string().optional()
|
|
757
|
-
}) } } }
|
|
758
|
-
},
|
|
759
|
-
responses: {
|
|
760
|
-
200: {
|
|
761
|
-
description: "Test message sent",
|
|
762
|
-
content: { "application/json": { schema: z.object({
|
|
763
|
-
success: z.boolean(),
|
|
764
|
-
messageTs: z.string().optional(),
|
|
765
|
-
error: z.string().optional()
|
|
766
|
-
}) } }
|
|
767
|
-
},
|
|
768
|
-
400: { description: "Invalid request" },
|
|
769
|
-
404: { description: "Workspace not found" }
|
|
770
|
-
}
|
|
771
|
-
}), async (c) => {
|
|
772
|
-
const { teamId } = c.req.valid("param");
|
|
773
|
-
const { channelId, message } = c.req.valid("json");
|
|
774
|
-
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
775
|
-
if (!workspace?.botToken) return c.json({
|
|
776
|
-
success: false,
|
|
777
|
-
error: "Workspace not found or no bot token available"
|
|
778
|
-
}, 404);
|
|
779
|
-
try {
|
|
780
|
-
const slackClient = getSlackClient(workspace.botToken);
|
|
781
|
-
const testMessage = message || "✅ *Test message from Inkeep*\n\nYour Slack integration is working correctly!";
|
|
782
|
-
const result = await slackClient.chat.postMessage({
|
|
783
|
-
channel: channelId,
|
|
784
|
-
text: testMessage,
|
|
785
|
-
blocks: [{
|
|
786
|
-
type: "section",
|
|
787
|
-
text: {
|
|
788
|
-
type: "mrkdwn",
|
|
789
|
-
text: testMessage
|
|
790
|
-
}
|
|
791
|
-
}, {
|
|
792
|
-
type: "context",
|
|
793
|
-
elements: [{
|
|
794
|
-
type: "mrkdwn",
|
|
795
|
-
text: "_This is a test message from the Inkeep dashboard_"
|
|
796
|
-
}]
|
|
797
|
-
}]
|
|
798
|
-
});
|
|
799
|
-
if (!result.ok) return c.json({
|
|
800
|
-
success: false,
|
|
801
|
-
error: result.error || "Failed to send message"
|
|
802
|
-
});
|
|
803
|
-
logger.info({
|
|
804
|
-
teamId,
|
|
805
|
-
channelId,
|
|
806
|
-
messageTs: result.ts
|
|
807
|
-
}, "Test message sent");
|
|
808
|
-
return c.json({
|
|
809
|
-
success: true,
|
|
810
|
-
messageTs: result.ts
|
|
811
|
-
});
|
|
812
|
-
} catch (error) {
|
|
813
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
814
|
-
logger.error({
|
|
815
|
-
error: errorMessage,
|
|
816
|
-
teamId,
|
|
817
|
-
channelId
|
|
818
|
-
}, "Failed to send test message");
|
|
819
|
-
return c.json({
|
|
820
|
-
success: false,
|
|
821
|
-
error: errorMessage
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
});
|
|
825
|
-
var workspaces_default = app;
|
|
826
|
-
|
|
827
|
-
//#endregion
|
|
828
|
-
export { workspaces_default as default };
|