cursor-bridge 1.0.0 → 1.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/dist/index.js +39 -17
- package/package.json +1 -1
- package/src/index.ts +55 -20
package/dist/index.js
CHANGED
|
@@ -7,10 +7,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const ws_1 = require("ws");
|
|
8
8
|
const uuid_1 = require("uuid");
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
|
|
11
10
|
const os_1 = __importDefault(require("os"));
|
|
12
11
|
const PORT = Number(process.argv[2]) || 9090;
|
|
13
12
|
const TOKEN = (0, uuid_1.v4)();
|
|
13
|
+
// 6 haneli pair code üret
|
|
14
|
+
function generatePairCode() {
|
|
15
|
+
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
16
|
+
}
|
|
17
|
+
const PAIR_CODE = generatePairCode();
|
|
14
18
|
const clients = new Map();
|
|
15
19
|
function getLocalIP() {
|
|
16
20
|
const interfaces = os_1.default.networkInterfaces();
|
|
@@ -38,7 +42,6 @@ function findPeer(clientId) {
|
|
|
38
42
|
}
|
|
39
43
|
function banner() {
|
|
40
44
|
const ip = getLocalIP();
|
|
41
|
-
const pairUrl = `cursor-bridge://${ip}:${PORT}/${TOKEN}`;
|
|
42
45
|
console.clear();
|
|
43
46
|
console.log('');
|
|
44
47
|
console.log(chalk_1.default.hex('#A855F7').bold(' ╔══════════════════════════════════════╗'));
|
|
@@ -47,35 +50,51 @@ function banner() {
|
|
|
47
50
|
chalk_1.default.hex('#A855F7').bold('║'));
|
|
48
51
|
console.log(chalk_1.default.hex('#A855F7').bold(' ╚══════════════════════════════════════╝'));
|
|
49
52
|
console.log('');
|
|
50
|
-
console.log(chalk_1.default.gray('
|
|
53
|
+
console.log(chalk_1.default.gray(' Enter this code in the mobile app to pair:'));
|
|
51
54
|
console.log('');
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
lines.forEach(line => console.log(' ' + line));
|
|
55
|
-
});
|
|
55
|
+
console.log(' ' +
|
|
56
|
+
chalk_1.default.bgHex('#A855F7').white.bold(` ${PAIR_CODE.split('').join(' ')} `));
|
|
56
57
|
console.log('');
|
|
57
|
-
console.log(chalk_1.default.gray('
|
|
58
|
-
console.log(chalk_1.default.
|
|
59
|
-
console.log(chalk_1.default.
|
|
60
|
-
console.log(chalk_1.default.
|
|
58
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
|
|
59
|
+
console.log(chalk_1.default.gray(' Host: ') + chalk_1.default.white(ip));
|
|
60
|
+
console.log(chalk_1.default.gray(' Port: ') + chalk_1.default.white(String(PORT)));
|
|
61
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────────'));
|
|
61
62
|
console.log('');
|
|
62
63
|
console.log(chalk_1.default.gray(' Waiting for mobile connection...'));
|
|
63
64
|
console.log('');
|
|
64
65
|
}
|
|
65
66
|
const wss = new ws_1.WebSocketServer({ port: PORT });
|
|
67
|
+
wss.on('error', error => {
|
|
68
|
+
console.error(chalk_1.default.red(' WebSocket error:'), error.message);
|
|
69
|
+
});
|
|
66
70
|
wss.on('connection', (ws) => {
|
|
67
71
|
const clientId = (0, uuid_1.v4)();
|
|
72
|
+
ws.on('error', error => {
|
|
73
|
+
console.error(chalk_1.default.red(` Client error:`), error.message);
|
|
74
|
+
clients.delete(clientId);
|
|
75
|
+
});
|
|
68
76
|
ws.on('message', (raw) => {
|
|
69
77
|
try {
|
|
70
78
|
const message = JSON.parse(raw.toString());
|
|
71
79
|
switch (message.type) {
|
|
72
80
|
case 'pair': {
|
|
73
|
-
const {
|
|
81
|
+
const { pairCode, clientType } = message.payload;
|
|
82
|
+
// Pair code doğrula
|
|
83
|
+
if (pairCode !== PAIR_CODE) {
|
|
84
|
+
ws.send(JSON.stringify({
|
|
85
|
+
type: 'error',
|
|
86
|
+
payload: { message: 'Invalid pair code' },
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
}));
|
|
89
|
+
console.log(chalk_1.default.hex('#EF4444')(' ✗ ') +
|
|
90
|
+
chalk_1.default.gray(`Invalid pair code attempt: ${pairCode}`));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
74
93
|
clients.set(clientId, {
|
|
75
94
|
id: clientId,
|
|
76
95
|
ws,
|
|
77
96
|
type: clientType,
|
|
78
|
-
token,
|
|
97
|
+
token: TOKEN,
|
|
79
98
|
});
|
|
80
99
|
const peer = findPeer(clientId);
|
|
81
100
|
ws.send(JSON.stringify({
|
|
@@ -83,6 +102,8 @@ wss.on('connection', (ws) => {
|
|
|
83
102
|
payload: {
|
|
84
103
|
status: peer ? 'connected' : 'waiting',
|
|
85
104
|
clientId,
|
|
105
|
+
host: getLocalIP(),
|
|
106
|
+
port: PORT,
|
|
86
107
|
},
|
|
87
108
|
timestamp: Date.now(),
|
|
88
109
|
}));
|
|
@@ -93,11 +114,11 @@ wss.on('connection', (ws) => {
|
|
|
93
114
|
timestamp: Date.now(),
|
|
94
115
|
}));
|
|
95
116
|
console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
|
|
96
|
-
chalk_1.default.white(`${clientType}
|
|
117
|
+
chalk_1.default.white(`${clientType} paired successfully!`));
|
|
97
118
|
}
|
|
98
119
|
else {
|
|
99
|
-
console.log(chalk_1.default.hex('#
|
|
100
|
-
chalk_1.default.white(`${clientType}
|
|
120
|
+
console.log(chalk_1.default.hex('#22C55E')(' ✓ ') +
|
|
121
|
+
chalk_1.default.white(`${clientType} connected with pair code`));
|
|
101
122
|
}
|
|
102
123
|
break;
|
|
103
124
|
}
|
|
@@ -162,7 +183,7 @@ wss.on('connection', (ws) => {
|
|
|
162
183
|
});
|
|
163
184
|
});
|
|
164
185
|
// Heartbeat
|
|
165
|
-
setInterval(() => {
|
|
186
|
+
const heartbeat = setInterval(() => {
|
|
166
187
|
clients.forEach(client => {
|
|
167
188
|
if (client.ws.readyState === ws_1.WebSocket.OPEN) {
|
|
168
189
|
client.ws.ping();
|
|
@@ -173,6 +194,7 @@ banner();
|
|
|
173
194
|
process.on('SIGINT', () => {
|
|
174
195
|
console.log('');
|
|
175
196
|
console.log(chalk_1.default.gray(' Bridge stopped.'));
|
|
197
|
+
clearInterval(heartbeat);
|
|
176
198
|
wss.close();
|
|
177
199
|
process.exit(0);
|
|
178
200
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import qrcode from 'qrcode-terminal';
|
|
7
6
|
import os from 'os';
|
|
8
7
|
|
|
9
8
|
const PORT = Number(process.argv[2]) || 9090;
|
|
10
9
|
const TOKEN = uuidv4();
|
|
11
10
|
|
|
11
|
+
// 6 haneli pair code üret
|
|
12
|
+
function generatePairCode(): string {
|
|
13
|
+
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PAIR_CODE = generatePairCode();
|
|
17
|
+
|
|
12
18
|
interface BridgeMessage {
|
|
13
19
|
type: string;
|
|
14
20
|
payload: Record<string, unknown>;
|
|
@@ -55,7 +61,6 @@ function findPeer(clientId: string): ConnectedClient | undefined {
|
|
|
55
61
|
|
|
56
62
|
function banner() {
|
|
57
63
|
const ip = getLocalIP();
|
|
58
|
-
const pairUrl = `cursor-bridge://${ip}:${PORT}/${TOKEN}`;
|
|
59
64
|
|
|
60
65
|
console.clear();
|
|
61
66
|
console.log('');
|
|
@@ -71,24 +76,26 @@ function banner() {
|
|
|
71
76
|
chalk.hex('#A855F7').bold(' ╚══════════════════════════════════════╝'),
|
|
72
77
|
);
|
|
73
78
|
console.log('');
|
|
74
|
-
console.log(
|
|
79
|
+
console.log(
|
|
80
|
+
chalk.gray(' Enter this code in the mobile app to pair:'),
|
|
81
|
+
);
|
|
75
82
|
console.log('');
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
|
|
83
|
+
console.log(
|
|
84
|
+
' ' +
|
|
85
|
+
chalk.bgHex('#A855F7').white.bold(` ${PAIR_CODE.split('').join(' ')} `),
|
|
86
|
+
);
|
|
82
87
|
console.log('');
|
|
83
|
-
console.log(chalk.gray(' Or connect manually:'));
|
|
84
88
|
console.log(
|
|
85
|
-
chalk.
|
|
89
|
+
chalk.gray(' ─────────────────────────────────────────'),
|
|
86
90
|
);
|
|
87
91
|
console.log(
|
|
88
|
-
chalk.
|
|
92
|
+
chalk.gray(' Host: ') + chalk.white(ip),
|
|
89
93
|
);
|
|
90
94
|
console.log(
|
|
91
|
-
chalk.
|
|
95
|
+
chalk.gray(' Port: ') + chalk.white(String(PORT)),
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
chalk.gray(' ─────────────────────────────────────────'),
|
|
92
99
|
);
|
|
93
100
|
console.log('');
|
|
94
101
|
console.log(chalk.gray(' Waiting for mobile connection...'));
|
|
@@ -97,25 +104,50 @@ function banner() {
|
|
|
97
104
|
|
|
98
105
|
const wss = new WebSocketServer({ port: PORT });
|
|
99
106
|
|
|
107
|
+
wss.on('error', error => {
|
|
108
|
+
console.error(chalk.red(' WebSocket error:'), error.message);
|
|
109
|
+
});
|
|
110
|
+
|
|
100
111
|
wss.on('connection', (ws: WebSocket) => {
|
|
101
112
|
const clientId = uuidv4();
|
|
102
113
|
|
|
114
|
+
ws.on('error', error => {
|
|
115
|
+
console.error(chalk.red(` Client error:`), error.message);
|
|
116
|
+
clients.delete(clientId);
|
|
117
|
+
});
|
|
118
|
+
|
|
103
119
|
ws.on('message', (raw: Buffer) => {
|
|
104
120
|
try {
|
|
105
121
|
const message: BridgeMessage = JSON.parse(raw.toString());
|
|
106
122
|
|
|
107
123
|
switch (message.type) {
|
|
108
124
|
case 'pair': {
|
|
109
|
-
const {
|
|
110
|
-
|
|
125
|
+
const { pairCode, clientType } = message.payload as {
|
|
126
|
+
pairCode: string;
|
|
111
127
|
clientType: 'mobile' | 'desktop';
|
|
112
128
|
};
|
|
113
129
|
|
|
130
|
+
// Pair code doğrula
|
|
131
|
+
if (pairCode !== PAIR_CODE) {
|
|
132
|
+
ws.send(
|
|
133
|
+
JSON.stringify({
|
|
134
|
+
type: 'error',
|
|
135
|
+
payload: { message: 'Invalid pair code' },
|
|
136
|
+
timestamp: Date.now(),
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
139
|
+
console.log(
|
|
140
|
+
chalk.hex('#EF4444')(' ✗ ') +
|
|
141
|
+
chalk.gray(`Invalid pair code attempt: ${pairCode}`),
|
|
142
|
+
);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
clients.set(clientId, {
|
|
115
147
|
id: clientId,
|
|
116
148
|
ws,
|
|
117
149
|
type: clientType,
|
|
118
|
-
token,
|
|
150
|
+
token: TOKEN,
|
|
119
151
|
});
|
|
120
152
|
|
|
121
153
|
const peer = findPeer(clientId);
|
|
@@ -126,6 +158,8 @@ wss.on('connection', (ws: WebSocket) => {
|
|
|
126
158
|
payload: {
|
|
127
159
|
status: peer ? 'connected' : 'waiting',
|
|
128
160
|
clientId,
|
|
161
|
+
host: getLocalIP(),
|
|
162
|
+
port: PORT,
|
|
129
163
|
},
|
|
130
164
|
timestamp: Date.now(),
|
|
131
165
|
}),
|
|
@@ -141,12 +175,12 @@ wss.on('connection', (ws: WebSocket) => {
|
|
|
141
175
|
);
|
|
142
176
|
console.log(
|
|
143
177
|
chalk.hex('#22C55E')(' ✓ ') +
|
|
144
|
-
chalk.white(`${clientType}
|
|
178
|
+
chalk.white(`${clientType} paired successfully!`),
|
|
145
179
|
);
|
|
146
180
|
} else {
|
|
147
181
|
console.log(
|
|
148
|
-
chalk.hex('#
|
|
149
|
-
chalk.white(`${clientType}
|
|
182
|
+
chalk.hex('#22C55E')(' ✓ ') +
|
|
183
|
+
chalk.white(`${clientType} connected with pair code`),
|
|
150
184
|
);
|
|
151
185
|
}
|
|
152
186
|
break;
|
|
@@ -232,7 +266,7 @@ wss.on('connection', (ws: WebSocket) => {
|
|
|
232
266
|
});
|
|
233
267
|
|
|
234
268
|
// Heartbeat
|
|
235
|
-
setInterval(() => {
|
|
269
|
+
const heartbeat = setInterval(() => {
|
|
236
270
|
clients.forEach(client => {
|
|
237
271
|
if (client.ws.readyState === WebSocket.OPEN) {
|
|
238
272
|
client.ws.ping();
|
|
@@ -245,6 +279,7 @@ banner();
|
|
|
245
279
|
process.on('SIGINT', () => {
|
|
246
280
|
console.log('');
|
|
247
281
|
console.log(chalk.gray(' Bridge stopped.'));
|
|
282
|
+
clearInterval(heartbeat);
|
|
248
283
|
wss.close();
|
|
249
284
|
process.exit(0);
|
|
250
285
|
});
|