@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.
Files changed (68) hide show
  1. package/dist/db/index.d.ts +1 -2
  2. package/dist/db/index.js +1 -2
  3. package/dist/db/runDbClient.d.ts +2 -2
  4. package/dist/env.d.ts +2 -24
  5. package/dist/env.js +1 -12
  6. package/dist/github/routes/setup.d.ts +2 -2
  7. package/dist/github/routes/tokenExchange.d.ts +2 -2
  8. package/package.json +2 -10
  9. package/dist/db/manageDbClient.d.ts +0 -7
  10. package/dist/db/manageDbClient.js +0 -16
  11. package/dist/slack/index.d.ts +0 -19
  12. package/dist/slack/index.js +0 -29
  13. package/dist/slack/middleware/permissions.d.ts +0 -16
  14. package/dist/slack/middleware/permissions.js +0 -49
  15. package/dist/slack/routes/events.d.ts +0 -10
  16. package/dist/slack/routes/events.js +0 -319
  17. package/dist/slack/routes/index.d.ts +0 -11
  18. package/dist/slack/routes/index.js +0 -64
  19. package/dist/slack/routes/internal.d.ts +0 -10
  20. package/dist/slack/routes/internal.js +0 -107
  21. package/dist/slack/routes/oauth.d.ts +0 -12
  22. package/dist/slack/routes/oauth.js +0 -218
  23. package/dist/slack/routes/resources.d.ts +0 -10
  24. package/dist/slack/routes/resources.js +0 -163
  25. package/dist/slack/routes/users.d.ts +0 -15
  26. package/dist/slack/routes/users.js +0 -430
  27. package/dist/slack/routes/workspaces.d.ts +0 -10
  28. package/dist/slack/routes/workspaces.js +0 -828
  29. package/dist/slack/routes.d.ts +0 -7
  30. package/dist/slack/routes.js +0 -12
  31. package/dist/slack/services/agent-resolution.d.ts +0 -49
  32. package/dist/slack/services/agent-resolution.js +0 -135
  33. package/dist/slack/services/api-client.d.ts +0 -161
  34. package/dist/slack/services/api-client.js +0 -248
  35. package/dist/slack/services/auth/index.d.ts +0 -61
  36. package/dist/slack/services/auth/index.js +0 -164
  37. package/dist/slack/services/blocks/index.d.ts +0 -60
  38. package/dist/slack/services/blocks/index.js +0 -143
  39. package/dist/slack/services/client.d.ts +0 -78
  40. package/dist/slack/services/client.js +0 -152
  41. package/dist/slack/services/commands/index.d.ts +0 -15
  42. package/dist/slack/services/commands/index.js +0 -556
  43. package/dist/slack/services/events/app-mention.d.ts +0 -41
  44. package/dist/slack/services/events/app-mention.js +0 -212
  45. package/dist/slack/services/events/block-actions.d.ts +0 -47
  46. package/dist/slack/services/events/block-actions.js +0 -287
  47. package/dist/slack/services/events/index.d.ts +0 -6
  48. package/dist/slack/services/events/index.js +0 -7
  49. package/dist/slack/services/events/modal-submission.d.ts +0 -12
  50. package/dist/slack/services/events/modal-submission.js +0 -279
  51. package/dist/slack/services/events/streaming.d.ts +0 -27
  52. package/dist/slack/services/events/streaming.js +0 -285
  53. package/dist/slack/services/events/utils.d.ts +0 -129
  54. package/dist/slack/services/events/utils.js +0 -315
  55. package/dist/slack/services/index.d.ts +0 -18
  56. package/dist/slack/services/index.js +0 -18
  57. package/dist/slack/services/modals.d.ts +0 -67
  58. package/dist/slack/services/modals.js +0 -203
  59. package/dist/slack/services/nango.d.ts +0 -82
  60. package/dist/slack/services/nango.js +0 -326
  61. package/dist/slack/services/security.d.ts +0 -35
  62. package/dist/slack/services/security.js +0 -65
  63. package/dist/slack/services/types.d.ts +0 -26
  64. package/dist/slack/services/types.js +0 -1
  65. package/dist/slack/services/workspace-tokens.d.ts +0 -37
  66. package/dist/slack/services/workspace-tokens.js +0 -39
  67. package/dist/slack/types.d.ts +0 -10
  68. 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 };