@inkeep/agents-work-apps 0.0.0-dev-20260219033751 → 0.0.0-dev-20260219045007

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.
@@ -4,10 +4,10 @@ import "./routes/setup.js";
4
4
  import "./routes/tokenExchange.js";
5
5
  import { WebhookVerificationResult, verifyWebhookSignature } from "./routes/webhooks.js";
6
6
  import { Hono } from "hono";
7
- import * as hono_types1 from "hono/types";
7
+ import * as hono_types0 from "hono/types";
8
8
 
9
9
  //#region src/github/index.d.ts
10
- declare function createGithubRoutes(): Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
11
- declare const githubRoutes: Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
10
+ declare function createGithubRoutes(): Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
11
+ declare const githubRoutes: Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
12
12
  //#endregion
13
13
  export { GenerateInstallationAccessTokenResult, GenerateTokenError, GenerateTokenResult, GitHubAppConfig, InstallationAccessToken, InstallationInfo, LookupInstallationError, LookupInstallationForRepoResult, LookupInstallationResult, WebhookVerificationResult, clearConfigCache, createAppJwt, createGithubRoutes, determineStatus, fetchInstallationDetails, fetchInstallationRepositories, generateInstallationAccessToken, getGitHubAppConfig, getGitHubAppName, getStateSigningSecret, getWebhookSecret, githubRoutes, isGitHubAppConfigured, isGitHubAppNameConfigured, isStateSigningConfigured, isWebhookConfigured, lookupInstallationForRepo, validateGitHubAppConfigOnStartup, validateGitHubInstallFlowConfigOnStartup, validateGitHubWebhookConfigOnStartup, verifyWebhookSignature };
@@ -1,11 +1,11 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types5 from "hono/types";
2
+ import * as hono_types9 from "hono/types";
3
3
 
4
4
  //#region src/github/mcp/index.d.ts
5
5
  declare const app: Hono<{
6
6
  Variables: {
7
7
  toolId: string;
8
8
  };
9
- }, hono_types5.BlankSchema, "/">;
9
+ }, hono_types9.BlankSchema, "/">;
10
10
  //#endregion
11
11
  export { app as default };
@@ -76,8 +76,8 @@ declare const ChangedFileSchema: z.ZodObject<{
76
76
  path: z.ZodString;
77
77
  status: z.ZodEnum<{
78
78
  added: "added";
79
- removed: "removed";
80
79
  modified: "modified";
80
+ removed: "removed";
81
81
  renamed: "renamed";
82
82
  copied: "copied";
83
83
  changed: "changed";
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types0 from "hono/types";
2
+ import * as hono_types5 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/setup.d.ts
5
- declare const app: Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types5.BlankEnv, hono_types5.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types6 from "hono/types";
2
+ import * as hono_types7 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/tokenExchange.d.ts
5
- declare const app: Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types7.BlankEnv, hono_types7.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types8 from "hono/types";
2
+ import * as hono_types3 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/webhooks.d.ts
5
5
  interface WebhookVerificationResult {
@@ -7,6 +7,6 @@ interface WebhookVerificationResult {
7
7
  error?: string;
8
8
  }
9
9
  declare function verifyWebhookSignature(payload: string, signature: string | undefined, secret: string): WebhookVerificationResult;
10
- declare const app: Hono<hono_types8.BlankEnv, hono_types8.BlankSchema, "/">;
10
+ declare const app: Hono<hono_types3.BlankEnv, hono_types3.BlankSchema, "/">;
11
11
  //#endregion
12
12
  export { WebhookVerificationResult, app as default, verifyWebhookSignature };
@@ -4,6 +4,7 @@ import { findWorkspaceConnectionByTeamId } from "../services/nango.js";
4
4
  import { checkUserIsChannelMember, getSlackClient } from "../services/client.js";
5
5
  import { OrgRoles, createApiError, findWorkAppSlackUserMappingByInkeepUserId, getUserOrganizationsFromDb } from "@inkeep/agents-core";
6
6
  import { createMiddleware } from "hono/factory";
7
+ import { registerAuthzMeta } from "@inkeep/agents-core/middleware";
7
8
 
8
9
  //#region src/slack/middleware/permissions.ts
9
10
  const logger = getLogger("slack-permissions");
@@ -41,49 +42,57 @@ async function resolveWorkAppTenantContext(c, teamId, userId) {
41
42
  * Middleware that requires Inkeep org admin/owner role.
42
43
  * Use for workspace-level settings that only Inkeep organization admins can modify.
43
44
  */
44
- const requireWorkspaceAdmin = () => createMiddleware(async (c, next) => {
45
- if (process.env.ENVIRONMENT === "test" && c.req.header("x-test-bypass-auth") === "true") {
45
+ const requireWorkspaceAdmin = () => {
46
+ const mw = createMiddleware(async (c, next) => {
47
+ if (process.env.ENVIRONMENT === "test" && c.req.header("x-test-bypass-auth") === "true") {
48
+ await next();
49
+ return;
50
+ }
51
+ const userId = c.get("userId");
52
+ if (!userId) throw createApiError({
53
+ code: "unauthorized",
54
+ message: "User context not found",
55
+ instance: c.req.path
56
+ });
57
+ if (userId === "system" || userId.startsWith("apikey:")) {
58
+ await next();
59
+ return;
60
+ }
61
+ const teamId = c.req.param("teamId") || c.req.param("workspaceId");
62
+ if (teamId && !c.get("tenantRole")) await resolveWorkAppTenantContext(c, teamId, userId);
63
+ const tenantId = c.get("tenantId");
64
+ const tenantRole = c.get("tenantRole");
65
+ if (!tenantId) throw createApiError({
66
+ code: "unauthorized",
67
+ message: "Organization context not found",
68
+ instance: c.req.path
69
+ });
70
+ if (!isOrgAdmin(tenantRole)) {
71
+ logger.warn({
72
+ userId,
73
+ tenantId,
74
+ tenantRole,
75
+ path: c.req.path
76
+ }, "User does not have admin role for workspace operation");
77
+ throw createApiError({
78
+ code: "forbidden",
79
+ message: "Only organization administrators can modify workspace settings",
80
+ instance: c.req.path,
81
+ extensions: {
82
+ requiredRole: "admin or owner",
83
+ currentRole: tenantRole
84
+ }
85
+ });
86
+ }
46
87
  await next();
47
- return;
48
- }
49
- const userId = c.get("userId");
50
- if (!userId) throw createApiError({
51
- code: "unauthorized",
52
- message: "User context not found",
53
- instance: c.req.path
54
88
  });
55
- if (userId === "system" || userId.startsWith("apikey:")) {
56
- await next();
57
- return;
58
- }
59
- const teamId = c.req.param("teamId") || c.req.param("workspaceId");
60
- if (teamId && !c.get("tenantRole")) await resolveWorkAppTenantContext(c, teamId, userId);
61
- const tenantId = c.get("tenantId");
62
- const tenantRole = c.get("tenantRole");
63
- if (!tenantId) throw createApiError({
64
- code: "unauthorized",
65
- message: "Organization context not found",
66
- instance: c.req.path
89
+ registerAuthzMeta(mw, {
90
+ resource: "organization",
91
+ permission: "admin",
92
+ description: "Requires Inkeep org admin/owner role to modify workspace settings"
67
93
  });
68
- if (!isOrgAdmin(tenantRole)) {
69
- logger.warn({
70
- userId,
71
- tenantId,
72
- tenantRole,
73
- path: c.req.path
74
- }, "User does not have admin role for workspace operation");
75
- throw createApiError({
76
- code: "forbidden",
77
- message: "Only organization administrators can modify workspace settings",
78
- instance: c.req.path,
79
- extensions: {
80
- requiredRole: "admin or owner",
81
- currentRole: tenantRole
82
- }
83
- });
84
- }
85
- await next();
86
- });
94
+ return mw;
95
+ };
87
96
  /**
88
97
  * Middleware that requires either:
89
98
  * 1. Org admin/owner role (can modify any channel), OR
@@ -91,77 +100,81 @@ const requireWorkspaceAdmin = () => createMiddleware(async (c, next) => {
91
100
  *
92
101
  * Use for channel-level settings where members can configure their own channels.
93
102
  */
94
- const requireChannelMemberOrAdmin = () => createMiddleware(async (c, next) => {
95
- if (process.env.ENVIRONMENT === "test" && c.req.header("x-test-bypass-auth") === "true") {
96
- await next();
97
- return;
98
- }
99
- const userId = c.get("userId");
100
- if (!userId) throw createApiError({
101
- code: "unauthorized",
102
- message: "User context not found",
103
- instance: c.req.path
104
- });
105
- if (userId === "system" || userId.startsWith("apikey:")) {
106
- await next();
107
- return;
108
- }
109
- const teamId = c.req.param("teamId");
110
- if (teamId && !c.get("tenantRole")) await resolveWorkAppTenantContext(c, teamId, userId);
111
- const tenantId = c.get("tenantId");
112
- const tenantRole = c.get("tenantRole");
113
- if (!tenantId) throw createApiError({
114
- code: "unauthorized",
115
- message: "Organization context not found",
116
- instance: c.req.path
117
- });
118
- if (isOrgAdmin(tenantRole)) {
119
- await next();
120
- return;
121
- }
122
- const channelId = c.req.param("channelId");
123
- if (!teamId || !channelId) throw createApiError({
124
- code: "bad_request",
125
- message: "Team ID and Channel ID are required",
126
- instance: c.req.path
127
- });
128
- const userMapping = (await findWorkAppSlackUserMappingByInkeepUserId(runDbClient_default)(userId)).find((m) => m.tenantId === tenantId && m.slackTeamId === teamId);
129
- if (!userMapping) throw createApiError({
130
- code: "forbidden",
131
- message: "You must link your Slack account to modify channel settings. Use /inkeep link in Slack.",
132
- instance: c.req.path
133
- });
134
- const workspace = await findWorkspaceConnectionByTeamId(teamId);
135
- if (!workspace?.botToken) throw createApiError({
136
- code: "not_found",
137
- message: "Slack workspace not found or not properly configured",
138
- instance: c.req.path
139
- });
140
- if (!await checkUserIsChannelMember(getSlackClient(workspace.botToken), channelId, userMapping.slackUserId)) {
141
- logger.info({
103
+ const requireChannelMemberOrAdmin = () => {
104
+ const mw = createMiddleware(async (c, next) => {
105
+ if (process.env.ENVIRONMENT === "test" && c.req.header("x-test-bypass-auth") === "true") {
106
+ await next();
107
+ return;
108
+ }
109
+ const userId = c.get("userId");
110
+ if (!userId) throw createApiError({
111
+ code: "unauthorized",
112
+ message: "User context not found",
113
+ instance: c.req.path
114
+ });
115
+ if (userId === "system" || userId.startsWith("apikey:")) {
116
+ await next();
117
+ return;
118
+ }
119
+ const teamId = c.req.param("teamId");
120
+ if (teamId && !c.get("tenantRole")) await resolveWorkAppTenantContext(c, teamId, userId);
121
+ const tenantId = c.get("tenantId");
122
+ const tenantRole = c.get("tenantRole");
123
+ if (!tenantId) throw createApiError({
124
+ code: "unauthorized",
125
+ message: "Organization context not found",
126
+ instance: c.req.path
127
+ });
128
+ if (isOrgAdmin(tenantRole)) {
129
+ await next();
130
+ return;
131
+ }
132
+ const channelId = c.req.param("channelId");
133
+ if (!teamId || !channelId) throw createApiError({
134
+ code: "bad_request",
135
+ message: "Team ID and Channel ID are required",
136
+ instance: c.req.path
137
+ });
138
+ const userMapping = (await findWorkAppSlackUserMappingByInkeepUserId(runDbClient_default)(userId)).find((m) => m.tenantId === tenantId && m.slackTeamId === teamId);
139
+ if (!userMapping) throw createApiError({
140
+ code: "forbidden",
141
+ message: "You must link your Slack account to modify channel settings. Use /inkeep link in Slack.",
142
+ instance: c.req.path
143
+ });
144
+ const workspace = await findWorkspaceConnectionByTeamId(teamId);
145
+ if (!workspace?.botToken) throw createApiError({
146
+ code: "not_found",
147
+ message: "Slack workspace not found or not properly configured",
148
+ instance: c.req.path
149
+ });
150
+ if (!await checkUserIsChannelMember(getSlackClient(workspace.botToken), channelId, userMapping.slackUserId)) {
151
+ logger.info({
152
+ userId,
153
+ slackUserId: userMapping.slackUserId,
154
+ channelId,
155
+ teamId
156
+ }, "User is not a member of the channel");
157
+ throw createApiError({
158
+ code: "forbidden",
159
+ message: "You can only configure channels you are a member of",
160
+ instance: c.req.path,
161
+ extensions: {
162
+ channelId,
163
+ reason: "not_channel_member"
164
+ }
165
+ });
166
+ }
167
+ logger.debug({
142
168
  userId,
143
169
  slackUserId: userMapping.slackUserId,
144
170
  channelId,
145
171
  teamId
146
- }, "User is not a member of the channel");
147
- throw createApiError({
148
- code: "forbidden",
149
- message: "You can only configure channels you are a member of",
150
- instance: c.req.path,
151
- extensions: {
152
- channelId,
153
- reason: "not_channel_member"
154
- }
155
- });
156
- }
157
- logger.debug({
158
- userId,
159
- slackUserId: userMapping.slackUserId,
160
- channelId,
161
- teamId
162
- }, "User verified as channel member");
163
- await next();
164
- });
172
+ }, "User verified as channel member");
173
+ await next();
174
+ });
175
+ registerAuthzMeta(mw, { description: "Requires Inkeep organization admin role, or Slack channel membership to modify channel settings" });
176
+ return mw;
177
+ };
165
178
 
166
179
  //#endregion
167
180
  export { isOrgAdmin, requireChannelMemberOrAdmin, requireWorkspaceAdmin };
@@ -5,9 +5,10 @@ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWork
5
5
  import { getSlackClient, getSlackTeamInfo, getSlackUserInfo } from "../services/client.js";
6
6
  import { getBotTokenForTeam, setBotTokenForTeam } from "../services/workspace-tokens.js";
7
7
  import "../services/index.js";
8
- import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
8
+ import { OpenAPIHono, z } from "@hono/zod-openapi";
9
9
  import { createWorkAppSlackWorkspace } from "@inkeep/agents-core";
10
10
  import * as crypto$1 from "node:crypto";
11
+ import { createProtectedRoute, noAuth } from "@inkeep/agents-core/middleware";
11
12
 
12
13
  //#region src/slack/routes/oauth.ts
13
14
  /**
@@ -70,7 +71,7 @@ function parseOAuthState(stateStr) {
70
71
  }
71
72
  }
72
73
  const app = new OpenAPIHono();
73
- app.openapi(createRoute({
74
+ app.openapi(createProtectedRoute({
74
75
  method: "get",
75
76
  path: "/install",
76
77
  summary: "Install Slack App",
@@ -81,6 +82,7 @@ app.openapi(createRoute({
81
82
  "Slack",
82
83
  "OAuth"
83
84
  ],
85
+ permission: noAuth(),
84
86
  request: { query: z.object({ tenant_id: z.string().optional() }) },
85
87
  responses: { 302: { description: "Redirect to Slack OAuth" } }
86
88
  }), (c) => {
@@ -115,7 +117,7 @@ app.openapi(createRoute({
115
117
  }, "Redirecting to Slack OAuth");
116
118
  return c.redirect(slackAuthUrl.toString());
117
119
  });
118
- app.openapi(createRoute({
120
+ app.openapi(createProtectedRoute({
119
121
  method: "get",
120
122
  path: "/oauth_redirect",
121
123
  summary: "Slack OAuth Callback",
@@ -126,6 +128,7 @@ app.openapi(createRoute({
126
128
  "Slack",
127
129
  "OAuth"
128
130
  ],
131
+ permission: noAuth(),
129
132
  request: { query: z.object({
130
133
  code: z.string().optional(),
131
134
  error: z.string().optional(),
@@ -2,8 +2,9 @@ import { getLogger } from "../../logger.js";
2
2
  import runDbClient_default from "../../db/runDbClient.js";
3
3
  import { createConnectSession } from "../services/nango.js";
4
4
  import "../services/index.js";
5
- import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
5
+ import { OpenAPIHono, z } from "@hono/zod-openapi";
6
6
  import { createWorkAppSlackUserMapping, deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingByInkeepUserId, verifySlackLinkToken } from "@inkeep/agents-core";
7
+ import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
7
8
 
8
9
  //#region src/slack/routes/users.ts
9
10
  /**
@@ -29,7 +30,7 @@ function isAuthorizedForUser(c, requestedUserId) {
29
30
  return false;
30
31
  }
31
32
  const app = new OpenAPIHono();
32
- app.openapi(createRoute({
33
+ app.openapi(createProtectedRoute({
33
34
  method: "get",
34
35
  path: "/link-status",
35
36
  summary: "Check Link Status",
@@ -40,6 +41,7 @@ app.openapi(createRoute({
40
41
  "Slack",
41
42
  "Users"
42
43
  ],
44
+ permission: inheritedWorkAppsAuth(),
43
45
  request: { query: z.object({
44
46
  slackUserId: z.string(),
45
47
  slackTeamId: z.string(),
@@ -67,7 +69,7 @@ app.openapi(createRoute({
67
69
  });
68
70
  return c.json({ linked: false });
69
71
  });
70
- app.openapi(createRoute({
72
+ app.openapi(createProtectedRoute({
71
73
  method: "post",
72
74
  path: "/link/verify-token",
73
75
  summary: "Verify Link Token",
@@ -78,6 +80,7 @@ app.openapi(createRoute({
78
80
  "Slack",
79
81
  "Users"
80
82
  ],
83
+ permission: inheritedWorkAppsAuth(),
81
84
  request: { body: { content: { "application/json": { schema: z.object({
82
85
  token: z.string().min(1),
83
86
  userId: z.string().min(1),
@@ -171,7 +174,7 @@ app.openapi(createRoute({
171
174
  return c.json({ error: "Failed to verify link. Please try again." }, 500);
172
175
  }
173
176
  });
174
- app.openapi(createRoute({
177
+ app.openapi(createProtectedRoute({
175
178
  method: "post",
176
179
  path: "/connect",
177
180
  summary: "Create Nango Connect Session",
@@ -182,6 +185,7 @@ app.openapi(createRoute({
182
185
  "Slack",
183
186
  "Users"
184
187
  ],
188
+ permission: inheritedWorkAppsAuth(),
185
189
  request: { body: { content: { "application/json": { schema: z.object({
186
190
  userId: z.string().describe("Inkeep user ID"),
187
191
  userEmail: z.string().optional().describe("User email"),
@@ -217,7 +221,7 @@ app.openapi(createRoute({
217
221
  if (!session) return c.json({ error: "Failed to create session" }, 500);
218
222
  return c.json(session);
219
223
  });
220
- app.openapi(createRoute({
224
+ app.openapi(createProtectedRoute({
221
225
  method: "post",
222
226
  path: "/disconnect",
223
227
  summary: "Disconnect User",
@@ -228,6 +232,7 @@ app.openapi(createRoute({
228
232
  "Slack",
229
233
  "Users"
230
234
  ],
235
+ permission: inheritedWorkAppsAuth(),
231
236
  request: { body: { content: { "application/json": { schema: z.object({
232
237
  userId: z.string().optional().describe("Inkeep user ID"),
233
238
  slackUserId: z.string().optional().describe("Slack user ID"),
@@ -285,7 +290,7 @@ app.openapi(createRoute({
285
290
  return c.json({ error: "Failed to disconnect" }, 500);
286
291
  }
287
292
  });
288
- app.openapi(createRoute({
293
+ app.openapi(createProtectedRoute({
289
294
  method: "get",
290
295
  path: "/status",
291
296
  summary: "Get Connection Status",
@@ -296,6 +301,7 @@ app.openapi(createRoute({
296
301
  "Slack",
297
302
  "Users"
298
303
  ],
304
+ permission: inheritedWorkAppsAuth(),
299
305
  request: { query: z.object({ userId: z.string().describe("Inkeep user ID") }) },
300
306
  responses: {
301
307
  200: {
@@ -4,8 +4,9 @@ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWork
4
4
  import { getSlackChannels, getSlackClient, revokeSlackToken } from "../services/client.js";
5
5
  import "../services/index.js";
6
6
  import { requireChannelMemberOrAdmin, requireWorkspaceAdmin } from "../middleware/permissions.js";
7
- import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
7
+ import { OpenAPIHono, z } from "@hono/zod-openapi";
8
8
  import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
9
+ import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
9
10
 
10
11
  //#region src/slack/routes/workspaces.ts
11
12
  /**
@@ -39,22 +40,6 @@ function verifyTenantOwnership(c, workspaceTenantId) {
39
40
  return sessionTenantId === workspaceTenantId;
40
41
  }
41
42
  const app = new OpenAPIHono();
42
- app.use("/:teamId/settings", async (c, next) => {
43
- if (c.req.method === "PUT") return requireWorkspaceAdmin()(c, next);
44
- return next();
45
- });
46
- app.use("/:teamId", async (c, next) => {
47
- if (c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
48
- return next();
49
- });
50
- app.use("/:teamId/channels/:channelId/settings", async (c, next) => {
51
- if (c.req.method === "PUT" || c.req.method === "DELETE") return requireChannelMemberOrAdmin()(c, next);
52
- return next();
53
- });
54
- app.use("/:teamId/test-message", async (c, next) => {
55
- if (c.req.method === "POST") return requireWorkspaceAdmin()(c, next);
56
- return next();
57
- });
58
43
  const ChannelAgentConfigSchema = z.object({
59
44
  projectId: z.string(),
60
45
  agentId: z.string(),
@@ -62,7 +47,7 @@ const ChannelAgentConfigSchema = z.object({
62
47
  projectName: z.string().optional()
63
48
  });
64
49
  const WorkspaceSettingsSchema = z.object({ defaultAgent: ChannelAgentConfigSchema.optional() });
65
- app.openapi(createRoute({
50
+ app.openapi(createProtectedRoute({
66
51
  method: "get",
67
52
  path: "/",
68
53
  summary: "List Workspaces",
@@ -73,6 +58,7 @@ app.openapi(createRoute({
73
58
  "Slack",
74
59
  "Workspaces"
75
60
  ],
61
+ permission: inheritedWorkAppsAuth(),
76
62
  responses: { 200: {
77
63
  description: "List of workspaces",
78
64
  content: { "application/json": { schema: z.object({ workspaces: z.array(z.object({
@@ -111,7 +97,7 @@ app.openapi(createRoute({
111
97
  return c.json({ workspaces: [] });
112
98
  }
113
99
  });
114
- app.openapi(createRoute({
100
+ app.openapi(createProtectedRoute({
115
101
  method: "get",
116
102
  path: "/{teamId}",
117
103
  summary: "Get Workspace",
@@ -122,6 +108,7 @@ app.openapi(createRoute({
122
108
  "Slack",
123
109
  "Workspaces"
124
110
  ],
111
+ permission: inheritedWorkAppsAuth(),
125
112
  request: { params: z.object({ teamId: z.string() }) },
126
113
  responses: {
127
114
  200: {
@@ -155,7 +142,7 @@ app.openapi(createRoute({
155
142
  defaultAgent
156
143
  });
157
144
  });
158
- app.openapi(createRoute({
145
+ app.openapi(createProtectedRoute({
159
146
  method: "get",
160
147
  path: "/{teamId}/settings",
161
148
  summary: "Get Workspace Settings",
@@ -166,6 +153,7 @@ app.openapi(createRoute({
166
153
  "Slack",
167
154
  "Workspaces"
168
155
  ],
156
+ permission: inheritedWorkAppsAuth(),
169
157
  request: { params: z.object({ teamId: z.string() }) },
170
158
  responses: { 200: {
171
159
  description: "Workspace settings",
@@ -188,7 +176,7 @@ app.openapi(createRoute({
188
176
  };
189
177
  return c.json({ defaultAgent });
190
178
  });
191
- app.openapi(createRoute({
179
+ app.openapi(createProtectedRoute({
192
180
  method: "put",
193
181
  path: "/{teamId}/settings",
194
182
  summary: "Update Workspace Settings",
@@ -199,6 +187,7 @@ app.openapi(createRoute({
199
187
  "Slack",
200
188
  "Workspaces"
201
189
  ],
190
+ permission: requireWorkspaceAdmin(),
202
191
  request: {
203
192
  params: z.object({ teamId: z.string() }),
204
193
  body: { content: { "application/json": { schema: WorkspaceSettingsSchema } } }
@@ -232,7 +221,7 @@ app.openapi(createRoute({
232
221
  }
233
222
  return c.json({ success: true });
234
223
  });
235
- app.openapi(createRoute({
224
+ app.openapi(createProtectedRoute({
236
225
  method: "delete",
237
226
  path: "/{teamId}",
238
227
  summary: "Uninstall Workspace",
@@ -243,6 +232,7 @@ app.openapi(createRoute({
243
232
  "Slack",
244
233
  "Workspaces"
245
234
  ],
235
+ permission: requireWorkspaceAdmin(),
246
236
  request: { params: z.object({ teamId: z.string() }) },
247
237
  responses: {
248
238
  200: {
@@ -301,7 +291,7 @@ app.openapi(createRoute({
301
291
  return c.json({ error: "Failed to uninstall workspace" }, 500);
302
292
  }
303
293
  });
304
- app.openapi(createRoute({
294
+ app.openapi(createProtectedRoute({
305
295
  method: "get",
306
296
  path: "/{teamId}/channels",
307
297
  summary: "List Channels",
@@ -312,6 +302,7 @@ app.openapi(createRoute({
312
302
  "Slack",
313
303
  "Channels"
314
304
  ],
305
+ permission: inheritedWorkAppsAuth(),
315
306
  request: {
316
307
  params: z.object({ teamId: z.string() }),
317
308
  query: z.object({
@@ -385,7 +376,7 @@ app.openapi(createRoute({
385
376
  return c.json({ error: "Failed to list channels" }, 500);
386
377
  }
387
378
  });
388
- app.openapi(createRoute({
379
+ app.openapi(createProtectedRoute({
389
380
  method: "get",
390
381
  path: "/{teamId}/channels/{channelId}/settings",
391
382
  summary: "Get Channel Settings",
@@ -396,6 +387,7 @@ app.openapi(createRoute({
396
387
  "Slack",
397
388
  "Channels"
398
389
  ],
390
+ permission: inheritedWorkAppsAuth(),
399
391
  request: { params: z.object({
400
392
  teamId: z.string(),
401
393
  channelId: z.string()
@@ -428,7 +420,7 @@ app.openapi(createRoute({
428
420
  } : void 0
429
421
  });
430
422
  });
431
- app.openapi(createRoute({
423
+ app.openapi(createProtectedRoute({
432
424
  method: "put",
433
425
  path: "/{teamId}/channels/{channelId}/settings",
434
426
  summary: "Set Channel Default Agent",
@@ -439,6 +431,7 @@ app.openapi(createRoute({
439
431
  "Slack",
440
432
  "Channels"
441
433
  ],
434
+ permission: requireChannelMemberOrAdmin(),
442
435
  request: {
443
436
  params: z.object({
444
437
  teamId: z.string(),
@@ -490,11 +483,7 @@ app.openapi(createRoute({
490
483
  configId: config.id
491
484
  });
492
485
  });
493
- app.use("/:teamId/channels/bulk", async (c, next) => {
494
- if (c.req.method === "PUT" || c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
495
- return next();
496
- });
497
- app.openapi(createRoute({
486
+ app.openapi(createProtectedRoute({
498
487
  method: "put",
499
488
  path: "/{teamId}/channels/bulk",
500
489
  summary: "Bulk Set Channel Agents",
@@ -505,6 +494,7 @@ app.openapi(createRoute({
505
494
  "Slack",
506
495
  "Channels"
507
496
  ],
497
+ permission: requireWorkspaceAdmin(),
508
498
  request: {
509
499
  params: z.object({ teamId: z.string() }),
510
500
  body: { content: { "application/json": { schema: z.object({
@@ -591,7 +581,7 @@ app.openapi(createRoute({
591
581
  errors: errors.length > 0 ? errors : void 0
592
582
  });
593
583
  });
594
- app.openapi(createRoute({
584
+ app.openapi(createProtectedRoute({
595
585
  method: "delete",
596
586
  path: "/{teamId}/channels/bulk",
597
587
  summary: "Bulk Remove Channel Configs",
@@ -602,6 +592,7 @@ app.openapi(createRoute({
602
592
  "Slack",
603
593
  "Channels"
604
594
  ],
595
+ permission: requireWorkspaceAdmin(),
605
596
  request: {
606
597
  params: z.object({ teamId: z.string() }),
607
598
  body: { content: { "application/json": { schema: z.object({ channelIds: z.array(z.string()).min(1) }) } } }
@@ -638,7 +629,7 @@ app.openapi(createRoute({
638
629
  removed
639
630
  });
640
631
  });
641
- app.openapi(createRoute({
632
+ app.openapi(createProtectedRoute({
642
633
  method: "delete",
643
634
  path: "/{teamId}/channels/{channelId}/settings",
644
635
  summary: "Remove Channel Config",
@@ -649,6 +640,7 @@ app.openapi(createRoute({
649
640
  "Slack",
650
641
  "Channels"
651
642
  ],
643
+ permission: requireChannelMemberOrAdmin(),
652
644
  request: { params: z.object({
653
645
  teamId: z.string(),
654
646
  channelId: z.string()
@@ -673,7 +665,7 @@ app.openapi(createRoute({
673
665
  }, "Removed channel agent config");
674
666
  return c.json({ success: deleted });
675
667
  });
676
- app.openapi(createRoute({
668
+ app.openapi(createProtectedRoute({
677
669
  method: "get",
678
670
  path: "/{teamId}/users",
679
671
  summary: "List Linked Users",
@@ -684,6 +676,7 @@ app.openapi(createRoute({
684
676
  "Slack",
685
677
  "Users"
686
678
  ],
679
+ permission: inheritedWorkAppsAuth(),
687
680
  request: { params: z.object({ teamId: z.string() }) },
688
681
  responses: { 200: {
689
682
  description: "List of linked users",
@@ -723,7 +716,7 @@ app.openapi(createRoute({
723
716
  lastUsedAt: link.lastUsedAt || void 0
724
717
  })) });
725
718
  });
726
- app.openapi(createRoute({
719
+ app.openapi(createProtectedRoute({
727
720
  method: "get",
728
721
  path: "/{teamId}/health",
729
722
  summary: "Check Workspace Health",
@@ -734,6 +727,7 @@ app.openapi(createRoute({
734
727
  "Slack",
735
728
  "Workspaces"
736
729
  ],
730
+ permission: inheritedWorkAppsAuth(),
737
731
  request: { params: z.object({ teamId: z.string() }) },
738
732
  responses: {
739
733
  200: {
@@ -819,7 +813,7 @@ app.openapi(createRoute({
819
813
  });
820
814
  }
821
815
  });
822
- app.openapi(createRoute({
816
+ app.openapi(createProtectedRoute({
823
817
  method: "post",
824
818
  path: "/{teamId}/test-message",
825
819
  summary: "Send Test Message",
@@ -830,6 +824,7 @@ app.openapi(createRoute({
830
824
  "Slack",
831
825
  "Workspaces"
832
826
  ],
827
+ permission: requireWorkspaceAdmin(),
833
828
  request: {
834
829
  params: z.object({ teamId: z.string() }),
835
830
  body: { content: { "application/json": { schema: z.object({
@@ -8,9 +8,9 @@ import { AgentOption } from "../modals.js";
8
8
  * Called on every @mention and /inkeep command — caching avoids redundant DB queries.
9
9
  */
10
10
  declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
11
- id: string;
12
11
  createdAt: string;
13
12
  updatedAt: string;
13
+ id: string;
14
14
  tenantId: string;
15
15
  clientId: string;
16
16
  slackUserId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-work-apps",
3
- "version": "0.0.0-dev-20260219033751",
3
+ "version": "0.0.0-dev-20260219045007",
4
4
  "description": "First party integrations for Inkeep Agents",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -33,7 +33,7 @@
33
33
  "jose": "^6.1.0",
34
34
  "minimatch": "^10.1.1",
35
35
  "slack-block-builder": "^2.8.0",
36
- "@inkeep/agents-core": "0.0.0-dev-20260219033751"
36
+ "@inkeep/agents-core": "0.0.0-dev-20260219045007"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@hono/zod-openapi": "^1.1.5",