@linkshell/gateway 0.1.0

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/Dockerfile ADDED
@@ -0,0 +1,37 @@
1
+ FROM node:22-alpine AS builder
2
+
3
+ RUN corepack enable && corepack prepare pnpm@10.18.3 --activate
4
+
5
+ WORKDIR /app
6
+ COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
7
+ COPY packages/shared-protocol/package.json packages/shared-protocol/
8
+ COPY packages/gateway/package.json packages/gateway/
9
+
10
+ RUN pnpm install --frozen-lockfile --filter @linkshell/gateway --filter @linkshell/protocol
11
+
12
+ COPY packages/shared-protocol/ packages/shared-protocol/
13
+ COPY packages/gateway/ packages/gateway/
14
+ COPY tsconfig.base.json ./
15
+
16
+ RUN pnpm --filter @linkshell/protocol build && pnpm --filter @linkshell/gateway build
17
+
18
+ # ── Runtime ──────────────────────────────────────────────────────────
19
+
20
+ FROM node:22-alpine
21
+
22
+ RUN corepack enable && corepack prepare pnpm@10.18.3 --activate
23
+
24
+ WORKDIR /app
25
+ COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
26
+ COPY packages/shared-protocol/package.json packages/shared-protocol/
27
+ COPY packages/gateway/package.json packages/gateway/
28
+
29
+ RUN pnpm install --frozen-lockfile --filter @linkshell/gateway --filter @linkshell/protocol --prod
30
+
31
+ COPY --from=builder /app/packages/shared-protocol/dist packages/shared-protocol/dist
32
+ COPY --from=builder /app/packages/gateway/dist packages/gateway/dist
33
+
34
+ ENV PORT=8787
35
+ EXPOSE 8787
36
+
37
+ CMD ["node", "packages/gateway/dist/gateway/src/index.js"]
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LinkShell Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @linkshell/gateway
2
+
3
+ LinkShell Gateway — WebSocket 消息中转服务,连接 CLI 和手机 App。
4
+
5
+ Gateway 不运行任何终端进程,只负责配对、会话管理和消息路由。
6
+
7
+ ## 部署
8
+
9
+ ### Docker(推荐)
10
+
11
+ ```bash
12
+ docker compose up -d
13
+ ```
14
+
15
+ ### 直接运行
16
+
17
+ ```bash
18
+ pnpm install
19
+ pnpm --filter @linkshell/gateway build
20
+ PORT=8787 node packages/gateway/dist/gateway/src/index.js
21
+ ```
22
+
23
+ ## 环境变量
24
+
25
+ | 变量 | 默认值 | 说明 |
26
+ |------|--------|------|
27
+ | `PORT` | `8787` | 监听端口 |
28
+ | `LOG_LEVEL` | `info` | 日志级别:debug / info / warn / error |
29
+
30
+ ## API
31
+
32
+ | 方法 | 路径 | 说明 |
33
+ |------|------|------|
34
+ | `GET` | `/healthz` | 健康检查 |
35
+ | `POST` | `/pairings` | 创建配对(返回 6 位 code,10 分钟有效) |
36
+ | `POST` | `/pairings/claim` | 用 code 换取 sessionId |
37
+ | `GET` | `/pairings/:code/status` | 查询配对状态 |
38
+ | `GET` | `/sessions` | 列出活跃会话 |
39
+ | `GET` | `/sessions/:id` | 会话详情 |
40
+ | `WS` | `/ws?sessionId=&role=` | 实时连接(role=host 或 client) |
41
+
42
+ ## 特性
43
+
44
+ - 内存态会话管理(无外部依赖)
45
+ - ACK 追踪 + 输出缓存(最近 200 条,client 重连时快速重放)
46
+ - 单设备控制权管理(claim/grant/reject/release)
47
+ - 心跳 ping/pong 检测死连接(20s 间隔)
48
+ - 会话 TTL(host 断开保留 60s,空闲 30min 清理)
49
+ - IP 限流(配对 30 req/min,WebSocket 20 conn/min)
50
+ - CORS 支持
51
+ - 协议版本协商
52
+ - 优雅关闭(SIGINT/SIGTERM)
53
+
54
+ ## 代码入口
55
+
56
+ 如果要继续改 Gateway,优先从这几个文件进入:
57
+
58
+ 1. src/index.ts
59
+ 2. src/pairings.ts
60
+ 3. src/sessions.ts
61
+ 4. src/relay.ts
62
+
63
+ ## License
64
+
65
+ MIT
@@ -0,0 +1,16 @@
1
+ export interface EmbeddedGatewayOptions {
2
+ port?: number;
3
+ logLevel?: "debug" | "info" | "warn" | "error";
4
+ silent?: boolean;
5
+ }
6
+ export interface EmbeddedGateway {
7
+ port: number;
8
+ httpUrl: string;
9
+ wsUrl: string;
10
+ close: () => Promise<void>;
11
+ }
12
+ /**
13
+ * Start an embedded gateway. Returns a handle to get URLs and close it.
14
+ * Used by CLI when no external --gateway is provided.
15
+ */
16
+ export declare function startEmbeddedGateway(options?: EmbeddedGatewayOptions): Promise<EmbeddedGateway>;
@@ -0,0 +1,239 @@
1
+ import { createServer } from "node:http";
2
+ import { randomUUID } from "node:crypto";
3
+ import { WebSocketServer } from "ws";
4
+ import { createEnvelope, serializeEnvelope, PROTOCOL_VERSION, } from "@linkshell/protocol";
5
+ import { z, ZodError } from "zod";
6
+ import { SessionManager } from "./sessions.js";
7
+ import { PairingManager } from "./pairings.js";
8
+ import { handleSocketMessage } from "./relay.js";
9
+ const PING_INTERVAL = 20_000;
10
+ const MAX_BODY_SIZE = 4096;
11
+ const MAX_WS_MESSAGE_SIZE = 64 * 1024;
12
+ const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
13
+ const createPairingBody = z.object({ sessionId: z.string().optional() });
14
+ const claimPairingBody = z.object({ pairingCode: z.string().length(6) });
15
+ class BodyTooLargeError extends Error {
16
+ }
17
+ function json(res, status, body) {
18
+ res.writeHead(status, {
19
+ "content-type": "application/json",
20
+ "access-control-allow-origin": "*",
21
+ "access-control-allow-methods": "GET, POST, OPTIONS",
22
+ "access-control-allow-headers": "Content-Type, Authorization",
23
+ });
24
+ res.end(JSON.stringify(body));
25
+ }
26
+ async function readJson(req) {
27
+ const chunks = [];
28
+ let size = 0;
29
+ for await (const chunk of req) {
30
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
31
+ size += buf.length;
32
+ if (size > MAX_BODY_SIZE)
33
+ throw new BodyTooLargeError();
34
+ chunks.push(buf);
35
+ }
36
+ if (chunks.length === 0)
37
+ return {};
38
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
39
+ }
40
+ function getClientIp(req) {
41
+ const forwarded = req.headers["x-forwarded-for"];
42
+ if (typeof forwarded === "string")
43
+ return forwarded.split(",")[0].trim();
44
+ return req.socket.remoteAddress ?? "unknown";
45
+ }
46
+ /**
47
+ * Start an embedded gateway. Returns a handle to get URLs and close it.
48
+ * Used by CLI when no external --gateway is provided.
49
+ */
50
+ export function startEmbeddedGateway(options = {}) {
51
+ const targetPort = options.port ?? 0; // 0 = random available port
52
+ const logLevel = options.logLevel ?? "warn";
53
+ const silent = options.silent ?? false;
54
+ function log(level, msg) {
55
+ if (silent)
56
+ return;
57
+ if (LOG_LEVELS[level] >= LOG_LEVELS[logLevel]) {
58
+ process.stderr.write(`[gateway:${level}] ${msg}\n`);
59
+ }
60
+ }
61
+ const sessionManager = new SessionManager();
62
+ const pairingManager = new PairingManager();
63
+ const server = createServer(async (req, res) => {
64
+ if (req.method === "OPTIONS") {
65
+ res.writeHead(204, {
66
+ "access-control-allow-origin": "*",
67
+ "access-control-allow-methods": "GET, POST, OPTIONS",
68
+ "access-control-allow-headers": "Content-Type, Authorization",
69
+ "access-control-max-age": "86400",
70
+ });
71
+ res.end();
72
+ return;
73
+ }
74
+ try {
75
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
76
+ const method = req.method ?? "GET";
77
+ if (method === "GET" && url.pathname === "/healthz") {
78
+ json(res, 200, { ok: true });
79
+ return;
80
+ }
81
+ if (method === "POST" && url.pathname === "/pairings") {
82
+ const body = createPairingBody.parse(await readJson(req));
83
+ const record = pairingManager.create(body.sessionId);
84
+ json(res, 201, {
85
+ sessionId: record.sessionId,
86
+ pairingCode: record.pairingCode,
87
+ expiresAt: new Date(record.expiresAt).toISOString(),
88
+ });
89
+ return;
90
+ }
91
+ if (method === "POST" && url.pathname === "/pairings/claim") {
92
+ const body = claimPairingBody.parse(await readJson(req));
93
+ const result = pairingManager.claim(body.pairingCode);
94
+ if ("error" in result) {
95
+ json(res, result.status, { error: result.error });
96
+ return;
97
+ }
98
+ json(res, 200, { sessionId: result.sessionId });
99
+ return;
100
+ }
101
+ if (method === "GET" && url.pathname === "/sessions") {
102
+ const sessions = sessionManager.listActive().map((s) => ({
103
+ id: s.id,
104
+ state: s.state,
105
+ hasHost: !!s.host,
106
+ clientCount: s.clients.size,
107
+ controllerId: s.controllerId ?? null,
108
+ lastActivity: s.lastActivity,
109
+ createdAt: s.createdAt,
110
+ provider: s.provider ?? null,
111
+ hostname: s.hostname ?? null,
112
+ }));
113
+ json(res, 200, { sessions });
114
+ return;
115
+ }
116
+ const sessionMatch = url.pathname.match(/^\/sessions\/([^/]+)$/);
117
+ if (method === "GET" && sessionMatch) {
118
+ const summary = sessionManager.getSummary(sessionMatch[1]);
119
+ if (!summary) {
120
+ json(res, 404, { error: "session_not_found" });
121
+ return;
122
+ }
123
+ json(res, 200, summary);
124
+ return;
125
+ }
126
+ const pairingMatch = url.pathname.match(/^\/pairings\/(\d{6})\/status$/);
127
+ if (method === "GET" && pairingMatch) {
128
+ const result = pairingManager.getStatus(pairingMatch[1]);
129
+ if ("error" in result) {
130
+ json(res, result.httpStatus, { error: result.error });
131
+ return;
132
+ }
133
+ json(res, 200, result);
134
+ return;
135
+ }
136
+ json(res, 404, { error: "not_found" });
137
+ }
138
+ catch (err) {
139
+ if (err instanceof ZodError) {
140
+ json(res, 400, { error: "invalid_message", message: err.errors[0]?.message ?? "Validation failed" });
141
+ }
142
+ else if (err instanceof BodyTooLargeError) {
143
+ json(res, 413, { error: "body_too_large", message: "Request body exceeds limit" });
144
+ }
145
+ else if (err instanceof SyntaxError) {
146
+ json(res, 400, { error: "invalid_json", message: "Malformed JSON" });
147
+ }
148
+ else {
149
+ log("error", `unhandled: ${err}`);
150
+ json(res, 500, { error: "internal_error", message: "Internal server error" });
151
+ }
152
+ }
153
+ });
154
+ const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_WS_MESSAGE_SIZE });
155
+ server.on("upgrade", (request, socket, head) => {
156
+ const url = new URL(request.url ?? "/", `http://${request.headers.host}`);
157
+ if (url.pathname !== "/ws") {
158
+ socket.destroy();
159
+ return;
160
+ }
161
+ wss.handleUpgrade(request, socket, head, (ws) => {
162
+ wss.emit("connection", ws, request, url);
163
+ });
164
+ });
165
+ wss.on("connection", (socket, _request, url) => {
166
+ const sessionId = url.searchParams.get("sessionId");
167
+ const role = url.searchParams.get("role");
168
+ if (!sessionId || !role || (role !== "host" && role !== "client")) {
169
+ socket.close(1008, "missing sessionId or role");
170
+ return;
171
+ }
172
+ const deviceId = url.searchParams.get("deviceId") ?? randomUUID();
173
+ const device = { socket, role, deviceId, connectedAt: Date.now() };
174
+ if (role === "host") {
175
+ const existingSession = sessionManager.get(sessionId);
176
+ const isReconnect = existingSession && existingSession.clients.size > 0 && existingSession.state === "host_disconnected";
177
+ sessionManager.setHost(sessionId, device);
178
+ if (isReconnect) {
179
+ const notification = serializeEnvelope(createEnvelope({ type: "session.host_reconnected", sessionId, payload: {} }));
180
+ for (const [, client] of existingSession.clients) {
181
+ if (client.socket.readyState === client.socket.OPEN)
182
+ client.socket.send(notification);
183
+ }
184
+ }
185
+ }
186
+ else {
187
+ sessionManager.addClient(sessionId, device);
188
+ }
189
+ socket.send(serializeEnvelope(createEnvelope({
190
+ type: "session.connect",
191
+ sessionId,
192
+ payload: { role, clientName: deviceId, protocolVersion: PROTOCOL_VERSION },
193
+ })));
194
+ const pingTimer = setInterval(() => {
195
+ if (socket.readyState === socket.OPEN)
196
+ socket.ping();
197
+ }, PING_INTERVAL);
198
+ socket.on("message", (data) => {
199
+ handleSocketMessage(socket, data.toString(), role, sessionId, deviceId, sessionManager);
200
+ });
201
+ socket.on("close", () => {
202
+ clearInterval(pingTimer);
203
+ if (role === "host") {
204
+ const result = sessionManager.removeHost(sessionId);
205
+ if (result) {
206
+ const notification = serializeEnvelope(createEnvelope({ type: "session.host_disconnected", sessionId, payload: { reason: "host connection closed" } }));
207
+ for (const [, client] of result.clients) {
208
+ if (client.socket.readyState === client.socket.OPEN)
209
+ client.socket.send(notification);
210
+ }
211
+ }
212
+ }
213
+ else {
214
+ sessionManager.removeClient(sessionId, deviceId);
215
+ }
216
+ });
217
+ socket.on("error", () => { });
218
+ });
219
+ return new Promise((resolve, reject) => {
220
+ server.on("error", reject);
221
+ server.listen(targetPort, () => {
222
+ const addr = server.address();
223
+ const actualPort = typeof addr === "object" && addr ? addr.port : targetPort;
224
+ log("info", `embedded gateway on port ${actualPort}`);
225
+ resolve({
226
+ port: actualPort,
227
+ httpUrl: `http://127.0.0.1:${actualPort}`,
228
+ wsUrl: `ws://127.0.0.1:${actualPort}/ws`,
229
+ close: () => new Promise((res) => {
230
+ wss.clients.forEach((ws) => ws.close(1001, "shutting down"));
231
+ sessionManager.destroy();
232
+ pairingManager.destroy();
233
+ server.close(() => res());
234
+ }),
235
+ });
236
+ });
237
+ });
238
+ }
239
+ //# sourceMappingURL=embedded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedded.js","sourceRoot":"","sources":["../../../src/embedded.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};