@lobu/gateway 3.0.9 → 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.
- package/dist/api/platform.d.ts.map +1 -1
- package/dist/api/platform.js +7 -26
- package/dist/api/platform.js.map +1 -1
- package/dist/auth/mcp/proxy.d.ts +14 -0
- package/dist/auth/mcp/proxy.d.ts.map +1 -1
- package/dist/auth/mcp/proxy.js +149 -13
- package/dist/auth/mcp/proxy.js.map +1 -1
- package/dist/cli/gateway.d.ts.map +1 -1
- package/dist/cli/gateway.js +29 -0
- package/dist/cli/gateway.js.map +1 -1
- package/dist/connections/chat-instance-manager.d.ts.map +1 -1
- package/dist/connections/chat-instance-manager.js +2 -1
- package/dist/connections/chat-instance-manager.js.map +1 -1
- package/dist/connections/interaction-bridge.d.ts +9 -2
- package/dist/connections/interaction-bridge.d.ts.map +1 -1
- package/dist/connections/interaction-bridge.js +121 -261
- package/dist/connections/interaction-bridge.js.map +1 -1
- package/dist/interactions.d.ts +9 -43
- package/dist/interactions.d.ts.map +1 -1
- package/dist/interactions.js +10 -52
- package/dist/interactions.js.map +1 -1
- package/dist/routes/public/agent.d.ts +4 -0
- package/dist/routes/public/agent.d.ts.map +1 -1
- package/dist/routes/public/agent.js +21 -0
- package/dist/routes/public/agent.js.map +1 -1
- package/dist/services/core-services.d.ts.map +1 -1
- package/dist/services/core-services.js +4 -0
- package/dist/services/core-services.js.map +1 -1
- package/package.json +9 -9
- package/src/__tests__/agent-config-routes.test.ts +0 -254
- package/src/__tests__/agent-history-routes.test.ts +0 -72
- package/src/__tests__/agent-routes.test.ts +0 -68
- package/src/__tests__/agent-schedules-routes.test.ts +0 -59
- package/src/__tests__/agent-settings-store.test.ts +0 -323
- package/src/__tests__/bedrock-model-catalog.test.ts +0 -40
- package/src/__tests__/bedrock-openai-service.test.ts +0 -157
- package/src/__tests__/bedrock-provider-module.test.ts +0 -56
- package/src/__tests__/chat-instance-manager-slack.test.ts +0 -204
- package/src/__tests__/chat-response-bridge.test.ts +0 -131
- package/src/__tests__/config-memory-plugins.test.ts +0 -92
- package/src/__tests__/config-request-store.test.ts +0 -127
- package/src/__tests__/connection-routes.test.ts +0 -144
- package/src/__tests__/core-services-store-selection.test.ts +0 -92
- package/src/__tests__/docker-deployment.test.ts +0 -1211
- package/src/__tests__/embedded-deployment.test.ts +0 -342
- package/src/__tests__/grant-store.test.ts +0 -148
- package/src/__tests__/http-proxy.test.ts +0 -281
- package/src/__tests__/instruction-service.test.ts +0 -37
- package/src/__tests__/link-buttons.test.ts +0 -112
- package/src/__tests__/lobu.test.ts +0 -32
- package/src/__tests__/mcp-config-service.test.ts +0 -347
- package/src/__tests__/mcp-proxy.test.ts +0 -694
- package/src/__tests__/message-handler-bridge.test.ts +0 -17
- package/src/__tests__/model-selection.test.ts +0 -172
- package/src/__tests__/oauth-templates.test.ts +0 -39
- package/src/__tests__/platform-adapter-slack-send.test.ts +0 -114
- package/src/__tests__/platform-helpers-model-resolution.test.ts +0 -253
- package/src/__tests__/provider-inheritance.test.ts +0 -212
- package/src/__tests__/routes/cli-auth.test.ts +0 -337
- package/src/__tests__/routes/interactions.test.ts +0 -121
- package/src/__tests__/secret-proxy.test.ts +0 -85
- package/src/__tests__/session-manager.test.ts +0 -572
- package/src/__tests__/setup.ts +0 -133
- package/src/__tests__/skill-and-mcp-registry.test.ts +0 -203
- package/src/__tests__/slack-routes.test.ts +0 -161
- package/src/__tests__/system-config-resolver.test.ts +0 -75
- package/src/__tests__/system-message-limiter.test.ts +0 -89
- package/src/__tests__/system-skills-service.test.ts +0 -362
- package/src/__tests__/transcription-service.test.ts +0 -222
- package/src/__tests__/utils/rate-limiter.test.ts +0 -102
- package/src/__tests__/worker-connection-manager.test.ts +0 -497
- package/src/__tests__/worker-job-router.test.ts +0 -722
- package/src/api/index.ts +0 -1
- package/src/api/platform.ts +0 -292
- package/src/api/response-renderer.ts +0 -157
- package/src/auth/agent-metadata-store.ts +0 -168
- package/src/auth/api-auth-middleware.ts +0 -69
- package/src/auth/api-key-provider-module.ts +0 -213
- package/src/auth/base-provider-module.ts +0 -201
- package/src/auth/bedrock/provider-module.ts +0 -110
- package/src/auth/chatgpt/chatgpt-oauth-module.ts +0 -185
- package/src/auth/chatgpt/device-code-client.ts +0 -218
- package/src/auth/chatgpt/index.ts +0 -1
- package/src/auth/claude/oauth-module.ts +0 -280
- package/src/auth/cli/token-service.ts +0 -249
- package/src/auth/external/client.ts +0 -560
- package/src/auth/external/device-code-client.ts +0 -235
- package/src/auth/mcp/config-service.ts +0 -420
- package/src/auth/mcp/proxy.ts +0 -1086
- package/src/auth/mcp/string-substitution.ts +0 -17
- package/src/auth/mcp/tool-cache.ts +0 -90
- package/src/auth/oauth/base-client.ts +0 -267
- package/src/auth/oauth/client.ts +0 -153
- package/src/auth/oauth/credentials.ts +0 -7
- package/src/auth/oauth/providers.ts +0 -69
- package/src/auth/oauth/state-store.ts +0 -150
- package/src/auth/oauth-templates.ts +0 -179
- package/src/auth/provider-catalog.ts +0 -220
- package/src/auth/provider-model-options.ts +0 -41
- package/src/auth/settings/agent-settings-store.ts +0 -565
- package/src/auth/settings/auth-profiles-manager.ts +0 -216
- package/src/auth/settings/index.ts +0 -12
- package/src/auth/settings/model-preference-store.ts +0 -52
- package/src/auth/settings/model-selection.ts +0 -135
- package/src/auth/settings/resolved-settings-view.ts +0 -298
- package/src/auth/settings/template-utils.ts +0 -44
- package/src/auth/settings/token-service.ts +0 -88
- package/src/auth/system-env-store.ts +0 -98
- package/src/auth/user-agents-store.ts +0 -68
- package/src/channels/binding-service.ts +0 -214
- package/src/channels/index.ts +0 -4
- package/src/cli/gateway.ts +0 -1312
- package/src/cli/index.ts +0 -74
- package/src/commands/built-in-commands.ts +0 -80
- package/src/commands/command-dispatcher.ts +0 -94
- package/src/commands/command-reply-adapters.ts +0 -27
- package/src/config/file-loader.ts +0 -618
- package/src/config/index.ts +0 -588
- package/src/config/network-allowlist.ts +0 -71
- package/src/connections/chat-instance-manager.ts +0 -1284
- package/src/connections/chat-response-bridge.ts +0 -618
- package/src/connections/index.ts +0 -7
- package/src/connections/interaction-bridge.ts +0 -831
- package/src/connections/message-handler-bridge.ts +0 -440
- package/src/connections/platform-auth-methods.ts +0 -15
- package/src/connections/types.ts +0 -84
- package/src/gateway/connection-manager.ts +0 -291
- package/src/gateway/index.ts +0 -698
- package/src/gateway/job-router.ts +0 -201
- package/src/gateway-main.ts +0 -200
- package/src/index.ts +0 -41
- package/src/infrastructure/queue/index.ts +0 -12
- package/src/infrastructure/queue/queue-producer.ts +0 -148
- package/src/infrastructure/queue/redis-queue.ts +0 -361
- package/src/infrastructure/queue/types.ts +0 -133
- package/src/infrastructure/redis/system-message-limiter.ts +0 -94
- package/src/interactions/config-request-store.ts +0 -198
- package/src/interactions.ts +0 -363
- package/src/lobu.ts +0 -311
- package/src/metrics/prometheus.ts +0 -159
- package/src/modules/module-system.ts +0 -179
- package/src/orchestration/base-deployment-manager.ts +0 -900
- package/src/orchestration/deployment-utils.ts +0 -98
- package/src/orchestration/impl/docker-deployment.ts +0 -620
- package/src/orchestration/impl/embedded-deployment.ts +0 -268
- package/src/orchestration/impl/index.ts +0 -8
- package/src/orchestration/impl/k8s/deployment.ts +0 -1061
- package/src/orchestration/impl/k8s/helpers.ts +0 -610
- package/src/orchestration/impl/k8s/index.ts +0 -1
- package/src/orchestration/index.ts +0 -333
- package/src/orchestration/message-consumer.ts +0 -584
- package/src/orchestration/scheduled-wakeup.ts +0 -704
- package/src/permissions/approval-policy.ts +0 -36
- package/src/permissions/grant-store.ts +0 -219
- package/src/platform/file-handler.ts +0 -66
- package/src/platform/link-buttons.ts +0 -57
- package/src/platform/renderer-utils.ts +0 -44
- package/src/platform/response-renderer.ts +0 -84
- package/src/platform/unified-thread-consumer.ts +0 -194
- package/src/platform.ts +0 -318
- package/src/proxy/http-proxy.ts +0 -752
- package/src/proxy/proxy-manager.ts +0 -81
- package/src/proxy/secret-proxy.ts +0 -402
- package/src/proxy/token-refresh-job.ts +0 -143
- package/src/routes/internal/audio.ts +0 -141
- package/src/routes/internal/device-auth.ts +0 -652
- package/src/routes/internal/files.ts +0 -226
- package/src/routes/internal/history.ts +0 -69
- package/src/routes/internal/images.ts +0 -127
- package/src/routes/internal/interactions.ts +0 -84
- package/src/routes/internal/middleware.ts +0 -23
- package/src/routes/internal/schedule.ts +0 -226
- package/src/routes/internal/types.ts +0 -22
- package/src/routes/openapi-auto.ts +0 -239
- package/src/routes/public/agent-access.ts +0 -23
- package/src/routes/public/agent-config.ts +0 -675
- package/src/routes/public/agent-history.ts +0 -422
- package/src/routes/public/agent-schedules.ts +0 -296
- package/src/routes/public/agent.ts +0 -1086
- package/src/routes/public/agents.ts +0 -373
- package/src/routes/public/channels.ts +0 -191
- package/src/routes/public/cli-auth.ts +0 -896
- package/src/routes/public/connections.ts +0 -574
- package/src/routes/public/landing.ts +0 -16
- package/src/routes/public/oauth.ts +0 -147
- package/src/routes/public/settings-auth.ts +0 -104
- package/src/routes/public/slack.ts +0 -173
- package/src/routes/shared/agent-ownership.ts +0 -101
- package/src/routes/shared/token-verifier.ts +0 -34
- package/src/services/bedrock-model-catalog.ts +0 -217
- package/src/services/bedrock-openai-service.ts +0 -658
- package/src/services/core-services.ts +0 -1072
- package/src/services/image-generation-service.ts +0 -257
- package/src/services/instruction-service.ts +0 -318
- package/src/services/mcp-registry.ts +0 -94
- package/src/services/platform-helpers.ts +0 -287
- package/src/services/session-manager.ts +0 -262
- package/src/services/settings-resolver.ts +0 -74
- package/src/services/system-config-resolver.ts +0 -89
- package/src/services/system-skills-service.ts +0 -229
- package/src/services/transcription-service.ts +0 -684
- package/src/session.ts +0 -110
- package/src/spaces/index.ts +0 -1
- package/src/spaces/space-resolver.ts +0 -17
- package/src/stores/in-memory-agent-store.ts +0 -403
- package/src/stores/redis-agent-store.ts +0 -279
- package/src/utils/public-url.ts +0 -44
- package/src/utils/rate-limiter.ts +0 -94
- package/tsconfig.json +0 -33
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { AgentSettings } from "./index";
|
|
2
|
-
|
|
3
|
-
function cloneSettingValue<T>(value: T): T {
|
|
4
|
-
return JSON.parse(JSON.stringify(value)) as T;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function buildDefaultSettingsFromSource(
|
|
8
|
-
source: AgentSettings | null
|
|
9
|
-
): Omit<AgentSettings, "updatedAt"> {
|
|
10
|
-
if (!source) return {};
|
|
11
|
-
|
|
12
|
-
const defaults: Omit<AgentSettings, "updatedAt"> = {};
|
|
13
|
-
|
|
14
|
-
if (source.model !== undefined) defaults.model = source.model;
|
|
15
|
-
if (source.modelSelection)
|
|
16
|
-
defaults.modelSelection = cloneSettingValue(source.modelSelection);
|
|
17
|
-
if (source.providerModelPreferences)
|
|
18
|
-
defaults.providerModelPreferences = cloneSettingValue(
|
|
19
|
-
source.providerModelPreferences
|
|
20
|
-
);
|
|
21
|
-
if (source.networkConfig)
|
|
22
|
-
defaults.networkConfig = cloneSettingValue(source.networkConfig);
|
|
23
|
-
if (source.nixConfig)
|
|
24
|
-
defaults.nixConfig = cloneSettingValue(source.nixConfig);
|
|
25
|
-
if (source.mcpServers)
|
|
26
|
-
defaults.mcpServers = cloneSettingValue(source.mcpServers);
|
|
27
|
-
if (source.soulMd !== undefined) defaults.soulMd = source.soulMd;
|
|
28
|
-
if (source.userMd !== undefined) defaults.userMd = source.userMd;
|
|
29
|
-
if (source.identityMd !== undefined) defaults.identityMd = source.identityMd;
|
|
30
|
-
if (source.skillsConfig)
|
|
31
|
-
defaults.skillsConfig = cloneSettingValue(source.skillsConfig);
|
|
32
|
-
if (source.toolsConfig)
|
|
33
|
-
defaults.toolsConfig = cloneSettingValue(source.toolsConfig);
|
|
34
|
-
if (source.pluginsConfig)
|
|
35
|
-
defaults.pluginsConfig = cloneSettingValue(source.pluginsConfig);
|
|
36
|
-
if (source.installedProviders) {
|
|
37
|
-
defaults.installedProviders = cloneSettingValue(source.installedProviders);
|
|
38
|
-
}
|
|
39
|
-
if (source.verboseLogging !== undefined) {
|
|
40
|
-
defaults.verboseLogging = source.verboseLogging;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return defaults;
|
|
44
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pre-filled skill configuration for an agent config session
|
|
3
|
-
*/
|
|
4
|
-
export interface PrefillSkill {
|
|
5
|
-
/** Skill repository (e.g., "anthropics/skills/pdf") */
|
|
6
|
-
repo: string;
|
|
7
|
-
/** Display name */
|
|
8
|
-
name?: string;
|
|
9
|
-
/** Description */
|
|
10
|
-
description?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Pre-filled MCP server configuration for an agent config session
|
|
15
|
-
*/
|
|
16
|
-
export interface PrefillMcpServer {
|
|
17
|
-
/** MCP server ID (key in mcpServers record) */
|
|
18
|
-
id: string;
|
|
19
|
-
/** Display name/description */
|
|
20
|
-
name?: string;
|
|
21
|
-
/** Server URL (for SSE type) */
|
|
22
|
-
url?: string;
|
|
23
|
-
/** Server type */
|
|
24
|
-
type?: "sse" | "stdio";
|
|
25
|
-
/** Command (for stdio type) */
|
|
26
|
-
command?: string;
|
|
27
|
-
/** Args (for stdio type) */
|
|
28
|
-
args?: string[];
|
|
29
|
-
/** Environment variables needed (just the keys, user fills values) */
|
|
30
|
-
envVars?: string[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Source message context where settings link was requested.
|
|
35
|
-
* Used to send follow-up notifications back to the same conversation.
|
|
36
|
-
*/
|
|
37
|
-
export interface SettingsSourceContext {
|
|
38
|
-
conversationId: string;
|
|
39
|
-
channelId: string;
|
|
40
|
-
teamId?: string;
|
|
41
|
-
platform?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Unified session payload for config/auth sessions.
|
|
46
|
-
*
|
|
47
|
-
* OAuth sessions populate email/name/oauthUserId. Claimed chat sessions
|
|
48
|
-
* populate platform/channelId/userId directly.
|
|
49
|
-
*/
|
|
50
|
-
export interface SettingsTokenPayload {
|
|
51
|
-
/** Agent to configure. Optional when using channel-based entry (user picks agent on page). */
|
|
52
|
-
agentId?: string;
|
|
53
|
-
userId: string;
|
|
54
|
-
platform: string;
|
|
55
|
-
exp: number; // Expiration timestamp (ms)
|
|
56
|
-
/** Channel that triggered the settings link. Used for agent switching and binding. */
|
|
57
|
-
channelId?: string;
|
|
58
|
-
/** Team/workspace ID for multi-tenant platforms (Slack). */
|
|
59
|
-
teamId?: string;
|
|
60
|
-
/** OAuth user email (set for OAuth sessions). */
|
|
61
|
-
email?: string;
|
|
62
|
-
/** OAuth user display name (set for OAuth sessions). */
|
|
63
|
-
name?: string;
|
|
64
|
-
/** OAuth provider user ID (set for OAuth sessions). */
|
|
65
|
-
oauthUserId?: string;
|
|
66
|
-
/** Optional message to display during config/auth flows */
|
|
67
|
-
message?: string;
|
|
68
|
-
/** Optional provider IDs to associate with the flow */
|
|
69
|
-
prefillProviders?: string[];
|
|
70
|
-
/** Optional skills to pre-fill (user confirms to enable) */
|
|
71
|
-
prefillSkills?: PrefillSkill[];
|
|
72
|
-
/** Optional MCP servers to pre-fill (user confirms to enable) */
|
|
73
|
-
prefillMcpServers?: PrefillMcpServer[];
|
|
74
|
-
/** Optional Nix packages to pre-fill */
|
|
75
|
-
prefillNixPackages?: string[];
|
|
76
|
-
/** Optional domain patterns to pre-fill as grants */
|
|
77
|
-
prefillGrants?: string[];
|
|
78
|
-
/** Optional source context for post-install notifications */
|
|
79
|
-
sourceContext?: SettingsSourceContext;
|
|
80
|
-
/** Settings mode: "admin" has full access, "user" is restricted by allowedScopes */
|
|
81
|
-
settingsMode?: "admin" | "user";
|
|
82
|
-
/** Scopes the user is allowed to configure (only relevant when settingsMode is "user") */
|
|
83
|
-
allowedScopes?: string[];
|
|
84
|
-
/** Connection ID that triggered this session */
|
|
85
|
-
connectionId?: string;
|
|
86
|
-
/** Whether this session has admin access */
|
|
87
|
-
isAdmin?: boolean;
|
|
88
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { createLogger, decrypt, encrypt } from "@lobu/core";
|
|
2
|
-
import type Redis from "ioredis";
|
|
3
|
-
|
|
4
|
-
const logger = createLogger("system-env-store");
|
|
5
|
-
const KEY_PREFIX = "system:env:";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Redis-backed store for system environment variables.
|
|
9
|
-
* Maintains an in-memory cache for synchronous resolution
|
|
10
|
-
* (required by the string-substitution system).
|
|
11
|
-
*/
|
|
12
|
-
export class SystemEnvStore {
|
|
13
|
-
private redis: Redis;
|
|
14
|
-
private cache: Map<string, string> = new Map();
|
|
15
|
-
|
|
16
|
-
constructor(redis: Redis) {
|
|
17
|
-
this.redis = redis;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async get(key: string): Promise<string | null> {
|
|
21
|
-
try {
|
|
22
|
-
const raw = await this.redis.get(`${KEY_PREFIX}${key}`);
|
|
23
|
-
if (raw === null) return null;
|
|
24
|
-
return decrypt(raw);
|
|
25
|
-
} catch (error) {
|
|
26
|
-
logger.error("Failed to get env var", { key, error });
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async set(key: string, value: string): Promise<void> {
|
|
32
|
-
try {
|
|
33
|
-
await this.redis.set(`${KEY_PREFIX}${key}`, encrypt(value));
|
|
34
|
-
this.cache.set(key, value);
|
|
35
|
-
logger.info(`Set system env var: ${key}`);
|
|
36
|
-
} catch (error) {
|
|
37
|
-
logger.error("Failed to set env var", { key, error });
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async delete(key: string): Promise<void> {
|
|
43
|
-
try {
|
|
44
|
-
await this.redis.del(`${KEY_PREFIX}${key}`);
|
|
45
|
-
this.cache.delete(key);
|
|
46
|
-
logger.info(`Deleted system env var: ${key}`);
|
|
47
|
-
} catch (error) {
|
|
48
|
-
logger.error("Failed to delete env var", { key, error });
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async listAll(): Promise<Record<string, string>> {
|
|
53
|
-
const result: Record<string, string> = {};
|
|
54
|
-
let cursor = "0";
|
|
55
|
-
try {
|
|
56
|
-
do {
|
|
57
|
-
const [nextCursor, keys] = await this.redis.scan(
|
|
58
|
-
cursor,
|
|
59
|
-
"MATCH",
|
|
60
|
-
`${KEY_PREFIX}*`,
|
|
61
|
-
"COUNT",
|
|
62
|
-
100
|
|
63
|
-
);
|
|
64
|
-
cursor = nextCursor;
|
|
65
|
-
for (const key of keys) {
|
|
66
|
-
const raw = await this.redis.get(key);
|
|
67
|
-
if (raw !== null) {
|
|
68
|
-
result[key.slice(KEY_PREFIX.length)] = decrypt(raw);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
} while (cursor !== "0");
|
|
72
|
-
} catch (error) {
|
|
73
|
-
logger.error("Failed to list env vars", { error });
|
|
74
|
-
}
|
|
75
|
-
return result;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Synchronous lookup: cache first, then process.env.
|
|
80
|
-
* Used by the string-substitution env resolver.
|
|
81
|
-
*/
|
|
82
|
-
resolve(key: string): string | undefined {
|
|
83
|
-
return this.cache.get(key) ?? process.env[key] ?? undefined;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Load all system:env:* keys from Redis into the in-memory cache.
|
|
88
|
-
* Call on startup before registering the resolver.
|
|
89
|
-
*/
|
|
90
|
-
async refreshCache(): Promise<void> {
|
|
91
|
-
const all = await this.listAll();
|
|
92
|
-
this.cache.clear();
|
|
93
|
-
for (const [key, value] of Object.entries(all)) {
|
|
94
|
-
this.cache.set(key, value);
|
|
95
|
-
}
|
|
96
|
-
logger.debug(`Loaded ${this.cache.size} system env vars into cache`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "@lobu/core";
|
|
2
|
-
import type Redis from "ioredis";
|
|
3
|
-
|
|
4
|
-
const logger = createLogger("user-agents-store");
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Track which agents belong to which users.
|
|
8
|
-
* Uses Redis sets for fast membership checks and listing.
|
|
9
|
-
*
|
|
10
|
-
* Storage pattern:
|
|
11
|
-
* - user_agents:{platform}:{userId} -> Set of agentIds
|
|
12
|
-
*/
|
|
13
|
-
export class UserAgentsStore {
|
|
14
|
-
private readonly KEY_PREFIX = "user_agents";
|
|
15
|
-
|
|
16
|
-
constructor(private redis: Redis) {}
|
|
17
|
-
|
|
18
|
-
private buildKey(platform: string, userId: string): string {
|
|
19
|
-
return `${this.KEY_PREFIX}:${platform}:${userId}`;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Add an agent to a user's list
|
|
24
|
-
*/
|
|
25
|
-
async addAgent(
|
|
26
|
-
platform: string,
|
|
27
|
-
userId: string,
|
|
28
|
-
agentId: string
|
|
29
|
-
): Promise<void> {
|
|
30
|
-
const key = this.buildKey(platform, userId);
|
|
31
|
-
await this.redis.sadd(key, agentId);
|
|
32
|
-
logger.info(`Added agent ${agentId} to user ${platform}/${userId}`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Remove an agent from a user's list
|
|
37
|
-
*/
|
|
38
|
-
async removeAgent(
|
|
39
|
-
platform: string,
|
|
40
|
-
userId: string,
|
|
41
|
-
agentId: string
|
|
42
|
-
): Promise<void> {
|
|
43
|
-
const key = this.buildKey(platform, userId);
|
|
44
|
-
await this.redis.srem(key, agentId);
|
|
45
|
-
logger.info(`Removed agent ${agentId} from user ${platform}/${userId}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* List all agents owned by a user
|
|
50
|
-
*/
|
|
51
|
-
async listAgents(platform: string, userId: string): Promise<string[]> {
|
|
52
|
-
const key = this.buildKey(platform, userId);
|
|
53
|
-
return this.redis.smembers(key);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Check if a user owns a specific agent
|
|
58
|
-
*/
|
|
59
|
-
async ownsAgent(
|
|
60
|
-
platform: string,
|
|
61
|
-
userId: string,
|
|
62
|
-
agentId: string
|
|
63
|
-
): Promise<boolean> {
|
|
64
|
-
const key = this.buildKey(platform, userId);
|
|
65
|
-
const result = await this.redis.sismember(key, agentId);
|
|
66
|
-
return result === 1;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { BaseRedisStore, createLogger } from "@lobu/core";
|
|
2
|
-
import type Redis from "ioredis";
|
|
3
|
-
|
|
4
|
-
const logger = createLogger("channel-binding-service");
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Channel binding - links a platform channel to a specific agent
|
|
8
|
-
*/
|
|
9
|
-
export interface ChannelBinding {
|
|
10
|
-
platform: string; // Platform identifier
|
|
11
|
-
channelId: string;
|
|
12
|
-
agentId: string;
|
|
13
|
-
teamId?: string; // Optional workspace/team ID for multi-tenant platforms
|
|
14
|
-
configuredBy?: string; // userId of who configured this binding
|
|
15
|
-
configuredAt?: number; // When the binding was configured
|
|
16
|
-
wasAdmin?: boolean; // Whether the configurer was an admin at time of configuration
|
|
17
|
-
createdAt: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Internal storage format includes reverse lookup info
|
|
22
|
-
*/
|
|
23
|
-
interface StoredBinding extends ChannelBinding {
|
|
24
|
-
// Stored at channel_binding:{platform}:{channelId} or channel_binding:{platform}:{teamId}:{channelId}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Service for managing channel-to-agent bindings
|
|
29
|
-
*
|
|
30
|
-
* Storage patterns:
|
|
31
|
-
* - Forward lookup: channel_binding:{platform}:{channelId} → binding data
|
|
32
|
-
* - Forward lookup (Slack): channel_binding:{platform}:{teamId}:{channelId} → binding data
|
|
33
|
-
* - Reverse index: channel_binding_index:{agentId} → Set of binding keys
|
|
34
|
-
*/
|
|
35
|
-
export class ChannelBindingService extends BaseRedisStore<StoredBinding> {
|
|
36
|
-
private readonly INDEX_PREFIX = "channel_binding_index";
|
|
37
|
-
|
|
38
|
-
constructor(redis: Redis) {
|
|
39
|
-
super({
|
|
40
|
-
redis,
|
|
41
|
-
keyPrefix: "channel_binding",
|
|
42
|
-
loggerName: "channel-binding-service",
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Build the binding key for a channel
|
|
48
|
-
* Includes teamId for multi-tenant platforms (e.g., Slack workspaces)
|
|
49
|
-
*/
|
|
50
|
-
private buildBindingKey(
|
|
51
|
-
platform: string,
|
|
52
|
-
channelId: string,
|
|
53
|
-
teamId?: string
|
|
54
|
-
): string {
|
|
55
|
-
if (teamId) {
|
|
56
|
-
return this.buildKey(platform, teamId, channelId);
|
|
57
|
-
}
|
|
58
|
-
return this.buildKey(platform, channelId);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Build the index key for an agent's bindings
|
|
63
|
-
*/
|
|
64
|
-
private buildIndexKey(agentId: string): string {
|
|
65
|
-
return `${this.INDEX_PREFIX}:${agentId}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get binding for a channel
|
|
70
|
-
* Returns null if channel is not bound to any agent
|
|
71
|
-
*/
|
|
72
|
-
async getBinding(
|
|
73
|
-
platform: string,
|
|
74
|
-
channelId: string,
|
|
75
|
-
teamId?: string
|
|
76
|
-
): Promise<ChannelBinding | null> {
|
|
77
|
-
const key = this.buildBindingKey(platform, channelId, teamId);
|
|
78
|
-
const binding = await this.get(key);
|
|
79
|
-
if (binding) {
|
|
80
|
-
logger.debug(
|
|
81
|
-
`Found binding for ${platform}/${channelId}: ${binding.agentId}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
return binding;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Create a binding from a channel to an agent
|
|
89
|
-
* If the channel was already bound, the old binding is removed
|
|
90
|
-
*/
|
|
91
|
-
async createBinding(
|
|
92
|
-
agentId: string,
|
|
93
|
-
platform: string,
|
|
94
|
-
channelId: string,
|
|
95
|
-
teamId?: string,
|
|
96
|
-
options?: { configuredBy?: string; wasAdmin?: boolean }
|
|
97
|
-
): Promise<void> {
|
|
98
|
-
const key = this.buildBindingKey(platform, channelId, teamId);
|
|
99
|
-
|
|
100
|
-
// Check if already bound to a different agent
|
|
101
|
-
const existing = await this.get(key);
|
|
102
|
-
if (existing && existing.agentId !== agentId) {
|
|
103
|
-
// Remove from old agent's index
|
|
104
|
-
const oldIndexKey = this.buildIndexKey(existing.agentId);
|
|
105
|
-
await this.redis.srem(oldIndexKey, key);
|
|
106
|
-
logger.info(
|
|
107
|
-
`Removed binding from agent ${existing.agentId} for ${platform}/${channelId}`
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Create the binding
|
|
112
|
-
const binding: StoredBinding = {
|
|
113
|
-
platform,
|
|
114
|
-
channelId,
|
|
115
|
-
agentId,
|
|
116
|
-
teamId,
|
|
117
|
-
configuredBy: options?.configuredBy,
|
|
118
|
-
configuredAt: Date.now(),
|
|
119
|
-
wasAdmin: options?.wasAdmin,
|
|
120
|
-
createdAt: Date.now(),
|
|
121
|
-
};
|
|
122
|
-
await this.set(key, binding);
|
|
123
|
-
|
|
124
|
-
// Add to agent's index
|
|
125
|
-
const indexKey = this.buildIndexKey(agentId);
|
|
126
|
-
await this.redis.sadd(indexKey, key);
|
|
127
|
-
|
|
128
|
-
logger.info(`Created binding: ${platform}/${channelId} → ${agentId}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Delete a binding for a channel
|
|
133
|
-
*/
|
|
134
|
-
async deleteBinding(
|
|
135
|
-
agentId: string,
|
|
136
|
-
platform: string,
|
|
137
|
-
channelId: string,
|
|
138
|
-
teamId?: string
|
|
139
|
-
): Promise<boolean> {
|
|
140
|
-
const key = this.buildBindingKey(platform, channelId, teamId);
|
|
141
|
-
const existing = await this.get(key);
|
|
142
|
-
|
|
143
|
-
if (!existing) {
|
|
144
|
-
logger.warn(`No binding found for ${platform}/${channelId}`);
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (existing.agentId !== agentId) {
|
|
149
|
-
logger.warn(
|
|
150
|
-
`Binding for ${platform}/${channelId} belongs to ${existing.agentId}, not ${agentId}`
|
|
151
|
-
);
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Delete the binding
|
|
156
|
-
await this.delete(key);
|
|
157
|
-
|
|
158
|
-
// Remove from agent's index
|
|
159
|
-
const indexKey = this.buildIndexKey(agentId);
|
|
160
|
-
await this.redis.srem(indexKey, key);
|
|
161
|
-
|
|
162
|
-
logger.info(`Deleted binding: ${platform}/${channelId} from ${agentId}`);
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* List all bindings for an agent
|
|
168
|
-
*/
|
|
169
|
-
async listBindings(agentId: string): Promise<ChannelBinding[]> {
|
|
170
|
-
const indexKey = this.buildIndexKey(agentId);
|
|
171
|
-
const bindingKeys = await this.redis.smembers(indexKey);
|
|
172
|
-
|
|
173
|
-
if (bindingKeys.length === 0) {
|
|
174
|
-
return [];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const bindings: ChannelBinding[] = [];
|
|
178
|
-
for (const key of bindingKeys) {
|
|
179
|
-
const binding = await this.get(key);
|
|
180
|
-
if (binding) {
|
|
181
|
-
bindings.push(binding);
|
|
182
|
-
} else {
|
|
183
|
-
// Clean up stale index entry
|
|
184
|
-
await this.redis.srem(indexKey, key);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return bindings;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Delete all bindings for an agent
|
|
193
|
-
* Used when deleting an agent
|
|
194
|
-
*/
|
|
195
|
-
async deleteAllBindings(agentId: string): Promise<number> {
|
|
196
|
-
const bindings = await this.listBindings(agentId);
|
|
197
|
-
|
|
198
|
-
for (const binding of bindings) {
|
|
199
|
-
const key = this.buildBindingKey(
|
|
200
|
-
binding.platform,
|
|
201
|
-
binding.channelId,
|
|
202
|
-
binding.teamId
|
|
203
|
-
);
|
|
204
|
-
await this.delete(key);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Delete the index
|
|
208
|
-
const indexKey = this.buildIndexKey(agentId);
|
|
209
|
-
await this.redis.del(indexKey);
|
|
210
|
-
|
|
211
|
-
logger.info(`Deleted ${bindings.length} bindings for agent ${agentId}`);
|
|
212
|
-
return bindings.length;
|
|
213
|
-
}
|
|
214
|
-
}
|
package/src/channels/index.ts
DELETED