@lobu/gateway 3.0.8 → 3.0.12

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 (219) hide show
  1. package/dist/api/platform.d.ts.map +1 -1
  2. package/dist/api/platform.js +8 -26
  3. package/dist/api/platform.js.map +1 -1
  4. package/dist/auth/mcp/proxy.d.ts +14 -0
  5. package/dist/auth/mcp/proxy.d.ts.map +1 -1
  6. package/dist/auth/mcp/proxy.js +149 -13
  7. package/dist/auth/mcp/proxy.js.map +1 -1
  8. package/dist/cli/gateway.d.ts.map +1 -1
  9. package/dist/cli/gateway.js +29 -0
  10. package/dist/cli/gateway.js.map +1 -1
  11. package/dist/cli/index.js +2 -2
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/connections/chat-instance-manager.d.ts.map +1 -1
  14. package/dist/connections/chat-instance-manager.js +2 -1
  15. package/dist/connections/chat-instance-manager.js.map +1 -1
  16. package/dist/connections/interaction-bridge.d.ts +9 -2
  17. package/dist/connections/interaction-bridge.d.ts.map +1 -1
  18. package/dist/connections/interaction-bridge.js +132 -230
  19. package/dist/connections/interaction-bridge.js.map +1 -1
  20. package/dist/connections/message-handler-bridge.d.ts.map +1 -1
  21. package/dist/connections/message-handler-bridge.js +44 -26
  22. package/dist/connections/message-handler-bridge.js.map +1 -1
  23. package/dist/interactions.d.ts +9 -43
  24. package/dist/interactions.d.ts.map +1 -1
  25. package/dist/interactions.js +10 -52
  26. package/dist/interactions.js.map +1 -1
  27. package/dist/orchestration/base-deployment-manager.js +7 -7
  28. package/dist/orchestration/base-deployment-manager.js.map +1 -1
  29. package/dist/platform/unified-thread-consumer.d.ts.map +1 -1
  30. package/dist/platform/unified-thread-consumer.js +38 -34
  31. package/dist/platform/unified-thread-consumer.js.map +1 -1
  32. package/dist/routes/public/agent.d.ts +4 -0
  33. package/dist/routes/public/agent.d.ts.map +1 -1
  34. package/dist/routes/public/agent.js +21 -0
  35. package/dist/routes/public/agent.js.map +1 -1
  36. package/dist/services/core-services.d.ts.map +1 -1
  37. package/dist/services/core-services.js +4 -0
  38. package/dist/services/core-services.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/__tests__/agent-config-routes.test.ts +0 -254
  41. package/src/__tests__/agent-history-routes.test.ts +0 -72
  42. package/src/__tests__/agent-routes.test.ts +0 -68
  43. package/src/__tests__/agent-schedules-routes.test.ts +0 -59
  44. package/src/__tests__/agent-settings-store.test.ts +0 -323
  45. package/src/__tests__/bedrock-model-catalog.test.ts +0 -40
  46. package/src/__tests__/bedrock-openai-service.test.ts +0 -157
  47. package/src/__tests__/bedrock-provider-module.test.ts +0 -56
  48. package/src/__tests__/chat-instance-manager-slack.test.ts +0 -204
  49. package/src/__tests__/chat-response-bridge.test.ts +0 -131
  50. package/src/__tests__/config-memory-plugins.test.ts +0 -92
  51. package/src/__tests__/config-request-store.test.ts +0 -127
  52. package/src/__tests__/connection-routes.test.ts +0 -144
  53. package/src/__tests__/core-services-store-selection.test.ts +0 -92
  54. package/src/__tests__/docker-deployment.test.ts +0 -1211
  55. package/src/__tests__/embedded-deployment.test.ts +0 -342
  56. package/src/__tests__/grant-store.test.ts +0 -148
  57. package/src/__tests__/http-proxy.test.ts +0 -281
  58. package/src/__tests__/instruction-service.test.ts +0 -37
  59. package/src/__tests__/link-buttons.test.ts +0 -112
  60. package/src/__tests__/lobu.test.ts +0 -32
  61. package/src/__tests__/mcp-config-service.test.ts +0 -347
  62. package/src/__tests__/mcp-proxy.test.ts +0 -694
  63. package/src/__tests__/message-handler-bridge.test.ts +0 -17
  64. package/src/__tests__/model-selection.test.ts +0 -172
  65. package/src/__tests__/oauth-templates.test.ts +0 -39
  66. package/src/__tests__/platform-adapter-slack-send.test.ts +0 -114
  67. package/src/__tests__/platform-helpers-model-resolution.test.ts +0 -253
  68. package/src/__tests__/provider-inheritance.test.ts +0 -212
  69. package/src/__tests__/routes/cli-auth.test.ts +0 -337
  70. package/src/__tests__/routes/interactions.test.ts +0 -121
  71. package/src/__tests__/secret-proxy.test.ts +0 -85
  72. package/src/__tests__/session-manager.test.ts +0 -572
  73. package/src/__tests__/setup.ts +0 -133
  74. package/src/__tests__/skill-and-mcp-registry.test.ts +0 -203
  75. package/src/__tests__/slack-routes.test.ts +0 -161
  76. package/src/__tests__/system-config-resolver.test.ts +0 -75
  77. package/src/__tests__/system-message-limiter.test.ts +0 -89
  78. package/src/__tests__/system-skills-service.test.ts +0 -362
  79. package/src/__tests__/transcription-service.test.ts +0 -222
  80. package/src/__tests__/utils/rate-limiter.test.ts +0 -102
  81. package/src/__tests__/worker-connection-manager.test.ts +0 -497
  82. package/src/__tests__/worker-job-router.test.ts +0 -722
  83. package/src/api/index.ts +0 -1
  84. package/src/api/platform.ts +0 -292
  85. package/src/api/response-renderer.ts +0 -157
  86. package/src/auth/agent-metadata-store.ts +0 -168
  87. package/src/auth/api-auth-middleware.ts +0 -69
  88. package/src/auth/api-key-provider-module.ts +0 -213
  89. package/src/auth/base-provider-module.ts +0 -201
  90. package/src/auth/bedrock/provider-module.ts +0 -110
  91. package/src/auth/chatgpt/chatgpt-oauth-module.ts +0 -185
  92. package/src/auth/chatgpt/device-code-client.ts +0 -218
  93. package/src/auth/chatgpt/index.ts +0 -1
  94. package/src/auth/claude/oauth-module.ts +0 -280
  95. package/src/auth/cli/token-service.ts +0 -249
  96. package/src/auth/external/client.ts +0 -560
  97. package/src/auth/external/device-code-client.ts +0 -235
  98. package/src/auth/mcp/config-service.ts +0 -420
  99. package/src/auth/mcp/proxy.ts +0 -1086
  100. package/src/auth/mcp/string-substitution.ts +0 -17
  101. package/src/auth/mcp/tool-cache.ts +0 -90
  102. package/src/auth/oauth/base-client.ts +0 -267
  103. package/src/auth/oauth/client.ts +0 -153
  104. package/src/auth/oauth/credentials.ts +0 -7
  105. package/src/auth/oauth/providers.ts +0 -69
  106. package/src/auth/oauth/state-store.ts +0 -150
  107. package/src/auth/oauth-templates.ts +0 -179
  108. package/src/auth/provider-catalog.ts +0 -220
  109. package/src/auth/provider-model-options.ts +0 -41
  110. package/src/auth/settings/agent-settings-store.ts +0 -565
  111. package/src/auth/settings/auth-profiles-manager.ts +0 -216
  112. package/src/auth/settings/index.ts +0 -12
  113. package/src/auth/settings/model-preference-store.ts +0 -52
  114. package/src/auth/settings/model-selection.ts +0 -135
  115. package/src/auth/settings/resolved-settings-view.ts +0 -298
  116. package/src/auth/settings/template-utils.ts +0 -44
  117. package/src/auth/settings/token-service.ts +0 -88
  118. package/src/auth/system-env-store.ts +0 -98
  119. package/src/auth/user-agents-store.ts +0 -68
  120. package/src/channels/binding-service.ts +0 -214
  121. package/src/channels/index.ts +0 -4
  122. package/src/cli/gateway.ts +0 -1312
  123. package/src/cli/index.ts +0 -74
  124. package/src/commands/built-in-commands.ts +0 -80
  125. package/src/commands/command-dispatcher.ts +0 -94
  126. package/src/commands/command-reply-adapters.ts +0 -27
  127. package/src/config/file-loader.ts +0 -618
  128. package/src/config/index.ts +0 -588
  129. package/src/config/network-allowlist.ts +0 -71
  130. package/src/connections/chat-instance-manager.ts +0 -1284
  131. package/src/connections/chat-response-bridge.ts +0 -618
  132. package/src/connections/index.ts +0 -7
  133. package/src/connections/interaction-bridge.ts +0 -831
  134. package/src/connections/message-handler-bridge.ts +0 -415
  135. package/src/connections/platform-auth-methods.ts +0 -15
  136. package/src/connections/types.ts +0 -84
  137. package/src/gateway/connection-manager.ts +0 -291
  138. package/src/gateway/index.ts +0 -698
  139. package/src/gateway/job-router.ts +0 -201
  140. package/src/gateway-main.ts +0 -200
  141. package/src/index.ts +0 -41
  142. package/src/infrastructure/queue/index.ts +0 -12
  143. package/src/infrastructure/queue/queue-producer.ts +0 -148
  144. package/src/infrastructure/queue/redis-queue.ts +0 -361
  145. package/src/infrastructure/queue/types.ts +0 -133
  146. package/src/infrastructure/redis/system-message-limiter.ts +0 -94
  147. package/src/interactions/config-request-store.ts +0 -198
  148. package/src/interactions.ts +0 -363
  149. package/src/lobu.ts +0 -311
  150. package/src/metrics/prometheus.ts +0 -159
  151. package/src/modules/module-system.ts +0 -179
  152. package/src/orchestration/base-deployment-manager.ts +0 -900
  153. package/src/orchestration/deployment-utils.ts +0 -98
  154. package/src/orchestration/impl/docker-deployment.ts +0 -620
  155. package/src/orchestration/impl/embedded-deployment.ts +0 -268
  156. package/src/orchestration/impl/index.ts +0 -8
  157. package/src/orchestration/impl/k8s/deployment.ts +0 -1061
  158. package/src/orchestration/impl/k8s/helpers.ts +0 -610
  159. package/src/orchestration/impl/k8s/index.ts +0 -1
  160. package/src/orchestration/index.ts +0 -333
  161. package/src/orchestration/message-consumer.ts +0 -584
  162. package/src/orchestration/scheduled-wakeup.ts +0 -704
  163. package/src/permissions/approval-policy.ts +0 -36
  164. package/src/permissions/grant-store.ts +0 -219
  165. package/src/platform/file-handler.ts +0 -66
  166. package/src/platform/link-buttons.ts +0 -57
  167. package/src/platform/renderer-utils.ts +0 -44
  168. package/src/platform/response-renderer.ts +0 -84
  169. package/src/platform/unified-thread-consumer.ts +0 -187
  170. package/src/platform.ts +0 -318
  171. package/src/proxy/http-proxy.ts +0 -752
  172. package/src/proxy/proxy-manager.ts +0 -81
  173. package/src/proxy/secret-proxy.ts +0 -402
  174. package/src/proxy/token-refresh-job.ts +0 -143
  175. package/src/routes/internal/audio.ts +0 -141
  176. package/src/routes/internal/device-auth.ts +0 -652
  177. package/src/routes/internal/files.ts +0 -226
  178. package/src/routes/internal/history.ts +0 -69
  179. package/src/routes/internal/images.ts +0 -127
  180. package/src/routes/internal/interactions.ts +0 -84
  181. package/src/routes/internal/middleware.ts +0 -23
  182. package/src/routes/internal/schedule.ts +0 -226
  183. package/src/routes/internal/types.ts +0 -22
  184. package/src/routes/openapi-auto.ts +0 -239
  185. package/src/routes/public/agent-access.ts +0 -23
  186. package/src/routes/public/agent-config.ts +0 -675
  187. package/src/routes/public/agent-history.ts +0 -422
  188. package/src/routes/public/agent-schedules.ts +0 -296
  189. package/src/routes/public/agent.ts +0 -1086
  190. package/src/routes/public/agents.ts +0 -373
  191. package/src/routes/public/channels.ts +0 -191
  192. package/src/routes/public/cli-auth.ts +0 -896
  193. package/src/routes/public/connections.ts +0 -574
  194. package/src/routes/public/landing.ts +0 -16
  195. package/src/routes/public/oauth.ts +0 -147
  196. package/src/routes/public/settings-auth.ts +0 -104
  197. package/src/routes/public/slack.ts +0 -173
  198. package/src/routes/shared/agent-ownership.ts +0 -101
  199. package/src/routes/shared/token-verifier.ts +0 -34
  200. package/src/services/bedrock-model-catalog.ts +0 -217
  201. package/src/services/bedrock-openai-service.ts +0 -658
  202. package/src/services/core-services.ts +0 -1072
  203. package/src/services/image-generation-service.ts +0 -257
  204. package/src/services/instruction-service.ts +0 -318
  205. package/src/services/mcp-registry.ts +0 -94
  206. package/src/services/platform-helpers.ts +0 -287
  207. package/src/services/session-manager.ts +0 -262
  208. package/src/services/settings-resolver.ts +0 -74
  209. package/src/services/system-config-resolver.ts +0 -89
  210. package/src/services/system-skills-service.ts +0 -229
  211. package/src/services/transcription-service.ts +0 -684
  212. package/src/session.ts +0 -110
  213. package/src/spaces/index.ts +0 -1
  214. package/src/spaces/space-resolver.ts +0 -17
  215. package/src/stores/in-memory-agent-store.ts +0 -403
  216. package/src/stores/redis-agent-store.ts +0 -279
  217. package/src/utils/public-url.ts +0 -44
  218. package/src/utils/rate-limiter.ts +0 -94
  219. package/tsconfig.json +0 -33
package/src/session.ts DELETED
@@ -1,110 +0,0 @@
1
- import type { AgentMcpConfig, NetworkConfig, NixConfig } from "@lobu/core";
2
-
3
- /**
4
- * Platform-agnostic session types and utilities
5
- * These types are used by all chat platforms for session tracking
6
- */
7
-
8
- // ============================================================================
9
- // Types
10
- // ============================================================================
11
-
12
- /**
13
- * Thread session data structure
14
- * Tracks the state of a conversation thread across any platform
15
- */
16
- export interface ThreadSession {
17
- conversationId: string; // Primary identifier (agentId for API platform)
18
- channelId: string;
19
- userId: string;
20
- threadCreator?: string; // Track the original thread creator
21
- jobName?: string;
22
- lastActivity: number;
23
- createdAt: number;
24
- botResponseId?: string; // Bot's response message ID for updates
25
- turnCount?: number; // Track conversation turns to prevent infinite loops
26
- status?: string; // Session status (created, active, completed, error)
27
- // API session parameters
28
- workingDirectory?: string;
29
- provider?: string;
30
- /** Model to use for the agent (e.g., claude-sonnet-4-20250514) */
31
- model?: string;
32
- /** Per-agent network configuration for sandbox isolation */
33
- networkConfig?: NetworkConfig;
34
- /** Per-agent MCP configuration (additive to global MCPs) */
35
- mcpConfig?: AgentMcpConfig;
36
- /** Nix environment configuration for agent workspace */
37
- nixConfig?: NixConfig;
38
- /** Original agent ID (before composite session key generation) */
39
- agentId?: string;
40
- /** Process without persisting history */
41
- dryRun?: boolean;
42
- }
43
-
44
- /**
45
- * Compute session key for Redis storage
46
- * For API platform: just conversationId (which equals agentId)
47
- * For Slack/WhatsApp: channelId:conversationId
48
- */
49
- export function computeSessionKey(session: {
50
- channelId: string;
51
- conversationId: string;
52
- }): string {
53
- // For API platform, channelId starts with "api-" or "api_" and we just use conversationId
54
- if (
55
- session.channelId.startsWith("api-") ||
56
- session.channelId.startsWith("api_") ||
57
- session.channelId === session.conversationId
58
- ) {
59
- return session.conversationId;
60
- }
61
- // For other platforms, use channelId:conversationId
62
- return `${session.channelId}:${session.conversationId}`;
63
- }
64
-
65
- /**
66
- * Session store interface
67
- * Platform adapters use this to store and retrieve session data
68
- */
69
- export interface SessionStore {
70
- get(sessionKey: string): Promise<ThreadSession | null>;
71
- set(sessionKey: string, session: ThreadSession): Promise<void>;
72
- delete(sessionKey: string): Promise<void>;
73
- getByThread(
74
- channelId: string,
75
- threadTs: string
76
- ): Promise<ThreadSession | null>;
77
- /** Optional cleanup - not needed for Redis TTL-based stores */
78
- cleanup?(ttl: number): Promise<number>;
79
- }
80
-
81
- /**
82
- * Session manager interface
83
- * Provides high-level session management operations
84
- */
85
- export interface ISessionManager {
86
- createSession(
87
- channelId: string,
88
- userId: string,
89
- conversationId?: string,
90
- threadCreator?: string
91
- ): Promise<ThreadSession>;
92
- getSession(sessionKey: string): Promise<ThreadSession | null>;
93
- findSessionByThread(
94
- channelId: string,
95
- threadTs: string
96
- ): Promise<ThreadSession | null>;
97
- updateSession(
98
- sessionKey: string,
99
- updates: Partial<ThreadSession>
100
- ): Promise<void>;
101
- setSession(session: ThreadSession): Promise<void>;
102
- deleteSession(sessionKey: string): Promise<void>;
103
- validateThreadOwnership(
104
- channelId: string,
105
- threadTs: string,
106
- userId: string
107
- ): Promise<{ allowed: boolean; owner?: string }>;
108
- touchSession(sessionKey: string): Promise<void>;
109
- cleanupExpired(ttl: number): Promise<number>;
110
- }
@@ -1 +0,0 @@
1
- export * from "./space-resolver";
@@ -1,17 +0,0 @@
1
- /**
2
- * Generate a deterministic, readable agent ID from platform identity.
3
- * One-to-one mapping: each user/chat gets exactly one agent.
4
- *
5
- * Format:
6
- * - DM: {platform}-{userId} (e.g., telegram-6570514069, slack-U12345)
7
- * - Group: {platform}-g-{chatId} (e.g., telegram-g--1001234567, slack-g-C12345)
8
- */
9
- export function platformAgentId(
10
- platform: string,
11
- userId: string,
12
- chatId: string,
13
- isGroup: boolean
14
- ): string {
15
- if (isGroup) return `${platform}-g-${chatId}`;
16
- return `${platform}-${userId}`;
17
- }
@@ -1,403 +0,0 @@
1
- /**
2
- * InMemoryAgentStore — default AgentStore backed by in-memory Maps.
3
- *
4
- * Populated from files (dev mode) or via API (embedded mode).
5
- */
6
-
7
- import type {
8
- AgentMetadata,
9
- AgentSettings,
10
- AgentStore,
11
- ChannelBinding,
12
- Grant,
13
- StoredConnection,
14
- } from "@lobu/core";
15
-
16
- export class InMemoryAgentStore implements AgentStore {
17
- private settings = new Map<string, AgentSettings>();
18
- private metadata = new Map<string, AgentMetadata>();
19
- private connections = new Map<string, StoredConnection>();
20
- private connectionsAll = new Set<string>();
21
- private connectionsByAgent = new Map<string, Set<string>>();
22
- private channelBindings = new Map<string, ChannelBinding>();
23
- private channelBindingIndex = new Map<string, Set<string>>();
24
- private grants = new Map<
25
- string,
26
- { expiresAt: number | null; grantedAt: number; denied?: boolean }
27
- >();
28
- private userAgents = new Map<string, Set<string>>();
29
- private sandboxes = new Map<string, Set<string>>();
30
-
31
- // ── Agent Settings ──────────────────────────────────────────────────
32
-
33
- async getSettings(agentId: string): Promise<AgentSettings | null> {
34
- return this.settings.get(agentId) ?? null;
35
- }
36
-
37
- async saveSettings(agentId: string, settings: AgentSettings): Promise<void> {
38
- this.settings.set(agentId, { ...settings, updatedAt: Date.now() });
39
- }
40
-
41
- async updateSettings(
42
- agentId: string,
43
- updates: Partial<AgentSettings>
44
- ): Promise<void> {
45
- const existing = this.settings.get(agentId);
46
- this.settings.set(agentId, {
47
- ...(existing || {}),
48
- ...updates,
49
- updatedAt: Date.now(),
50
- } as AgentSettings);
51
- }
52
-
53
- async deleteSettings(agentId: string): Promise<void> {
54
- this.settings.delete(agentId);
55
- }
56
-
57
- async hasSettings(agentId: string): Promise<boolean> {
58
- return this.settings.has(agentId);
59
- }
60
-
61
- // ── Agent Metadata ────────────────────────────────────────────────
62
-
63
- async getMetadata(agentId: string): Promise<AgentMetadata | null> {
64
- return this.metadata.get(agentId) ?? null;
65
- }
66
-
67
- async saveMetadata(agentId: string, metadata: AgentMetadata): Promise<void> {
68
- this.metadata.set(agentId, metadata);
69
- if (metadata.parentConnectionId) {
70
- let set = this.sandboxes.get(metadata.parentConnectionId);
71
- if (!set) {
72
- set = new Set();
73
- this.sandboxes.set(metadata.parentConnectionId, set);
74
- }
75
- set.add(agentId);
76
- }
77
- }
78
-
79
- async updateMetadata(
80
- agentId: string,
81
- updates: Partial<AgentMetadata>
82
- ): Promise<void> {
83
- const existing = this.metadata.get(agentId);
84
- if (!existing) return;
85
- await this.saveMetadata(agentId, { ...existing, ...updates });
86
- }
87
-
88
- async deleteMetadata(agentId: string): Promise<void> {
89
- const existing = this.metadata.get(agentId);
90
- this.metadata.delete(agentId);
91
- if (existing?.parentConnectionId) {
92
- const set = this.sandboxes.get(existing.parentConnectionId);
93
- if (set) {
94
- set.delete(agentId);
95
- if (set.size === 0) this.sandboxes.delete(existing.parentConnectionId);
96
- }
97
- }
98
- }
99
-
100
- async hasAgent(agentId: string): Promise<boolean> {
101
- return this.metadata.has(agentId);
102
- }
103
-
104
- async listAgents(): Promise<AgentMetadata[]> {
105
- return Array.from(this.metadata.values());
106
- }
107
-
108
- async listSandboxes(connectionId: string): Promise<AgentMetadata[]> {
109
- const ids = this.sandboxes.get(connectionId);
110
- if (!ids) return [];
111
- const results: AgentMetadata[] = [];
112
- for (const id of ids) {
113
- const m = this.metadata.get(id);
114
- if (m) results.push(m);
115
- }
116
- return results;
117
- }
118
-
119
- // ── Connections ──────────────────────────────────────────────────
120
-
121
- async getConnection(connectionId: string): Promise<StoredConnection | null> {
122
- return this.connections.get(connectionId) ?? null;
123
- }
124
-
125
- async listConnections(filter?: {
126
- templateAgentId?: string;
127
- platform?: string;
128
- }): Promise<StoredConnection[]> {
129
- let ids: Iterable<string>;
130
- if (filter?.templateAgentId) {
131
- ids = this.connectionsByAgent.get(filter.templateAgentId) ?? [];
132
- } else {
133
- ids = this.connectionsAll;
134
- }
135
-
136
- let connections: StoredConnection[] = [];
137
- for (const id of ids) {
138
- const conn = this.connections.get(id);
139
- if (conn) connections.push(conn);
140
- }
141
-
142
- if (filter?.platform) {
143
- connections = connections.filter((c) => c.platform === filter.platform);
144
- }
145
- return connections;
146
- }
147
-
148
- async saveConnection(connection: StoredConnection): Promise<void> {
149
- this.connections.set(connection.id, connection);
150
- this.connectionsAll.add(connection.id);
151
- if (connection.templateAgentId) {
152
- let set = this.connectionsByAgent.get(connection.templateAgentId);
153
- if (!set) {
154
- set = new Set();
155
- this.connectionsByAgent.set(connection.templateAgentId, set);
156
- }
157
- set.add(connection.id);
158
- }
159
- }
160
-
161
- async updateConnection(
162
- connectionId: string,
163
- updates: Partial<StoredConnection>
164
- ): Promise<void> {
165
- const existing = this.connections.get(connectionId);
166
- if (!existing) return;
167
- await this.saveConnection({
168
- ...existing,
169
- ...updates,
170
- id: connectionId,
171
- updatedAt: Date.now(),
172
- });
173
- }
174
-
175
- async deleteConnection(connectionId: string): Promise<void> {
176
- const conn = this.connections.get(connectionId);
177
- this.connections.delete(connectionId);
178
- this.connectionsAll.delete(connectionId);
179
- if (conn?.templateAgentId) {
180
- const set = this.connectionsByAgent.get(conn.templateAgentId);
181
- if (set) {
182
- set.delete(connectionId);
183
- if (set.size === 0)
184
- this.connectionsByAgent.delete(conn.templateAgentId);
185
- }
186
- }
187
- }
188
-
189
- // ── Grants ──────────────────────────────────────────────────────
190
-
191
- private grantKey(agentId: string, pattern: string): string {
192
- return `${agentId}:${pattern}`;
193
- }
194
-
195
- private getValidGrant(
196
- agentId: string,
197
- pattern: string
198
- ): { expiresAt: number | null; grantedAt: number; denied?: boolean } | null {
199
- const key = this.grantKey(agentId, pattern);
200
- const entry = this.grants.get(key);
201
- if (!entry) return null;
202
- if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
203
- this.grants.delete(key);
204
- return null;
205
- }
206
- return entry;
207
- }
208
-
209
- async grant(
210
- agentId: string,
211
- pattern: string,
212
- expiresAt: number | null,
213
- denied?: boolean
214
- ): Promise<void> {
215
- this.grants.set(this.grantKey(agentId, pattern), {
216
- expiresAt,
217
- grantedAt: Date.now(),
218
- ...(denied && { denied: true }),
219
- });
220
- }
221
-
222
- async hasGrant(agentId: string, pattern: string): Promise<boolean> {
223
- // Exact match
224
- const exact = this.getValidGrant(agentId, pattern);
225
- if (exact) return !exact.denied;
226
-
227
- // MCP wildcard: /mcp/gmail/tools/send_email -> /mcp/gmail/tools/*
228
- if (pattern.startsWith("/mcp/")) {
229
- const lastSlash = pattern.lastIndexOf("/");
230
- if (lastSlash > 0) {
231
- const wildcard = `${pattern.substring(0, lastSlash)}/*`;
232
- const entry = this.getValidGrant(agentId, wildcard);
233
- if (entry) return !entry.denied;
234
- }
235
- }
236
-
237
- // Domain wildcard: sub.example.com -> *.example.com
238
- if (!pattern.startsWith("/")) {
239
- const parts = pattern.split(".");
240
- if (parts.length > 2) {
241
- const wildcard = `*.${parts.slice(1).join(".")}`;
242
- const entry = this.getValidGrant(agentId, wildcard);
243
- if (entry) return !entry.denied;
244
- }
245
- }
246
-
247
- return false;
248
- }
249
-
250
- async isDenied(agentId: string, pattern: string): Promise<boolean> {
251
- const entry = this.getValidGrant(agentId, pattern);
252
- if (!entry) return false;
253
- return entry.denied === true;
254
- }
255
-
256
- async listGrants(agentId: string): Promise<Grant[]> {
257
- const prefix = `${agentId}:`;
258
- const grants: Grant[] = [];
259
- for (const [key, entry] of this.grants) {
260
- if (!key.startsWith(prefix)) continue;
261
- if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
262
- this.grants.delete(key);
263
- continue;
264
- }
265
- grants.push({
266
- pattern: key.substring(prefix.length),
267
- expiresAt: entry.expiresAt,
268
- grantedAt: entry.grantedAt,
269
- ...(entry.denied && { denied: true }),
270
- });
271
- }
272
- return grants;
273
- }
274
-
275
- async revokeGrant(agentId: string, pattern: string): Promise<void> {
276
- this.grants.delete(this.grantKey(agentId, pattern));
277
- }
278
-
279
- // ── User-Agent Associations ─────────────────────────────────────
280
-
281
- private userKey(platform: string, userId: string): string {
282
- return `${platform}:${userId}`;
283
- }
284
-
285
- async addUserAgent(
286
- platform: string,
287
- userId: string,
288
- agentId: string
289
- ): Promise<void> {
290
- const key = this.userKey(platform, userId);
291
- let set = this.userAgents.get(key);
292
- if (!set) {
293
- set = new Set();
294
- this.userAgents.set(key, set);
295
- }
296
- set.add(agentId);
297
- }
298
-
299
- async removeUserAgent(
300
- platform: string,
301
- userId: string,
302
- agentId: string
303
- ): Promise<void> {
304
- const key = this.userKey(platform, userId);
305
- const set = this.userAgents.get(key);
306
- if (set) {
307
- set.delete(agentId);
308
- if (set.size === 0) this.userAgents.delete(key);
309
- }
310
- }
311
-
312
- async listUserAgents(platform: string, userId: string): Promise<string[]> {
313
- const set = this.userAgents.get(this.userKey(platform, userId));
314
- return set ? Array.from(set) : [];
315
- }
316
-
317
- async ownsAgent(
318
- platform: string,
319
- userId: string,
320
- agentId: string
321
- ): Promise<boolean> {
322
- const set = this.userAgents.get(this.userKey(platform, userId));
323
- return set ? set.has(agentId) : false;
324
- }
325
-
326
- // ── Channel Bindings ────────────────────────────────────────────
327
-
328
- private channelBindingKey(
329
- platform: string,
330
- channelId: string,
331
- teamId?: string
332
- ): string {
333
- return teamId
334
- ? `${platform}:${channelId}:${teamId}`
335
- : `${platform}:${channelId}`;
336
- }
337
-
338
- async getChannelBinding(
339
- platform: string,
340
- channelId: string,
341
- teamId?: string
342
- ): Promise<ChannelBinding | null> {
343
- return (
344
- this.channelBindings.get(
345
- this.channelBindingKey(platform, channelId, teamId)
346
- ) ?? null
347
- );
348
- }
349
-
350
- async createChannelBinding(binding: ChannelBinding): Promise<void> {
351
- const key = this.channelBindingKey(
352
- binding.platform,
353
- binding.channelId,
354
- binding.teamId
355
- );
356
- this.channelBindings.set(key, binding);
357
- let set = this.channelBindingIndex.get(binding.agentId);
358
- if (!set) {
359
- set = new Set();
360
- this.channelBindingIndex.set(binding.agentId, set);
361
- }
362
- set.add(key);
363
- }
364
-
365
- async deleteChannelBinding(
366
- platform: string,
367
- channelId: string,
368
- teamId?: string
369
- ): Promise<void> {
370
- const key = this.channelBindingKey(platform, channelId, teamId);
371
- const binding = this.channelBindings.get(key);
372
- if (binding) {
373
- const set = this.channelBindingIndex.get(binding.agentId);
374
- if (set) {
375
- set.delete(key);
376
- if (set.size === 0) this.channelBindingIndex.delete(binding.agentId);
377
- }
378
- }
379
- this.channelBindings.delete(key);
380
- }
381
-
382
- async listChannelBindings(agentId: string): Promise<ChannelBinding[]> {
383
- const keys = this.channelBindingIndex.get(agentId);
384
- if (!keys) return [];
385
- const bindings: ChannelBinding[] = [];
386
- for (const key of keys) {
387
- const binding = this.channelBindings.get(key);
388
- if (binding) bindings.push(binding);
389
- }
390
- return bindings;
391
- }
392
-
393
- async deleteAllChannelBindings(agentId: string): Promise<number> {
394
- const keys = this.channelBindingIndex.get(agentId);
395
- if (!keys || keys.size === 0) return 0;
396
- const count = keys.size;
397
- for (const key of keys) {
398
- this.channelBindings.delete(key);
399
- }
400
- this.channelBindingIndex.delete(agentId);
401
- return count;
402
- }
403
- }