@deadragdoll/tellymcp 0.0.1
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/.env.example.client +93 -0
- package/.env.example.gateway +120 -0
- package/CHANGELOG.md +155 -0
- package/LICENSE +21 -0
- package/README-ru.md +338 -0
- package/README.md +1262 -0
- package/STANDALONE-ru.md +266 -0
- package/STANDALONE.md +266 -0
- package/TOOLS.md +1296 -0
- package/config/templates/env.both.template +83 -0
- package/config/templates/env.client.template +60 -0
- package/config/templates/env.gateway.template +82 -0
- package/dist/cli.js +636 -0
- package/dist/index.js +17 -0
- package/dist/lib/logfeed/store.js +52 -0
- package/dist/lib/middlewares/tracer.js +172 -0
- package/dist/lib/mixins/db.js +267 -0
- package/dist/lib/mixins/logfeed.js +34 -0
- package/dist/lib/mixins/session.errors.js +142 -0
- package/dist/lib/moleculer.js +2 -0
- package/dist/lib/trace.js +147 -0
- package/dist/lib/traceContext.js +116 -0
- package/dist/moleculer.config.js +274 -0
- package/dist/services/features/telegram-mcp/approval.service.js +33 -0
- package/dist/services/features/telegram-mcp/browser.service.js +42 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
- package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
- package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
- package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
- package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
- package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
- package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
- package/dist/services/features/telegram-mcp/notify.service.js +33 -0
- package/dist/services/features/telegram-mcp/pair.service.js +33 -0
- package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
- package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
- package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
- package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
- package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
- package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
- package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
- package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
- package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
- package/package.json +110 -0
- package/scripts/postinstall.js +60 -0
|
@@ -0,0 +1,1141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TELEGRAM_MCP_GATEWAY_SERVICE_NAME = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const db_1 = require("../../../lib/mixins/db");
|
|
10
|
+
const gatewayReplyResolution_1 = require("./src/features/distributed-gateway/model/gatewayReplyResolution");
|
|
11
|
+
const ensuredb_service_1 = require("./ensuredb.service");
|
|
12
|
+
exports.TELEGRAM_MCP_GATEWAY_SERVICE_NAME = "telegramMcp.gateway";
|
|
13
|
+
const MCP_SCHEMA = process.env.DB_SCHEME || "mcp";
|
|
14
|
+
const DISTRIBUTED_MODE = process.env.DISTRIBUTED_MODE || "client";
|
|
15
|
+
const GATEWAY_ENABLED = DISTRIBUTED_MODE === "gateway" || DISTRIBUTED_MODE === "both";
|
|
16
|
+
function trimOptionalText(value) {
|
|
17
|
+
const text = typeof value === "string" ? value.trim() : String(value ?? "").trim();
|
|
18
|
+
return text ? text : null;
|
|
19
|
+
}
|
|
20
|
+
function sanitizeArtifactName(value) {
|
|
21
|
+
const withoutControlChars = Array.from(value)
|
|
22
|
+
.map((char) => (char.charCodeAt(0) < 32 ? "-" : char))
|
|
23
|
+
.join("");
|
|
24
|
+
return withoutControlChars
|
|
25
|
+
.trim()
|
|
26
|
+
.replace(/[/\\]+/gu, "-")
|
|
27
|
+
.replace(/\s+/gu, " ")
|
|
28
|
+
.replace(/^\.+$/u, "file")
|
|
29
|
+
.slice(0, 180) || "file";
|
|
30
|
+
}
|
|
31
|
+
function allocateArtifactRelativePath(shareId, preferredName, usedNames) {
|
|
32
|
+
const sanitized = sanitizeArtifactName(preferredName);
|
|
33
|
+
const ext = node_path_1.default.extname(sanitized);
|
|
34
|
+
const base = ext ? sanitized.slice(0, -ext.length) : sanitized;
|
|
35
|
+
let candidate = sanitized;
|
|
36
|
+
let index = 1;
|
|
37
|
+
while (usedNames.has(candidate.toLowerCase())) {
|
|
38
|
+
candidate = `${base}--${index}${ext}`;
|
|
39
|
+
index += 1;
|
|
40
|
+
}
|
|
41
|
+
usedNames.add(candidate.toLowerCase());
|
|
42
|
+
return `shares/files/${shareId}/${candidate}`;
|
|
43
|
+
}
|
|
44
|
+
function readClientMeta(client) {
|
|
45
|
+
if (!client?.meta || typeof client.meta !== "object" || Array.isArray(client.meta)) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
return client.meta;
|
|
49
|
+
}
|
|
50
|
+
const TelegramMcpGatewayService = {
|
|
51
|
+
name: exports.TELEGRAM_MCP_GATEWAY_SERVICE_NAME,
|
|
52
|
+
mixins: [db_1.DBMixin],
|
|
53
|
+
dependencies: [ensuredb_service_1.TELEGRAM_MCP_ENSUREDB_SERVICE_NAME],
|
|
54
|
+
methods: {
|
|
55
|
+
normalizeOptionalText(value) {
|
|
56
|
+
const text = typeof value === "string" ? value.trim() : String(value ?? "").trim();
|
|
57
|
+
return text ? text : null;
|
|
58
|
+
},
|
|
59
|
+
requireText(value, fieldName) {
|
|
60
|
+
const text = this.normalizeOptionalText?.(value);
|
|
61
|
+
if (!text) {
|
|
62
|
+
throw new Error(`${fieldName} is required`);
|
|
63
|
+
}
|
|
64
|
+
return text;
|
|
65
|
+
},
|
|
66
|
+
async registerClientRecord(input) {
|
|
67
|
+
const clientUuid = this.normalizeOptionalText?.(input.client_uuid) || (0, node_crypto_1.randomUUID)();
|
|
68
|
+
const now = new Date().toISOString();
|
|
69
|
+
const clientLabel = this.normalizeOptionalText?.(input.client_label);
|
|
70
|
+
const botUsername = this.normalizeOptionalText?.(input.bot_username);
|
|
71
|
+
const tokenFingerprint = this.normalizeOptionalText?.(input.bot_token_fingerprint);
|
|
72
|
+
const meta = input.meta && typeof input.meta === "object" && !Array.isArray(input.meta)
|
|
73
|
+
? input.meta
|
|
74
|
+
: {};
|
|
75
|
+
const existing = await this.db
|
|
76
|
+
.withSchema(MCP_SCHEMA)
|
|
77
|
+
.table("gateway_clients")
|
|
78
|
+
.where({ client_uuid: clientUuid })
|
|
79
|
+
.first();
|
|
80
|
+
if (existing) {
|
|
81
|
+
await this.db
|
|
82
|
+
.withSchema(MCP_SCHEMA)
|
|
83
|
+
.table("gateway_clients")
|
|
84
|
+
.where({ client_uuid: clientUuid })
|
|
85
|
+
.update({
|
|
86
|
+
...(clientLabel ? { client_label: clientLabel } : {}),
|
|
87
|
+
...(botUsername ? { bot_username: botUsername } : {}),
|
|
88
|
+
...(tokenFingerprint ? { bot_token_fingerprint: tokenFingerprint } : {}),
|
|
89
|
+
meta: this.db.raw(`?::jsonb`, [JSON.stringify(meta)]),
|
|
90
|
+
updated_at: now,
|
|
91
|
+
last_seen_at: now,
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
client_uuid: clientUuid,
|
|
95
|
+
created: false,
|
|
96
|
+
updated_at: now,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_clients").insert({
|
|
100
|
+
client_uuid: clientUuid,
|
|
101
|
+
...(clientLabel ? { client_label: clientLabel } : {}),
|
|
102
|
+
...(botUsername ? { bot_username: botUsername } : {}),
|
|
103
|
+
...(tokenFingerprint ? { bot_token_fingerprint: tokenFingerprint } : {}),
|
|
104
|
+
meta: this.db.raw(`?::jsonb`, [JSON.stringify(meta)]),
|
|
105
|
+
created_at: now,
|
|
106
|
+
updated_at: now,
|
|
107
|
+
last_seen_at: now,
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
client_uuid: clientUuid,
|
|
111
|
+
created: true,
|
|
112
|
+
updated_at: now,
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
async createProjectRecord(input) {
|
|
116
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
117
|
+
const name = this.requireText?.(input.name, "name");
|
|
118
|
+
const client = await this.db
|
|
119
|
+
.withSchema(MCP_SCHEMA)
|
|
120
|
+
.table("gateway_clients")
|
|
121
|
+
.where({ client_uuid: clientUuid })
|
|
122
|
+
.first();
|
|
123
|
+
if (!client) {
|
|
124
|
+
throw new Error(`Client ${clientUuid} is not registered`);
|
|
125
|
+
}
|
|
126
|
+
const clientMeta = readClientMeta(client);
|
|
127
|
+
const ownerTelegramUserId = this.normalizeOptionalText?.(clientMeta.telegram_user_id);
|
|
128
|
+
const ownerTelegramUsername = this.normalizeOptionalText?.(clientMeta.telegram_username);
|
|
129
|
+
const ownerDisplayName = this.normalizeOptionalText?.(clientMeta.telegram_display_name);
|
|
130
|
+
const projectUuid = (0, node_crypto_1.randomUUID)();
|
|
131
|
+
const inviteToken = (0, node_crypto_1.randomUUID)();
|
|
132
|
+
const now = new Date().toISOString();
|
|
133
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_projects").insert({
|
|
134
|
+
project_uuid: projectUuid,
|
|
135
|
+
name,
|
|
136
|
+
invite_token: inviteToken,
|
|
137
|
+
created_by_client_uuid: clientUuid,
|
|
138
|
+
...(ownerTelegramUserId
|
|
139
|
+
? { owner_telegram_user_id: ownerTelegramUserId }
|
|
140
|
+
: {}),
|
|
141
|
+
...(ownerTelegramUsername
|
|
142
|
+
? { owner_telegram_username: ownerTelegramUsername }
|
|
143
|
+
: {}),
|
|
144
|
+
...(ownerDisplayName ? { owner_display_name: ownerDisplayName } : {}),
|
|
145
|
+
is_active: true,
|
|
146
|
+
created_at: now,
|
|
147
|
+
updated_at: now,
|
|
148
|
+
});
|
|
149
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_project_members").insert({
|
|
150
|
+
project_uuid: projectUuid,
|
|
151
|
+
client_uuid: clientUuid,
|
|
152
|
+
role: "owner",
|
|
153
|
+
status: "active",
|
|
154
|
+
...(ownerTelegramUserId ? { telegram_user_id: ownerTelegramUserId } : {}),
|
|
155
|
+
...(ownerTelegramUsername ? { telegram_username: ownerTelegramUsername } : {}),
|
|
156
|
+
...(ownerDisplayName ? { display_name: ownerDisplayName } : {}),
|
|
157
|
+
joined_at: now,
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
project_uuid: projectUuid,
|
|
161
|
+
invite_token: inviteToken,
|
|
162
|
+
name,
|
|
163
|
+
created: true,
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
async joinProjectRecord(input) {
|
|
167
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
168
|
+
const inviteToken = this.requireText?.(input.invite_token, "invite_token");
|
|
169
|
+
const client = await this.db
|
|
170
|
+
.withSchema(MCP_SCHEMA)
|
|
171
|
+
.table("gateway_clients")
|
|
172
|
+
.where({ client_uuid: clientUuid })
|
|
173
|
+
.first();
|
|
174
|
+
if (!client) {
|
|
175
|
+
throw new Error(`Client ${clientUuid} is not registered`);
|
|
176
|
+
}
|
|
177
|
+
const clientMeta = readClientMeta(client);
|
|
178
|
+
const memberTelegramUserId = this.normalizeOptionalText?.(clientMeta.telegram_user_id);
|
|
179
|
+
const memberTelegramUsername = this.normalizeOptionalText?.(clientMeta.telegram_username);
|
|
180
|
+
const memberDisplayName = this.normalizeOptionalText?.(clientMeta.telegram_display_name);
|
|
181
|
+
const project = await this.db
|
|
182
|
+
.withSchema(MCP_SCHEMA)
|
|
183
|
+
.table("gateway_projects")
|
|
184
|
+
.where({ invite_token: inviteToken, is_active: true })
|
|
185
|
+
.first();
|
|
186
|
+
if (!project) {
|
|
187
|
+
throw new Error("Project invite token is invalid or inactive");
|
|
188
|
+
}
|
|
189
|
+
const existing = await this.db
|
|
190
|
+
.withSchema(MCP_SCHEMA)
|
|
191
|
+
.table("gateway_project_members")
|
|
192
|
+
.where({
|
|
193
|
+
project_uuid: project.project_uuid,
|
|
194
|
+
client_uuid: clientUuid,
|
|
195
|
+
})
|
|
196
|
+
.first();
|
|
197
|
+
if (existing) {
|
|
198
|
+
const notifyRows = existing.status !== "active"
|
|
199
|
+
? await this.db
|
|
200
|
+
.withSchema(MCP_SCHEMA)
|
|
201
|
+
.table("gateway_project_members")
|
|
202
|
+
.where({
|
|
203
|
+
project_uuid: project.project_uuid,
|
|
204
|
+
status: "active",
|
|
205
|
+
})
|
|
206
|
+
.whereNot({
|
|
207
|
+
client_uuid: clientUuid,
|
|
208
|
+
})
|
|
209
|
+
.distinct("client_uuid")
|
|
210
|
+
: [];
|
|
211
|
+
if (existing.status !== "active") {
|
|
212
|
+
await this.db
|
|
213
|
+
.withSchema(MCP_SCHEMA)
|
|
214
|
+
.table("gateway_project_members")
|
|
215
|
+
.where({
|
|
216
|
+
project_uuid: project.project_uuid,
|
|
217
|
+
client_uuid: clientUuid,
|
|
218
|
+
})
|
|
219
|
+
.update({
|
|
220
|
+
status: "active",
|
|
221
|
+
...(memberTelegramUserId
|
|
222
|
+
? { telegram_user_id: memberTelegramUserId }
|
|
223
|
+
: {}),
|
|
224
|
+
...(memberTelegramUsername
|
|
225
|
+
? { telegram_username: memberTelegramUsername }
|
|
226
|
+
: {}),
|
|
227
|
+
...(memberDisplayName ? { display_name: memberDisplayName } : {}),
|
|
228
|
+
joined_at: new Date().toISOString(),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
project_uuid: project.project_uuid,
|
|
233
|
+
invite_token: project.invite_token,
|
|
234
|
+
name: project.name,
|
|
235
|
+
joined: false,
|
|
236
|
+
...(notifyRows.length > 0
|
|
237
|
+
? {
|
|
238
|
+
notify_client_uuids: notifyRows
|
|
239
|
+
.map((row) => String(row.client_uuid))
|
|
240
|
+
.filter(Boolean),
|
|
241
|
+
}
|
|
242
|
+
: {}),
|
|
243
|
+
member_display_name: memberDisplayName ?? null,
|
|
244
|
+
member_telegram_username: memberTelegramUsername ?? null,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_project_members").insert({
|
|
248
|
+
project_uuid: project.project_uuid,
|
|
249
|
+
client_uuid: clientUuid,
|
|
250
|
+
role: "member",
|
|
251
|
+
status: "active",
|
|
252
|
+
...(memberTelegramUserId ? { telegram_user_id: memberTelegramUserId } : {}),
|
|
253
|
+
...(memberTelegramUsername ? { telegram_username: memberTelegramUsername } : {}),
|
|
254
|
+
...(memberDisplayName ? { display_name: memberDisplayName } : {}),
|
|
255
|
+
joined_at: new Date().toISOString(),
|
|
256
|
+
});
|
|
257
|
+
const notifyRows = await this.db
|
|
258
|
+
.withSchema(MCP_SCHEMA)
|
|
259
|
+
.table("gateway_project_members")
|
|
260
|
+
.where({
|
|
261
|
+
project_uuid: project.project_uuid,
|
|
262
|
+
status: "active",
|
|
263
|
+
})
|
|
264
|
+
.whereNot({
|
|
265
|
+
client_uuid: clientUuid,
|
|
266
|
+
})
|
|
267
|
+
.distinct("client_uuid");
|
|
268
|
+
return {
|
|
269
|
+
project_uuid: project.project_uuid,
|
|
270
|
+
invite_token: project.invite_token,
|
|
271
|
+
name: project.name,
|
|
272
|
+
joined: true,
|
|
273
|
+
...(notifyRows.length > 0
|
|
274
|
+
? {
|
|
275
|
+
notify_client_uuids: notifyRows
|
|
276
|
+
.map((row) => String(row.client_uuid))
|
|
277
|
+
.filter(Boolean),
|
|
278
|
+
}
|
|
279
|
+
: {}),
|
|
280
|
+
member_display_name: memberDisplayName ?? null,
|
|
281
|
+
member_telegram_username: memberTelegramUsername ?? null,
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
async registerSessionRecord(input) {
|
|
285
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
286
|
+
const projectUuid = this.requireText?.(input.project_uuid, "project_uuid");
|
|
287
|
+
const localSessionId = this.requireText?.(input.local_session_id, "local_session_id");
|
|
288
|
+
const now = new Date().toISOString();
|
|
289
|
+
const membership = await this.db
|
|
290
|
+
.withSchema(MCP_SCHEMA)
|
|
291
|
+
.table("gateway_project_members")
|
|
292
|
+
.where({
|
|
293
|
+
project_uuid: projectUuid,
|
|
294
|
+
client_uuid: clientUuid,
|
|
295
|
+
status: "active",
|
|
296
|
+
})
|
|
297
|
+
.first();
|
|
298
|
+
if (!membership) {
|
|
299
|
+
throw new Error(`Client ${clientUuid} is not an active member of project ${projectUuid}`);
|
|
300
|
+
}
|
|
301
|
+
const existing = await this.db
|
|
302
|
+
.withSchema(MCP_SCHEMA)
|
|
303
|
+
.table("gateway_sessions")
|
|
304
|
+
.where({
|
|
305
|
+
project_uuid: projectUuid,
|
|
306
|
+
client_uuid: clientUuid,
|
|
307
|
+
local_session_id: localSessionId,
|
|
308
|
+
})
|
|
309
|
+
.first();
|
|
310
|
+
const payload = {
|
|
311
|
+
project_uuid: projectUuid,
|
|
312
|
+
client_uuid: clientUuid,
|
|
313
|
+
local_session_id: localSessionId,
|
|
314
|
+
...(this.normalizeOptionalText?.(input.label)
|
|
315
|
+
? { label: this.normalizeOptionalText?.(input.label) }
|
|
316
|
+
: {}),
|
|
317
|
+
...(this.normalizeOptionalText?.(input.cwd)
|
|
318
|
+
? { cwd: this.normalizeOptionalText?.(input.cwd) }
|
|
319
|
+
: {}),
|
|
320
|
+
...(this.normalizeOptionalText?.(input.tmux_session_name)
|
|
321
|
+
? { tmux_session_name: this.normalizeOptionalText?.(input.tmux_session_name) }
|
|
322
|
+
: {}),
|
|
323
|
+
...(this.normalizeOptionalText?.(input.tmux_window_name)
|
|
324
|
+
? { tmux_window_name: this.normalizeOptionalText?.(input.tmux_window_name) }
|
|
325
|
+
: {}),
|
|
326
|
+
...(Number.isInteger(input.tmux_window_index)
|
|
327
|
+
? { tmux_window_index: input.tmux_window_index }
|
|
328
|
+
: {}),
|
|
329
|
+
...(this.normalizeOptionalText?.(input.tmux_pane_id)
|
|
330
|
+
? { tmux_pane_id: this.normalizeOptionalText?.(input.tmux_pane_id) }
|
|
331
|
+
: {}),
|
|
332
|
+
...(Number.isInteger(input.tmux_pane_index)
|
|
333
|
+
? { tmux_pane_index: input.tmux_pane_index }
|
|
334
|
+
: {}),
|
|
335
|
+
...(this.normalizeOptionalText?.(input.tmux_target)
|
|
336
|
+
? { tmux_target: this.normalizeOptionalText?.(input.tmux_target) }
|
|
337
|
+
: {}),
|
|
338
|
+
status: this.normalizeOptionalText?.(input.status) || "active",
|
|
339
|
+
meta: this.db.raw(`?::jsonb`, [
|
|
340
|
+
JSON.stringify(input.meta && typeof input.meta === "object" && !Array.isArray(input.meta)
|
|
341
|
+
? input.meta
|
|
342
|
+
: {}),
|
|
343
|
+
]),
|
|
344
|
+
updated_at: now,
|
|
345
|
+
};
|
|
346
|
+
if (existing) {
|
|
347
|
+
await this.db
|
|
348
|
+
.withSchema(MCP_SCHEMA)
|
|
349
|
+
.table("gateway_sessions")
|
|
350
|
+
.where({ session_uuid: existing.session_uuid })
|
|
351
|
+
.update(payload);
|
|
352
|
+
return {
|
|
353
|
+
session_uuid: existing.session_uuid,
|
|
354
|
+
created: false,
|
|
355
|
+
updated_at: now,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
const sessionUuid = (0, node_crypto_1.randomUUID)();
|
|
359
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_sessions").insert({
|
|
360
|
+
session_uuid: sessionUuid,
|
|
361
|
+
...payload,
|
|
362
|
+
created_at: now,
|
|
363
|
+
});
|
|
364
|
+
return {
|
|
365
|
+
session_uuid: sessionUuid,
|
|
366
|
+
created: true,
|
|
367
|
+
updated_at: now,
|
|
368
|
+
};
|
|
369
|
+
},
|
|
370
|
+
async unregisterSessionRecord(input) {
|
|
371
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
372
|
+
const localSessionId = this.requireText?.(input.local_session_id, "local_session_id");
|
|
373
|
+
const deleted = await this.db
|
|
374
|
+
.withSchema(MCP_SCHEMA)
|
|
375
|
+
.table("gateway_sessions")
|
|
376
|
+
.where({
|
|
377
|
+
client_uuid: clientUuid,
|
|
378
|
+
local_session_id: localSessionId,
|
|
379
|
+
})
|
|
380
|
+
.del();
|
|
381
|
+
return {
|
|
382
|
+
local_session_id: localSessionId,
|
|
383
|
+
deleted,
|
|
384
|
+
};
|
|
385
|
+
},
|
|
386
|
+
async listProjectsRecord(input) {
|
|
387
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
388
|
+
const rows = await this.db
|
|
389
|
+
.withSchema(MCP_SCHEMA)
|
|
390
|
+
.table("gateway_project_members as m")
|
|
391
|
+
.join("gateway_projects as p", "p.project_uuid", "m.project_uuid")
|
|
392
|
+
.where("m.client_uuid", clientUuid)
|
|
393
|
+
.where("m.status", "active")
|
|
394
|
+
.where("p.is_active", true)
|
|
395
|
+
.select("p.project_uuid", "p.name", "p.invite_token", "m.role", "m.status", "m.joined_at")
|
|
396
|
+
.orderBy("p.name", "asc");
|
|
397
|
+
return {
|
|
398
|
+
projects: rows.map((row) => ({
|
|
399
|
+
project_uuid: row.project_uuid,
|
|
400
|
+
name: row.name,
|
|
401
|
+
invite_token: row.invite_token,
|
|
402
|
+
role: row.role,
|
|
403
|
+
status: row.status,
|
|
404
|
+
...(row.joined_at ? { joined_at: String(row.joined_at) } : {}),
|
|
405
|
+
})),
|
|
406
|
+
};
|
|
407
|
+
},
|
|
408
|
+
async leaveProjectRecord(input) {
|
|
409
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
410
|
+
const projectUuid = this.requireText?.(input.project_uuid, "project_uuid");
|
|
411
|
+
const client = await this.db
|
|
412
|
+
.withSchema(MCP_SCHEMA)
|
|
413
|
+
.table("gateway_clients")
|
|
414
|
+
.where({ client_uuid: clientUuid })
|
|
415
|
+
.first();
|
|
416
|
+
const membership = await this.db
|
|
417
|
+
.withSchema(MCP_SCHEMA)
|
|
418
|
+
.table("gateway_project_members")
|
|
419
|
+
.where({
|
|
420
|
+
client_uuid: clientUuid,
|
|
421
|
+
project_uuid: projectUuid,
|
|
422
|
+
})
|
|
423
|
+
.first();
|
|
424
|
+
const project = await this.db
|
|
425
|
+
.withSchema(MCP_SCHEMA)
|
|
426
|
+
.table("gateway_projects")
|
|
427
|
+
.where({ project_uuid: projectUuid })
|
|
428
|
+
.first();
|
|
429
|
+
const clientMeta = readClientMeta(client ?? {});
|
|
430
|
+
const memberDisplayName = this.normalizeOptionalText?.(membership?.display_name) ??
|
|
431
|
+
this.normalizeOptionalText?.(clientMeta.telegram_display_name) ??
|
|
432
|
+
null;
|
|
433
|
+
const memberTelegramUsername = this.normalizeOptionalText?.(membership?.telegram_username) ??
|
|
434
|
+
this.normalizeOptionalText?.(clientMeta.telegram_username) ??
|
|
435
|
+
null;
|
|
436
|
+
const updated = await this.db
|
|
437
|
+
.withSchema(MCP_SCHEMA)
|
|
438
|
+
.table("gateway_project_members")
|
|
439
|
+
.where({
|
|
440
|
+
client_uuid: clientUuid,
|
|
441
|
+
project_uuid: projectUuid,
|
|
442
|
+
})
|
|
443
|
+
.update({
|
|
444
|
+
status: "left",
|
|
445
|
+
});
|
|
446
|
+
const notifyRows = updated > 0
|
|
447
|
+
? await this.db
|
|
448
|
+
.withSchema(MCP_SCHEMA)
|
|
449
|
+
.table("gateway_project_members")
|
|
450
|
+
.where({
|
|
451
|
+
project_uuid: projectUuid,
|
|
452
|
+
status: "active",
|
|
453
|
+
})
|
|
454
|
+
.whereNot({
|
|
455
|
+
client_uuid: clientUuid,
|
|
456
|
+
})
|
|
457
|
+
.distinct("client_uuid")
|
|
458
|
+
: [];
|
|
459
|
+
return {
|
|
460
|
+
project_uuid: projectUuid,
|
|
461
|
+
left: updated > 0,
|
|
462
|
+
...(project?.name ? { project_name: project.name } : {}),
|
|
463
|
+
...(notifyRows.length > 0
|
|
464
|
+
? {
|
|
465
|
+
notify_client_uuids: notifyRows
|
|
466
|
+
.map((row) => String(row.client_uuid))
|
|
467
|
+
.filter(Boolean),
|
|
468
|
+
}
|
|
469
|
+
: {}),
|
|
470
|
+
...(memberDisplayName ? { member_display_name: memberDisplayName } : {}),
|
|
471
|
+
...(memberTelegramUsername
|
|
472
|
+
? { member_telegram_username: memberTelegramUsername }
|
|
473
|
+
: {}),
|
|
474
|
+
};
|
|
475
|
+
},
|
|
476
|
+
async deleteProjectRecord(input) {
|
|
477
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
478
|
+
const projectUuid = this.requireText?.(input.project_uuid, "project_uuid");
|
|
479
|
+
const project = await this.db
|
|
480
|
+
.withSchema(MCP_SCHEMA)
|
|
481
|
+
.table("gateway_projects")
|
|
482
|
+
.where({ project_uuid: projectUuid, is_active: true })
|
|
483
|
+
.first();
|
|
484
|
+
if (!project) {
|
|
485
|
+
throw new Error("Project was not found or is already inactive.");
|
|
486
|
+
}
|
|
487
|
+
const ownerMembership = await this.db
|
|
488
|
+
.withSchema(MCP_SCHEMA)
|
|
489
|
+
.table("gateway_project_members")
|
|
490
|
+
.where({
|
|
491
|
+
client_uuid: clientUuid,
|
|
492
|
+
project_uuid: projectUuid,
|
|
493
|
+
status: "active",
|
|
494
|
+
role: "owner",
|
|
495
|
+
})
|
|
496
|
+
.first();
|
|
497
|
+
if (!ownerMembership) {
|
|
498
|
+
throw new Error("Only the project owner can delete this project.");
|
|
499
|
+
}
|
|
500
|
+
const notifyRows = await this.db
|
|
501
|
+
.withSchema(MCP_SCHEMA)
|
|
502
|
+
.table("gateway_project_members")
|
|
503
|
+
.where({
|
|
504
|
+
project_uuid: projectUuid,
|
|
505
|
+
status: "active",
|
|
506
|
+
})
|
|
507
|
+
.distinct("client_uuid");
|
|
508
|
+
const deleted = await this.db
|
|
509
|
+
.withSchema(MCP_SCHEMA)
|
|
510
|
+
.table("gateway_projects")
|
|
511
|
+
.where({ project_uuid: projectUuid })
|
|
512
|
+
.del();
|
|
513
|
+
return {
|
|
514
|
+
project_uuid: projectUuid,
|
|
515
|
+
deleted: deleted > 0,
|
|
516
|
+
...(project.name ? { project_name: project.name } : {}),
|
|
517
|
+
...(notifyRows.length > 0
|
|
518
|
+
? {
|
|
519
|
+
notify_client_uuids: notifyRows
|
|
520
|
+
.map((row) => String(row.client_uuid))
|
|
521
|
+
.filter(Boolean),
|
|
522
|
+
}
|
|
523
|
+
: {}),
|
|
524
|
+
};
|
|
525
|
+
},
|
|
526
|
+
async listProjectSessionsRecord(input) {
|
|
527
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
528
|
+
const projectUuid = this.requireText?.(input.project_uuid, "project_uuid");
|
|
529
|
+
const membership = await this.db
|
|
530
|
+
.withSchema(MCP_SCHEMA)
|
|
531
|
+
.table("gateway_project_members")
|
|
532
|
+
.where({
|
|
533
|
+
client_uuid: clientUuid,
|
|
534
|
+
project_uuid: projectUuid,
|
|
535
|
+
status: "active",
|
|
536
|
+
})
|
|
537
|
+
.first();
|
|
538
|
+
if (!membership) {
|
|
539
|
+
throw new Error(`Client ${clientUuid} is not an active member of project ${projectUuid}`);
|
|
540
|
+
}
|
|
541
|
+
const rows = await this.db
|
|
542
|
+
.withSchema(MCP_SCHEMA)
|
|
543
|
+
.table("gateway_sessions as s")
|
|
544
|
+
.leftJoin("gateway_clients as c", "c.client_uuid", "s.client_uuid")
|
|
545
|
+
.leftJoin("gateway_project_members as m", function joinMember() {
|
|
546
|
+
this.on("m.project_uuid", "=", "s.project_uuid").andOn("m.client_uuid", "=", "s.client_uuid");
|
|
547
|
+
})
|
|
548
|
+
.where("s.project_uuid", projectUuid)
|
|
549
|
+
.where("s.status", "active")
|
|
550
|
+
.where("m.status", "active")
|
|
551
|
+
.select("s.session_uuid", "s.project_uuid", "s.client_uuid", "s.local_session_id", "s.label", "s.status", "s.updated_at", "c.client_label", this.db.raw("coalesce(nullif(m.telegram_username, ''), nullif(c.meta->>'telegram_username', '')) as telegram_username"), "c.bot_username", "m.joined_at")
|
|
552
|
+
.orderByRaw("coalesce(s.label, s.local_session_id) asc")
|
|
553
|
+
.orderBy("s.updated_at", "desc");
|
|
554
|
+
return {
|
|
555
|
+
sessions: rows.map((row) => ({
|
|
556
|
+
session_uuid: row.session_uuid,
|
|
557
|
+
project_uuid: row.project_uuid,
|
|
558
|
+
client_uuid: row.client_uuid,
|
|
559
|
+
local_session_id: row.local_session_id,
|
|
560
|
+
label: row.label ?? null,
|
|
561
|
+
status: row.status,
|
|
562
|
+
client_label: row.client_label ?? null,
|
|
563
|
+
telegram_username: row.telegram_username ?? null,
|
|
564
|
+
bot_username: row.bot_username ?? null,
|
|
565
|
+
...(row.joined_at ? { joined_at: String(row.joined_at) } : {}),
|
|
566
|
+
...(row.updated_at ? { updated_at: String(row.updated_at) } : {}),
|
|
567
|
+
})),
|
|
568
|
+
};
|
|
569
|
+
},
|
|
570
|
+
async sendPartnerNoteRecord(input) {
|
|
571
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
572
|
+
const localSessionId = this.requireText?.(input.session_id, "session_id");
|
|
573
|
+
const targetSessionId = this.requireText?.(input.target_session_id, "target_session_id");
|
|
574
|
+
const requestedProjectUuid = this.normalizeOptionalText?.(input.project_uuid);
|
|
575
|
+
const kind = this.requireText?.(input.kind, "kind");
|
|
576
|
+
const summary = this.requireText?.(input.summary, "summary");
|
|
577
|
+
const message = this.requireText?.(input.message, "message");
|
|
578
|
+
const expectedReply = this.normalizeOptionalText?.(input.expected_reply);
|
|
579
|
+
const inReplyTo = this.normalizeOptionalText?.(input.in_reply_to);
|
|
580
|
+
const requiresReply = typeof input.requires_reply === "boolean"
|
|
581
|
+
? input.requires_reply
|
|
582
|
+
: kind === "question" || kind === "request";
|
|
583
|
+
const targetSession = await this.db
|
|
584
|
+
.withSchema(MCP_SCHEMA)
|
|
585
|
+
.table("gateway_sessions as s")
|
|
586
|
+
.leftJoin("gateway_clients as c", "c.client_uuid", "s.client_uuid")
|
|
587
|
+
.leftJoin("gateway_projects as p", "p.project_uuid", "s.project_uuid")
|
|
588
|
+
.where({
|
|
589
|
+
"s.session_uuid": targetSessionId,
|
|
590
|
+
"s.status": "active",
|
|
591
|
+
})
|
|
592
|
+
.select("s.*", "p.name as project_name", this.db.raw("coalesce(nullif(c.meta->>'telegram_display_name', ''), nullif(c.meta->>'telegram_username', ''), c.client_label, c.bot_username) as target_actor_label"))
|
|
593
|
+
.first();
|
|
594
|
+
if (!targetSession) {
|
|
595
|
+
throw new Error(`Target project session ${targetSessionId} was not found.`);
|
|
596
|
+
}
|
|
597
|
+
if (requestedProjectUuid &&
|
|
598
|
+
requestedProjectUuid !== String(targetSession.project_uuid)) {
|
|
599
|
+
throw new Error("Target session does not belong to the requested project.");
|
|
600
|
+
}
|
|
601
|
+
const sourceSession = await this.db
|
|
602
|
+
.withSchema(MCP_SCHEMA)
|
|
603
|
+
.table("gateway_sessions")
|
|
604
|
+
.where({
|
|
605
|
+
project_uuid: String(targetSession.project_uuid),
|
|
606
|
+
client_uuid: clientUuid,
|
|
607
|
+
local_session_id: localSessionId,
|
|
608
|
+
status: "active",
|
|
609
|
+
})
|
|
610
|
+
.first();
|
|
611
|
+
if (!sourceSession) {
|
|
612
|
+
throw new Error(`Active project session '${localSessionId}' is not registered for client ${clientUuid} in project ${targetSession.project_uuid}.`);
|
|
613
|
+
}
|
|
614
|
+
const shareId = (0, node_crypto_1.randomUUID)();
|
|
615
|
+
const messageUuid = (0, node_crypto_1.randomUUID)();
|
|
616
|
+
const deliveryUuid = (0, node_crypto_1.randomUUID)();
|
|
617
|
+
const now = new Date().toISOString();
|
|
618
|
+
const resolvedInReplyTo = await (0, gatewayReplyResolution_1.resolveGatewayInReplyTo)(inReplyTo ?? undefined, {
|
|
619
|
+
findMessageUuidByMessageUuid: async (messageUuid) => {
|
|
620
|
+
const directReplyTarget = await this.db
|
|
621
|
+
.withSchema(MCP_SCHEMA)
|
|
622
|
+
.table("gateway_messages")
|
|
623
|
+
.where({ message_uuid: messageUuid })
|
|
624
|
+
.select("message_uuid")
|
|
625
|
+
.first();
|
|
626
|
+
return directReplyTarget?.message_uuid
|
|
627
|
+
? String(directReplyTarget.message_uuid)
|
|
628
|
+
: undefined;
|
|
629
|
+
},
|
|
630
|
+
findMessageUuidByShareId: async (shareId) => {
|
|
631
|
+
const shareReplyTarget = await this.db
|
|
632
|
+
.withSchema(MCP_SCHEMA)
|
|
633
|
+
.table("gateway_messages")
|
|
634
|
+
.whereRaw("meta->>'share_id' = ?", [shareId])
|
|
635
|
+
.select("message_uuid")
|
|
636
|
+
.orderBy("created_at", "desc")
|
|
637
|
+
.first();
|
|
638
|
+
return shareReplyTarget?.message_uuid
|
|
639
|
+
? String(shareReplyTarget.message_uuid)
|
|
640
|
+
: undefined;
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_messages").insert({
|
|
644
|
+
message_uuid: messageUuid,
|
|
645
|
+
project_uuid: sourceSession.project_uuid,
|
|
646
|
+
from_session_uuid: sourceSession.session_uuid,
|
|
647
|
+
to_session_uuid: targetSession.session_uuid,
|
|
648
|
+
kind,
|
|
649
|
+
summary,
|
|
650
|
+
body: message,
|
|
651
|
+
...(expectedReply ? { expected_reply: expectedReply } : {}),
|
|
652
|
+
...(resolvedInReplyTo ? { in_reply_to: resolvedInReplyTo } : {}),
|
|
653
|
+
requires_reply: requiresReply,
|
|
654
|
+
meta: this.db.raw(`?::jsonb`, [JSON.stringify({ share_id: shareId })]),
|
|
655
|
+
created_at: now,
|
|
656
|
+
});
|
|
657
|
+
const artifactRefs = Array.isArray(input.artifact_refs)
|
|
658
|
+
? input.artifact_refs
|
|
659
|
+
: [];
|
|
660
|
+
const usedArtifactNames = new Set();
|
|
661
|
+
const queuedArtifacts = [];
|
|
662
|
+
for (const artifact of artifactRefs) {
|
|
663
|
+
const originalName = trimOptionalText(artifact.original_name) ||
|
|
664
|
+
trimOptionalText(artifact.relative_path) ||
|
|
665
|
+
trimOptionalText(artifact.file_path) ||
|
|
666
|
+
"file";
|
|
667
|
+
const relativePath = allocateArtifactRelativePath(shareId, node_path_1.default.basename(originalName), usedArtifactNames);
|
|
668
|
+
const mimeType = trimOptionalText(artifact.mime_type) ?? undefined;
|
|
669
|
+
const storageRef = trimOptionalText(artifact.storage_ref) ?? undefined;
|
|
670
|
+
const contentBase64 = trimOptionalText(artifact.content_base64) ?? undefined;
|
|
671
|
+
const queuedArtifact = {
|
|
672
|
+
artifact_uuid: (0, node_crypto_1.randomUUID)(),
|
|
673
|
+
original_name: node_path_1.default.basename(originalName),
|
|
674
|
+
...(mimeType ? { mime_type: mimeType } : {}),
|
|
675
|
+
...(typeof artifact.size_bytes === "number"
|
|
676
|
+
? { size_bytes: artifact.size_bytes }
|
|
677
|
+
: {}),
|
|
678
|
+
...(storageRef ? { storage_ref: storageRef } : {}),
|
|
679
|
+
relative_path: relativePath,
|
|
680
|
+
...(contentBase64 ? { content_base64: contentBase64 } : {}),
|
|
681
|
+
};
|
|
682
|
+
queuedArtifacts.push(queuedArtifact);
|
|
683
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_message_artifacts").insert({
|
|
684
|
+
artifact_uuid: queuedArtifact.artifact_uuid,
|
|
685
|
+
message_uuid: messageUuid,
|
|
686
|
+
original_name: queuedArtifact.original_name,
|
|
687
|
+
...(queuedArtifact.mime_type
|
|
688
|
+
? { mime_type: queuedArtifact.mime_type }
|
|
689
|
+
: {}),
|
|
690
|
+
...(typeof queuedArtifact.size_bytes === "number"
|
|
691
|
+
? { size_bytes: queuedArtifact.size_bytes }
|
|
692
|
+
: {}),
|
|
693
|
+
...(queuedArtifact.storage_ref
|
|
694
|
+
? { storage_ref: queuedArtifact.storage_ref }
|
|
695
|
+
: {}),
|
|
696
|
+
relative_path: relativePath,
|
|
697
|
+
meta: this.db.raw(`?::jsonb`, [
|
|
698
|
+
JSON.stringify({
|
|
699
|
+
file_path: trimOptionalText(artifact.file_path),
|
|
700
|
+
relative_path: trimOptionalText(artifact.relative_path),
|
|
701
|
+
content_base64: trimOptionalText(artifact.content_base64),
|
|
702
|
+
}),
|
|
703
|
+
]),
|
|
704
|
+
created_at: now,
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
await this.db.withSchema(MCP_SCHEMA).table("gateway_deliveries").insert({
|
|
708
|
+
delivery_uuid: deliveryUuid,
|
|
709
|
+
message_uuid: messageUuid,
|
|
710
|
+
target_client_uuid: targetSession.client_uuid,
|
|
711
|
+
target_session_uuid: targetSession.session_uuid,
|
|
712
|
+
status: "queued",
|
|
713
|
+
attempt_count: 0,
|
|
714
|
+
available_at: now,
|
|
715
|
+
created_at: now,
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
session_id: localSessionId,
|
|
719
|
+
partner_session_id: targetSession.session_uuid,
|
|
720
|
+
...(targetSession.project_name
|
|
721
|
+
? { project_name: targetSession.project_name }
|
|
722
|
+
: {}),
|
|
723
|
+
...(targetSession.target_actor_label
|
|
724
|
+
? { target_actor_label: targetSession.target_actor_label }
|
|
725
|
+
: {}),
|
|
726
|
+
...(targetSession.label
|
|
727
|
+
? { target_session_label: targetSession.label }
|
|
728
|
+
: {}),
|
|
729
|
+
kind: kind,
|
|
730
|
+
share_id: shareId,
|
|
731
|
+
delivery_status: "queued",
|
|
732
|
+
note_path: `gateway://shares/${shareId}.md`,
|
|
733
|
+
share_index_path: "gateway://SHARED_INDEX.md",
|
|
734
|
+
copied_artifacts: artifactRefs.map((artifact) => trimOptionalText(artifact.original_name) ||
|
|
735
|
+
trimOptionalText(artifact.relative_path) ||
|
|
736
|
+
trimOptionalText(artifact.file_path) ||
|
|
737
|
+
"file"),
|
|
738
|
+
inbox_message_id: deliveryUuid,
|
|
739
|
+
requires_reply: requiresReply,
|
|
740
|
+
delivery_uuid: deliveryUuid,
|
|
741
|
+
target_client_uuid: targetSession.client_uuid,
|
|
742
|
+
delivery: {
|
|
743
|
+
delivery_uuid: deliveryUuid,
|
|
744
|
+
message_uuid: messageUuid,
|
|
745
|
+
share_id: shareId,
|
|
746
|
+
...(targetSession.project_name
|
|
747
|
+
? { project_name: targetSession.project_name }
|
|
748
|
+
: {}),
|
|
749
|
+
source_actor_label: sourceSession.label ?? sourceSession.local_session_id,
|
|
750
|
+
kind,
|
|
751
|
+
summary,
|
|
752
|
+
message,
|
|
753
|
+
...(expectedReply ? { expected_reply: expectedReply } : {}),
|
|
754
|
+
requires_reply: requiresReply,
|
|
755
|
+
...(resolvedInReplyTo ? { in_reply_to: resolvedInReplyTo } : {}),
|
|
756
|
+
source_session_uuid: sourceSession.session_uuid,
|
|
757
|
+
source_session_label: sourceSession.label ?? sourceSession.local_session_id,
|
|
758
|
+
source_local_session_id: sourceSession.local_session_id,
|
|
759
|
+
target_session_uuid: targetSession.session_uuid,
|
|
760
|
+
target_local_session_id: targetSession.local_session_id,
|
|
761
|
+
target_session_label: targetSession.label ?? targetSession.local_session_id,
|
|
762
|
+
created_at: now,
|
|
763
|
+
note_relative_path: `shares/${shareId}.md`,
|
|
764
|
+
share_index_file_name: "SHARED_INDEX.md",
|
|
765
|
+
artifacts: queuedArtifacts,
|
|
766
|
+
},
|
|
767
|
+
};
|
|
768
|
+
},
|
|
769
|
+
async pollDeliveriesRecord(input) {
|
|
770
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
771
|
+
const limit = typeof input.limit === "number" && Number.isFinite(input.limit)
|
|
772
|
+
? Math.max(1, Math.min(50, Math.trunc(input.limit)))
|
|
773
|
+
: 20;
|
|
774
|
+
const rows = await this.db
|
|
775
|
+
.withSchema(MCP_SCHEMA)
|
|
776
|
+
.table("gateway_deliveries as d")
|
|
777
|
+
.join("gateway_messages as m", "m.message_uuid", "d.message_uuid")
|
|
778
|
+
.join("gateway_projects as p", "p.project_uuid", "m.project_uuid")
|
|
779
|
+
.join("gateway_sessions as s_from", "s_from.session_uuid", "m.from_session_uuid")
|
|
780
|
+
.join("gateway_sessions as s_to", "s_to.session_uuid", "m.to_session_uuid")
|
|
781
|
+
.leftJoin("gateway_clients as c_from", "c_from.client_uuid", "s_from.client_uuid")
|
|
782
|
+
.where("d.target_client_uuid", clientUuid)
|
|
783
|
+
.where("d.status", "queued")
|
|
784
|
+
.where("d.available_at", "<=", this.db.fn.now())
|
|
785
|
+
.select("d.delivery_uuid", "d.message_uuid", "p.project_uuid", "m.kind", "m.summary", "m.body", "m.expected_reply", "m.requires_reply", "m.in_reply_to", "m.meta", "m.created_at", "p.name as project_name", this.db.raw("coalesce(nullif(c_from.meta->>'telegram_display_name', ''), nullif(c_from.meta->>'telegram_username', ''), c_from.client_label, c_from.bot_username) as source_actor_label"), "s_from.session_uuid as source_session_uuid", "s_from.local_session_id as source_local_session_id", "s_from.label as source_session_label", "s_to.session_uuid as target_session_uuid", "s_to.local_session_id as target_local_session_id", "s_to.label as target_session_label")
|
|
786
|
+
.orderBy("m.created_at", "asc")
|
|
787
|
+
.limit(limit);
|
|
788
|
+
const messageIds = rows.map((row) => row.message_uuid);
|
|
789
|
+
const artifactRows = messageIds.length
|
|
790
|
+
? await this.db
|
|
791
|
+
.withSchema(MCP_SCHEMA)
|
|
792
|
+
.table("gateway_message_artifacts")
|
|
793
|
+
.whereIn("message_uuid", messageIds)
|
|
794
|
+
.select("artifact_uuid", "message_uuid", "original_name", "mime_type", "size_bytes", "storage_ref", "relative_path", "meta")
|
|
795
|
+
.orderBy("created_at", "asc")
|
|
796
|
+
: [];
|
|
797
|
+
const artifactsByMessage = new Map();
|
|
798
|
+
for (const artifact of artifactRows) {
|
|
799
|
+
const meta = artifact.meta && typeof artifact.meta === "object" ? artifact.meta : {};
|
|
800
|
+
const list = artifactsByMessage.get(artifact.message_uuid) ?? [];
|
|
801
|
+
list.push({
|
|
802
|
+
artifact_uuid: artifact.artifact_uuid,
|
|
803
|
+
original_name: artifact.original_name,
|
|
804
|
+
...(artifact.mime_type ? { mime_type: artifact.mime_type } : {}),
|
|
805
|
+
...(typeof artifact.size_bytes === "number"
|
|
806
|
+
? { size_bytes: Number(artifact.size_bytes) }
|
|
807
|
+
: {}),
|
|
808
|
+
...(artifact.storage_ref ? { storage_ref: artifact.storage_ref } : {}),
|
|
809
|
+
...(artifact.relative_path ? { relative_path: artifact.relative_path } : {}),
|
|
810
|
+
...(typeof meta.content_base64 === "string"
|
|
811
|
+
? {
|
|
812
|
+
content_base64: meta.content_base64,
|
|
813
|
+
}
|
|
814
|
+
: {}),
|
|
815
|
+
});
|
|
816
|
+
artifactsByMessage.set(artifact.message_uuid, list);
|
|
817
|
+
}
|
|
818
|
+
return {
|
|
819
|
+
deliveries: rows.map((row) => {
|
|
820
|
+
const meta = row.meta && typeof row.meta === "object" ? row.meta : {};
|
|
821
|
+
const shareId = typeof meta.share_id === "string"
|
|
822
|
+
? meta.share_id
|
|
823
|
+
: row.message_uuid;
|
|
824
|
+
return {
|
|
825
|
+
delivery_uuid: row.delivery_uuid,
|
|
826
|
+
message_uuid: row.message_uuid,
|
|
827
|
+
share_id: shareId,
|
|
828
|
+
...(row.project_uuid ? { project_uuid: row.project_uuid } : {}),
|
|
829
|
+
...(row.project_name ? { project_name: row.project_name } : {}),
|
|
830
|
+
...(row.source_actor_label
|
|
831
|
+
? { source_actor_label: row.source_actor_label }
|
|
832
|
+
: {}),
|
|
833
|
+
kind: row.kind,
|
|
834
|
+
summary: row.summary,
|
|
835
|
+
message: row.body,
|
|
836
|
+
...(row.expected_reply ? { expected_reply: row.expected_reply } : {}),
|
|
837
|
+
requires_reply: Boolean(row.requires_reply),
|
|
838
|
+
...(row.in_reply_to ? { in_reply_to: row.in_reply_to } : {}),
|
|
839
|
+
source_session_uuid: row.source_session_uuid,
|
|
840
|
+
source_session_label: row.source_session_label ?? row.source_local_session_id,
|
|
841
|
+
source_local_session_id: row.source_local_session_id,
|
|
842
|
+
target_session_uuid: row.target_session_uuid,
|
|
843
|
+
target_local_session_id: row.target_local_session_id,
|
|
844
|
+
target_session_label: row.target_session_label ?? row.target_local_session_id,
|
|
845
|
+
created_at: String(row.created_at),
|
|
846
|
+
note_relative_path: `shares/${shareId}.md`,
|
|
847
|
+
share_index_file_name: "SHARED_INDEX.md",
|
|
848
|
+
artifacts: artifactsByMessage.get(row.message_uuid) ?? [],
|
|
849
|
+
};
|
|
850
|
+
}),
|
|
851
|
+
};
|
|
852
|
+
},
|
|
853
|
+
async ackDeliveriesRecord(input) {
|
|
854
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
855
|
+
const deliveryIds = Array.isArray(input.delivery_ids)
|
|
856
|
+
? input.delivery_ids
|
|
857
|
+
.map((item) => this.normalizeOptionalText?.(item))
|
|
858
|
+
.filter((item) => Boolean(item))
|
|
859
|
+
: [];
|
|
860
|
+
if (deliveryIds.length === 0) {
|
|
861
|
+
throw new Error("delivery_ids must contain at least one id");
|
|
862
|
+
}
|
|
863
|
+
const rows = await this.db
|
|
864
|
+
.withSchema(MCP_SCHEMA)
|
|
865
|
+
.table("gateway_deliveries as d")
|
|
866
|
+
.join("gateway_messages as m", "m.message_uuid", "d.message_uuid")
|
|
867
|
+
.join("gateway_sessions as s_from", "s_from.session_uuid", "m.from_session_uuid")
|
|
868
|
+
.where("d.target_client_uuid", clientUuid)
|
|
869
|
+
.whereIn("d.delivery_uuid", deliveryIds)
|
|
870
|
+
.select("d.delivery_uuid", "d.delivered_at", "d.acked_at", "s_from.client_uuid as source_client_uuid", this.db.raw(`coalesce(m.meta->>'share_id', '') as share_id`));
|
|
871
|
+
const updated = await this.db
|
|
872
|
+
.withSchema(MCP_SCHEMA)
|
|
873
|
+
.table("gateway_deliveries")
|
|
874
|
+
.where("target_client_uuid", clientUuid)
|
|
875
|
+
.whereIn("delivery_uuid", deliveryIds)
|
|
876
|
+
.update({
|
|
877
|
+
status: "delivered",
|
|
878
|
+
acked_at: new Date().toISOString(),
|
|
879
|
+
});
|
|
880
|
+
return {
|
|
881
|
+
acked: updated,
|
|
882
|
+
deliveries: rows.map((row) => ({
|
|
883
|
+
delivery_uuid: row.delivery_uuid,
|
|
884
|
+
share_id: String(row.share_id || ""),
|
|
885
|
+
status: "delivered",
|
|
886
|
+
source_client_uuid: row.source_client_uuid,
|
|
887
|
+
...(row.delivered_at ? { delivered_at: String(row.delivered_at) } : {}),
|
|
888
|
+
acked_at: new Date().toISOString(),
|
|
889
|
+
})),
|
|
890
|
+
};
|
|
891
|
+
},
|
|
892
|
+
async failDeliveriesRecord(input) {
|
|
893
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
894
|
+
const deliveryIds = Array.isArray(input.delivery_ids)
|
|
895
|
+
? input.delivery_ids
|
|
896
|
+
.map((item) => this.normalizeOptionalText?.(item))
|
|
897
|
+
.filter((item) => Boolean(item))
|
|
898
|
+
: [];
|
|
899
|
+
const errorText = this.normalizeOptionalText?.(input.error_text);
|
|
900
|
+
if (deliveryIds.length === 0) {
|
|
901
|
+
throw new Error("delivery_ids must contain at least one id");
|
|
902
|
+
}
|
|
903
|
+
const rows = await this.db
|
|
904
|
+
.withSchema(MCP_SCHEMA)
|
|
905
|
+
.table("gateway_deliveries as d")
|
|
906
|
+
.join("gateway_messages as m", "m.message_uuid", "d.message_uuid")
|
|
907
|
+
.join("gateway_sessions as s_from", "s_from.session_uuid", "m.from_session_uuid")
|
|
908
|
+
.where("d.target_client_uuid", clientUuid)
|
|
909
|
+
.whereIn("d.delivery_uuid", deliveryIds)
|
|
910
|
+
.select("d.delivery_uuid", "d.delivered_at", "d.acked_at", "s_from.client_uuid as source_client_uuid", this.db.raw(`coalesce(m.meta->>'share_id', '') as share_id`));
|
|
911
|
+
const updated = await this.db
|
|
912
|
+
.withSchema(MCP_SCHEMA)
|
|
913
|
+
.table("gateway_deliveries")
|
|
914
|
+
.where("target_client_uuid", clientUuid)
|
|
915
|
+
.whereIn("delivery_uuid", deliveryIds)
|
|
916
|
+
.update({
|
|
917
|
+
status: "failed",
|
|
918
|
+
...(errorText ? { last_error: errorText } : {}),
|
|
919
|
+
acked_at: new Date().toISOString(),
|
|
920
|
+
});
|
|
921
|
+
return {
|
|
922
|
+
failed: updated,
|
|
923
|
+
deliveries: rows.map((row) => ({
|
|
924
|
+
delivery_uuid: row.delivery_uuid,
|
|
925
|
+
share_id: String(row.share_id || ""),
|
|
926
|
+
status: "failed",
|
|
927
|
+
source_client_uuid: row.source_client_uuid,
|
|
928
|
+
...(row.delivered_at ? { delivered_at: String(row.delivered_at) } : {}),
|
|
929
|
+
acked_at: new Date().toISOString(),
|
|
930
|
+
})),
|
|
931
|
+
};
|
|
932
|
+
},
|
|
933
|
+
async listSenderDeliveryStatusesRecord(input) {
|
|
934
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
935
|
+
const limit = typeof input.limit === "number" && Number.isFinite(input.limit)
|
|
936
|
+
? Math.max(1, Math.min(200, Math.trunc(input.limit)))
|
|
937
|
+
: 100;
|
|
938
|
+
const rows = await this.db
|
|
939
|
+
.withSchema(MCP_SCHEMA)
|
|
940
|
+
.table("gateway_deliveries as d")
|
|
941
|
+
.join("gateway_messages as m", "m.message_uuid", "d.message_uuid")
|
|
942
|
+
.join("gateway_sessions as s_from", "s_from.session_uuid", "m.from_session_uuid")
|
|
943
|
+
.where("s_from.client_uuid", clientUuid)
|
|
944
|
+
.whereIn("d.status", ["delivered", "failed"])
|
|
945
|
+
.select("d.delivery_uuid", "d.status", "d.delivered_at", "d.acked_at", this.db.raw(`coalesce(m.meta->>'share_id', '') as share_id`))
|
|
946
|
+
.orderBy("d.acked_at", "desc")
|
|
947
|
+
.limit(limit);
|
|
948
|
+
return {
|
|
949
|
+
deliveries: rows.map((row) => ({
|
|
950
|
+
delivery_uuid: row.delivery_uuid,
|
|
951
|
+
share_id: String(row.share_id || ""),
|
|
952
|
+
status: row.status,
|
|
953
|
+
...(row.delivered_at ? { delivered_at: String(row.delivered_at) } : {}),
|
|
954
|
+
...(row.acked_at ? { acked_at: String(row.acked_at) } : {}),
|
|
955
|
+
})),
|
|
956
|
+
};
|
|
957
|
+
},
|
|
958
|
+
async listSessionHistoryRecord(input) {
|
|
959
|
+
const clientUuid = this.requireText?.(input.client_uuid, "client_uuid");
|
|
960
|
+
const localSessionId = this.requireText?.(input.local_session_id, "local_session_id");
|
|
961
|
+
const limit = typeof input.limit === "number" && Number.isFinite(input.limit)
|
|
962
|
+
? Math.max(1, Math.min(20, Math.trunc(input.limit)))
|
|
963
|
+
: 5;
|
|
964
|
+
const sessionRows = await this.db
|
|
965
|
+
.withSchema(MCP_SCHEMA)
|
|
966
|
+
.table("gateway_sessions")
|
|
967
|
+
.where({
|
|
968
|
+
client_uuid: clientUuid,
|
|
969
|
+
local_session_id: localSessionId,
|
|
970
|
+
status: "active",
|
|
971
|
+
})
|
|
972
|
+
.select("session_uuid");
|
|
973
|
+
const sessionUuids = sessionRows
|
|
974
|
+
.map((row) => this.normalizeOptionalText?.(row.session_uuid))
|
|
975
|
+
.filter((row) => Boolean(row));
|
|
976
|
+
if (sessionUuids.length === 0) {
|
|
977
|
+
return { history: [] };
|
|
978
|
+
}
|
|
979
|
+
const rows = await this.db
|
|
980
|
+
.withSchema(MCP_SCHEMA)
|
|
981
|
+
.table("gateway_messages as m")
|
|
982
|
+
.join("gateway_sessions as s_from", "s_from.session_uuid", "m.from_session_uuid")
|
|
983
|
+
.join("gateway_sessions as s_to", "s_to.session_uuid", "m.to_session_uuid")
|
|
984
|
+
.leftJoin("gateway_projects as p", "p.project_uuid", "m.project_uuid")
|
|
985
|
+
.leftJoin("gateway_deliveries as d", "d.message_uuid", "m.message_uuid")
|
|
986
|
+
.where((builder) => {
|
|
987
|
+
builder
|
|
988
|
+
.whereIn("m.from_session_uuid", sessionUuids)
|
|
989
|
+
.orWhereIn("m.to_session_uuid", sessionUuids);
|
|
990
|
+
})
|
|
991
|
+
.select("m.message_uuid", "m.kind", "m.summary", "m.created_at", "p.project_uuid", "p.name as project_name", "s_from.session_uuid as from_session_uuid", "s_from.local_session_id as from_local_session_id", "s_from.label as from_session_label", "s_to.session_uuid as to_session_uuid", "s_to.local_session_id as to_local_session_id", "s_to.label as to_session_label", "d.status as delivery_status")
|
|
992
|
+
.orderBy("m.created_at", "desc")
|
|
993
|
+
.limit(limit);
|
|
994
|
+
const currentSessionSet = new Set(sessionUuids);
|
|
995
|
+
return {
|
|
996
|
+
history: rows.map((row) => {
|
|
997
|
+
const outgoing = currentSessionSet.has(String(row.from_session_uuid));
|
|
998
|
+
return {
|
|
999
|
+
message_uuid: String(row.message_uuid),
|
|
1000
|
+
kind: String(row.kind),
|
|
1001
|
+
summary: String(row.summary || ""),
|
|
1002
|
+
created_at: String(row.created_at),
|
|
1003
|
+
direction: outgoing ? "outgoing" : "incoming",
|
|
1004
|
+
...(row.project_uuid ? { project_uuid: String(row.project_uuid) } : {}),
|
|
1005
|
+
...(row.project_name ? { project_name: String(row.project_name) } : {}),
|
|
1006
|
+
from_session_id: String(row.from_local_session_id),
|
|
1007
|
+
from_label: String(row.from_session_label || row.from_local_session_id),
|
|
1008
|
+
to_session_id: String(row.to_local_session_id),
|
|
1009
|
+
to_label: String(row.to_session_label || row.to_local_session_id),
|
|
1010
|
+
...(row.delivery_status
|
|
1011
|
+
? { delivery_status: String(row.delivery_status) }
|
|
1012
|
+
: {}),
|
|
1013
|
+
};
|
|
1014
|
+
}),
|
|
1015
|
+
};
|
|
1016
|
+
},
|
|
1017
|
+
},
|
|
1018
|
+
actions: {
|
|
1019
|
+
registerClient: {
|
|
1020
|
+
async handler(ctx) {
|
|
1021
|
+
if (!GATEWAY_ENABLED) {
|
|
1022
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1023
|
+
}
|
|
1024
|
+
return this.registerClientRecord?.(ctx.params);
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
createProject: {
|
|
1028
|
+
async handler(ctx) {
|
|
1029
|
+
if (!GATEWAY_ENABLED) {
|
|
1030
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1031
|
+
}
|
|
1032
|
+
return this.createProjectRecord?.(ctx.params);
|
|
1033
|
+
},
|
|
1034
|
+
},
|
|
1035
|
+
joinProject: {
|
|
1036
|
+
async handler(ctx) {
|
|
1037
|
+
if (!GATEWAY_ENABLED) {
|
|
1038
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1039
|
+
}
|
|
1040
|
+
return this.joinProjectRecord?.(ctx.params);
|
|
1041
|
+
},
|
|
1042
|
+
},
|
|
1043
|
+
registerSession: {
|
|
1044
|
+
async handler(ctx) {
|
|
1045
|
+
if (!GATEWAY_ENABLED) {
|
|
1046
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1047
|
+
}
|
|
1048
|
+
return this.registerSessionRecord?.(ctx.params);
|
|
1049
|
+
},
|
|
1050
|
+
},
|
|
1051
|
+
unregisterSession: {
|
|
1052
|
+
async handler(ctx) {
|
|
1053
|
+
if (!GATEWAY_ENABLED) {
|
|
1054
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1055
|
+
}
|
|
1056
|
+
return this.unregisterSessionRecord?.(ctx.params);
|
|
1057
|
+
},
|
|
1058
|
+
},
|
|
1059
|
+
listProjects: {
|
|
1060
|
+
async handler(ctx) {
|
|
1061
|
+
if (!GATEWAY_ENABLED) {
|
|
1062
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1063
|
+
}
|
|
1064
|
+
return this.listProjectsRecord?.(ctx.params);
|
|
1065
|
+
},
|
|
1066
|
+
},
|
|
1067
|
+
leaveProject: {
|
|
1068
|
+
async handler(ctx) {
|
|
1069
|
+
if (!GATEWAY_ENABLED) {
|
|
1070
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1071
|
+
}
|
|
1072
|
+
return this.leaveProjectRecord?.(ctx.params);
|
|
1073
|
+
},
|
|
1074
|
+
},
|
|
1075
|
+
deleteProject: {
|
|
1076
|
+
async handler(ctx) {
|
|
1077
|
+
if (!GATEWAY_ENABLED) {
|
|
1078
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1079
|
+
}
|
|
1080
|
+
return this.deleteProjectRecord?.(ctx.params);
|
|
1081
|
+
},
|
|
1082
|
+
},
|
|
1083
|
+
listProjectSessions: {
|
|
1084
|
+
async handler(ctx) {
|
|
1085
|
+
if (!GATEWAY_ENABLED) {
|
|
1086
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1087
|
+
}
|
|
1088
|
+
return this.listProjectSessionsRecord?.(ctx.params);
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
listSessionHistory: {
|
|
1092
|
+
async handler(ctx) {
|
|
1093
|
+
if (!GATEWAY_ENABLED) {
|
|
1094
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1095
|
+
}
|
|
1096
|
+
return this.listSessionHistoryRecord?.(ctx.params);
|
|
1097
|
+
},
|
|
1098
|
+
},
|
|
1099
|
+
sendPartnerNote: {
|
|
1100
|
+
async handler(ctx) {
|
|
1101
|
+
if (!GATEWAY_ENABLED) {
|
|
1102
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1103
|
+
}
|
|
1104
|
+
return this.sendPartnerNoteRecord?.(ctx.params);
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
pollDeliveries: {
|
|
1108
|
+
async handler(ctx) {
|
|
1109
|
+
if (!GATEWAY_ENABLED) {
|
|
1110
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1111
|
+
}
|
|
1112
|
+
return this.pollDeliveriesRecord?.(ctx.params);
|
|
1113
|
+
},
|
|
1114
|
+
},
|
|
1115
|
+
ackDeliveries: {
|
|
1116
|
+
async handler(ctx) {
|
|
1117
|
+
if (!GATEWAY_ENABLED) {
|
|
1118
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1119
|
+
}
|
|
1120
|
+
return this.ackDeliveriesRecord?.(ctx.params);
|
|
1121
|
+
},
|
|
1122
|
+
},
|
|
1123
|
+
failDeliveries: {
|
|
1124
|
+
async handler(ctx) {
|
|
1125
|
+
if (!GATEWAY_ENABLED) {
|
|
1126
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1127
|
+
}
|
|
1128
|
+
return this.failDeliveriesRecord?.(ctx.params);
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
listSenderDeliveryStatuses: {
|
|
1132
|
+
async handler(ctx) {
|
|
1133
|
+
if (!GATEWAY_ENABLED) {
|
|
1134
|
+
throw new Error("Gateway service is disabled in client mode");
|
|
1135
|
+
}
|
|
1136
|
+
return this.listSenderDeliveryStatusesRecord?.(ctx.params);
|
|
1137
|
+
},
|
|
1138
|
+
},
|
|
1139
|
+
},
|
|
1140
|
+
};
|
|
1141
|
+
exports.default = TelegramMcpGatewayService;
|