@involvex/syncstuff-cli 0.0.7 → 0.0.10
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/Agends.md +110 -0
- package/dist/cli.js +4396 -654
- package/package.json +5 -2
- package/src/cli/commands/debug.ts +1 -2
- package/src/cli/commands/device.ts +12 -13
- package/src/cli/commands/devices.ts +12 -13
- package/src/cli/commands/login.ts +1 -1
- package/src/cli/commands/logout.ts +1 -1
- package/src/cli/commands/scan.ts +4 -4
- package/src/cli/commands/transfer.ts +1 -1
- package/src/cli/commands/version.ts +4 -4
- package/src/cli/commands/whoami.ts +1 -1
- package/src/cli/index.ts +1 -1
- package/src/utils/config.ts +1 -0
- package/src/utils/network.ts +116 -161
- package/src/utils/ui.ts +1 -1
- package/.eslintignore +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@involvex/syncstuff-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://syncstuff-web.involvex.workers.dev/",
|
|
6
6
|
"sponsor": {
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
"inquirer": "13.1.0",
|
|
30
30
|
"ora": "9.0.0",
|
|
31
31
|
"boxen": "8.0.1",
|
|
32
|
-
"table": "6.9.0"
|
|
32
|
+
"table": "6.9.0",
|
|
33
|
+
"bonjour-service": "^1.1.1",
|
|
34
|
+
"@syncstuff/network-types": "workspace:*",
|
|
35
|
+
"uuid": "^9.0.1"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
38
|
"@eslint/css": "0.14.1",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import { apiClient, type Device } from "../../utils/api-client.js";
|
|
4
|
-
import {
|
|
4
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
5
5
|
import {
|
|
6
6
|
createSpinner,
|
|
7
7
|
createTable,
|
|
@@ -77,7 +77,7 @@ async function listAvailableDevices(ctx: CommandContext): Promise<Device[]> {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const tableData = response.data.map(device => [
|
|
80
|
-
device.id.substring(0, 8)
|
|
80
|
+
`${device.id.substring(0, 8)}...`,
|
|
81
81
|
device.name,
|
|
82
82
|
device.type,
|
|
83
83
|
device.platform,
|
|
@@ -100,19 +100,18 @@ async function listAvailableDevices(ctx: CommandContext): Promise<Device[]> {
|
|
|
100
100
|
printSeparator();
|
|
101
101
|
|
|
102
102
|
return response.data;
|
|
103
|
+
}
|
|
104
|
+
spinner.fail("Failed to fetch devices");
|
|
105
|
+
if (
|
|
106
|
+
response.error?.includes("404") ||
|
|
107
|
+
response.error?.includes("Not found")
|
|
108
|
+
) {
|
|
109
|
+
info("Devices endpoint not yet implemented in API");
|
|
110
|
+
info("This feature will be available soon!");
|
|
103
111
|
} else {
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
response.error?.includes("404") ||
|
|
107
|
-
response.error?.includes("Not found")
|
|
108
|
-
) {
|
|
109
|
-
info("Devices endpoint not yet implemented in API");
|
|
110
|
-
info("This feature will be available soon!");
|
|
111
|
-
} else {
|
|
112
|
-
error(response.error || "Unknown error");
|
|
113
|
-
}
|
|
114
|
-
return [];
|
|
112
|
+
error(response.error || "Unknown error");
|
|
115
113
|
}
|
|
114
|
+
return [];
|
|
116
115
|
} catch (err) {
|
|
117
116
|
spinner.fail("Error fetching devices");
|
|
118
117
|
error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { apiClient } from "../../utils/api-client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
4
4
|
import {
|
|
5
5
|
createSpinner,
|
|
6
6
|
createTable,
|
|
@@ -60,7 +60,7 @@ async function fetchAndDisplayDevices(ctx: CommandContext): Promise<boolean> {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
const tableData = response.data.map(device => [
|
|
63
|
-
device.id.substring(0, 8)
|
|
63
|
+
`${device.id.substring(0, 8)}...`,
|
|
64
64
|
device.name,
|
|
65
65
|
device.type,
|
|
66
66
|
device.platform,
|
|
@@ -82,19 +82,18 @@ async function fetchAndDisplayDevices(ctx: CommandContext): Promise<boolean> {
|
|
|
82
82
|
success(`Found ${response.data.length} device(s)`);
|
|
83
83
|
printSeparator();
|
|
84
84
|
return true;
|
|
85
|
+
}
|
|
86
|
+
spinner.fail("Failed to fetch devices");
|
|
87
|
+
if (
|
|
88
|
+
response.error?.includes("404") ||
|
|
89
|
+
response.error?.includes("Not found")
|
|
90
|
+
) {
|
|
91
|
+
info("Devices endpoint not yet implemented in API");
|
|
92
|
+
info("This feature will be available soon!");
|
|
85
93
|
} else {
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
response.error?.includes("404") ||
|
|
89
|
-
response.error?.includes("Not found")
|
|
90
|
-
) {
|
|
91
|
-
info("Devices endpoint not yet implemented in API");
|
|
92
|
-
info("This feature will be available soon!");
|
|
93
|
-
} else {
|
|
94
|
-
error(response.error || "Unknown error");
|
|
95
|
-
}
|
|
96
|
-
return false;
|
|
94
|
+
error(response.error || "Unknown error");
|
|
97
95
|
}
|
|
96
|
+
return false;
|
|
98
97
|
} catch (err) {
|
|
99
98
|
spinner.fail("Error fetching devices");
|
|
100
99
|
error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import inquirer from "inquirer";
|
|
2
2
|
import { apiClient } from "../../utils/api-client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
4
4
|
import {
|
|
5
5
|
createSpinner,
|
|
6
6
|
error,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { apiClient } from "../../utils/api-client.js";
|
|
2
|
-
import {
|
|
2
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
3
3
|
import { error, printHeader, printSeparator, success } from "../../utils/ui.js";
|
|
4
4
|
|
|
5
5
|
export async function logout(ctx: CommandContext): Promise<void> {
|
package/src/cli/commands/scan.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
3
|
+
import { type LocalDevice, networkScanner } from "../../utils/network.js";
|
|
4
4
|
import {
|
|
5
5
|
createSpinner,
|
|
6
6
|
createTable,
|
|
@@ -21,7 +21,7 @@ export async function scanLocal(
|
|
|
21
21
|
ctx: CommandContext,
|
|
22
22
|
): Promise<void> {
|
|
23
23
|
const timeout = args.includes("--timeout")
|
|
24
|
-
? parseInt(args[args.indexOf("--timeout") + 1] || "10", 10)
|
|
24
|
+
? Number.parseInt(args[args.indexOf("--timeout") + 1] || "10", 10)
|
|
25
25
|
: 10;
|
|
26
26
|
const continuous = args.includes("--watch") || args.includes("-w");
|
|
27
27
|
|
|
@@ -135,7 +135,7 @@ async function continuousScan(
|
|
|
135
135
|
|
|
136
136
|
function displayDevices(devices: LocalDevice[]): void {
|
|
137
137
|
const tableData = devices.map(device => [
|
|
138
|
-
device.id.substring(0, 8)
|
|
138
|
+
`${device.id.substring(0, 8)}...`,
|
|
139
139
|
device.name,
|
|
140
140
|
device.platform,
|
|
141
141
|
`${device.ip}:${device.port}`,
|
|
@@ -3,7 +3,7 @@ import { existsSync, statSync } from "fs";
|
|
|
3
3
|
import inquirer from "inquirer";
|
|
4
4
|
import { basename, resolve } from "path";
|
|
5
5
|
import { apiClient } from "../../utils/api-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
7
7
|
import {
|
|
8
8
|
createSpinner,
|
|
9
9
|
error,
|
|
@@ -18,8 +18,8 @@ export function showversion() {
|
|
|
18
18
|
|
|
19
19
|
if (DebugMode.enabled === true) {
|
|
20
20
|
console.log(chalk.yellow("Debug mode enabled"));
|
|
21
|
-
console.log(
|
|
22
|
-
console.log(
|
|
21
|
+
console.log(`Package path: ${packagePath}`);
|
|
22
|
+
console.log(`Version: ${version}`);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const versionBox = createBox(
|
|
@@ -27,7 +27,7 @@ export function showversion() {
|
|
|
27
27
|
chalk.bold("Version:") +
|
|
28
28
|
` ${chalk.green(version)}\n` +
|
|
29
29
|
chalk.bold("Package:") +
|
|
30
|
-
|
|
30
|
+
" @involvex/syncstuff-cli",
|
|
31
31
|
{
|
|
32
32
|
title: "Version Information",
|
|
33
33
|
titleAlignment: "center",
|
|
@@ -40,7 +40,7 @@ export function showversion() {
|
|
|
40
40
|
if (DebugMode.enabled === true) {
|
|
41
41
|
const packagePath = join(__dirname, "../../../package.json");
|
|
42
42
|
console.log(chalk.yellow("Debug mode enabled"));
|
|
43
|
-
console.log(
|
|
43
|
+
console.log(`Packagepath: ${packagePath}`);
|
|
44
44
|
console.log(chalk.yellow("Version: 0.0.1 (unable to read package.json)"));
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { apiClient } from "../../utils/api-client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { type CommandContext, debugLog } from "../../utils/context.js";
|
|
4
4
|
import {
|
|
5
5
|
createBox,
|
|
6
6
|
createSpinner,
|
package/src/cli/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { debugLog, parseArgs
|
|
2
|
+
import { type CommandContext, debugLog, parseArgs } from "../utils/context.js";
|
|
3
3
|
import { printHeader } from "../utils/ui.js";
|
|
4
4
|
import { checkForUpdates } from "../utils/update-checker.js";
|
|
5
5
|
|
package/src/utils/config.ts
CHANGED
package/src/utils/network.ts
CHANGED
|
@@ -1,146 +1,82 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import {
|
|
2
|
+
SYNCSTUFF_PROTOCOL,
|
|
3
|
+
SYNCSTUFF_SERVICE_TYPE,
|
|
4
|
+
type LocalDevice,
|
|
5
|
+
type ServiceTxtRecord,
|
|
6
|
+
} from "@syncstuff/network-types";
|
|
7
|
+
import { Bonjour, Browser, Service } from "bonjour-service";
|
|
8
|
+
import { createSocket } from "dgram";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { v4 as uuidv4 } from "uuid";
|
|
11
|
+
import { readConfig, writeConfig } from "./config.js";
|
|
12
|
+
|
|
13
|
+
export type { LocalDevice };
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const packageJson = require("../../package.json");
|
|
15
17
|
/**
|
|
16
|
-
* Network scanner for discovering SyncStuff devices on local network
|
|
17
|
-
* Uses UDP multicast to find devices
|
|
18
|
+
* Network scanner for discovering SyncStuff devices on the local network using mDNS.
|
|
18
19
|
*/
|
|
19
20
|
class NetworkScanner {
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* Get local IP addresses
|
|
24
|
-
*/
|
|
25
|
-
getLocalIPs(): string[] {
|
|
26
|
-
const interfaces = networkInterfaces();
|
|
27
|
-
const ips: string[] = [];
|
|
21
|
+
private bonjour: Bonjour;
|
|
22
|
+
private browser: Browser | null = null;
|
|
23
|
+
private ad: Service | null = null;
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!iface) continue;
|
|
32
|
-
|
|
33
|
-
for (const addr of iface) {
|
|
34
|
-
if (addr.family === "IPv4" && !addr.internal) {
|
|
35
|
-
ips.push(addr.address);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return ips;
|
|
25
|
+
constructor() {
|
|
26
|
+
this.bonjour = new Bonjour();
|
|
41
27
|
}
|
|
42
28
|
|
|
43
29
|
/**
|
|
44
|
-
* Scan the local network for SyncStuff devices
|
|
45
|
-
* Uses UDP broadcast to discover devices
|
|
30
|
+
* Scan the local network for SyncStuff devices using mDNS.
|
|
46
31
|
*/
|
|
47
|
-
async scan(timeout =
|
|
32
|
+
async scan(timeout = 5000): Promise<LocalDevice[]> {
|
|
48
33
|
return new Promise(resolve => {
|
|
34
|
+
if (this.browser) {
|
|
35
|
+
this.browser.stop();
|
|
36
|
+
}
|
|
49
37
|
const devices: LocalDevice[] = [];
|
|
50
38
|
const seenIds = new Set<string>();
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
version: data.version || "1.0.0",
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
} catch {
|
|
79
|
-
// Ignore non-JSON messages
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
this.socket.bind(0, () => {
|
|
84
|
-
this.socket?.setBroadcast(true);
|
|
85
|
-
|
|
86
|
-
// Send discovery broadcast
|
|
87
|
-
const discoveryMessage = JSON.stringify({
|
|
88
|
-
service: "syncstuff",
|
|
89
|
-
action: "discover",
|
|
90
|
-
timestamp: Date.now(),
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Broadcast on local network
|
|
94
|
-
const localIPs = this.getLocalIPs();
|
|
95
|
-
for (const ip of localIPs) {
|
|
96
|
-
const parts = ip.split(".");
|
|
97
|
-
parts[3] = "255";
|
|
98
|
-
const broadcastAddr = parts.join(".");
|
|
99
|
-
|
|
100
|
-
this.socket?.send(
|
|
101
|
-
discoveryMessage,
|
|
102
|
-
0,
|
|
103
|
-
discoveryMessage.length,
|
|
104
|
-
SYNCSTUFF_PORT,
|
|
105
|
-
broadcastAddr,
|
|
106
|
-
);
|
|
40
|
+
this.browser = this.bonjour.find({
|
|
41
|
+
type: SYNCSTUFF_SERVICE_TYPE,
|
|
42
|
+
protocol: SYNCSTUFF_PROTOCOL,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
this.browser.on("up", (service: Service) => {
|
|
46
|
+
const txt = (service.txt || {}) as unknown as ServiceTxtRecord;
|
|
47
|
+
const deviceId = txt.deviceId;
|
|
48
|
+
|
|
49
|
+
if (deviceId && !seenIds.has(deviceId)) {
|
|
50
|
+
const addresses = service.addresses || [];
|
|
51
|
+
const ip = addresses.find(addr => addr.includes("."));
|
|
52
|
+
if (ip) {
|
|
53
|
+
seenIds.add(deviceId);
|
|
54
|
+
devices.push({
|
|
55
|
+
id: deviceId,
|
|
56
|
+
name: txt.deviceName || service.name,
|
|
57
|
+
platform: txt.platform || "unknown",
|
|
58
|
+
ip,
|
|
59
|
+
port: service.port,
|
|
60
|
+
version: txt.version || "1.0.0",
|
|
61
|
+
});
|
|
107
62
|
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
108
65
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
SYNCSTUFF_PORT,
|
|
115
|
-
"224.0.0.251",
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Cleanup after timeout
|
|
120
|
-
setTimeout(() => {
|
|
121
|
-
this.cleanup();
|
|
122
|
-
resolve(devices);
|
|
123
|
-
}, timeout);
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error("Failed to start scanner:", error);
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
if (this.browser) {
|
|
68
|
+
this.browser.stop();
|
|
69
|
+
this.browser = null;
|
|
70
|
+
}
|
|
126
71
|
resolve(devices);
|
|
127
|
-
}
|
|
72
|
+
}, timeout);
|
|
128
73
|
});
|
|
129
74
|
}
|
|
130
75
|
|
|
131
|
-
private cleanup(): void {
|
|
132
|
-
if (this.socket) {
|
|
133
|
-
try {
|
|
134
|
-
this.socket.close();
|
|
135
|
-
} catch {
|
|
136
|
-
// Ignore close errors
|
|
137
|
-
}
|
|
138
|
-
this.socket = null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
76
|
/**
|
|
143
|
-
* Send a message to a specific device
|
|
77
|
+
* Send a message to a specific device.
|
|
78
|
+
* Note: This still uses a direct UDP socket, which is fine for direct communication
|
|
79
|
+
* once a device's IP and port are known.
|
|
144
80
|
*/
|
|
145
81
|
async sendTo(ip: string, port: number, message: object): Promise<void> {
|
|
146
82
|
return new Promise((resolve, reject) => {
|
|
@@ -159,49 +95,68 @@ class NetworkScanner {
|
|
|
159
95
|
}
|
|
160
96
|
|
|
161
97
|
/**
|
|
162
|
-
* Start advertising this device on the local network
|
|
98
|
+
* Start advertising this device on the local network using mDNS.
|
|
163
99
|
*/
|
|
164
|
-
startAdvertising(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const socket = createSocket({ type: "udp4", reuseAddr: true });
|
|
170
|
-
|
|
171
|
-
socket.bind(() => {
|
|
172
|
-
socket.setBroadcast(true);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const advertise = () => {
|
|
176
|
-
const message = JSON.stringify({
|
|
177
|
-
service: "syncstuff",
|
|
178
|
-
deviceId: "cli-device-" + Math.floor(Math.random() * 10000), // Simple random ID for CLI
|
|
179
|
-
deviceName,
|
|
180
|
-
platform,
|
|
181
|
-
port,
|
|
182
|
-
version: "0.0.6", // Should match package.json
|
|
183
|
-
timestamp: Date.now(),
|
|
100
|
+
startAdvertising(deviceName: string, port: number, platform = "cli") {
|
|
101
|
+
if (this.ad) {
|
|
102
|
+
this.ad.stop?.(() => {
|
|
103
|
+
this.ad = null;
|
|
104
|
+
this.publish(deviceName, port, platform);
|
|
184
105
|
});
|
|
106
|
+
} else {
|
|
107
|
+
this.publish(deviceName, port, platform);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
185
110
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
111
|
+
/**
|
|
112
|
+
* Stop advertising this device.
|
|
113
|
+
*/
|
|
114
|
+
stopAdvertising() {
|
|
115
|
+
if (this.ad) {
|
|
116
|
+
this.ad.stop?.(() => {
|
|
117
|
+
this.ad = null;
|
|
118
|
+
console.log("Stopped advertising.");
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
198
122
|
|
|
199
|
-
|
|
200
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Unpublish all services and destroy the bonjour instance.
|
|
125
|
+
*/
|
|
126
|
+
destroy() {
|
|
127
|
+
this.bonjour.unpublishAll(() => {
|
|
128
|
+
this.bonjour.destroy();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
201
131
|
|
|
202
|
-
|
|
203
|
-
|
|
132
|
+
private publish(deviceName: string, port: number, platform: string) {
|
|
133
|
+
const config = readConfig();
|
|
134
|
+
if (!config.deviceId) {
|
|
135
|
+
config.deviceId = uuidv4();
|
|
136
|
+
writeConfig(config);
|
|
137
|
+
}
|
|
138
|
+
const deviceId = config.deviceId;
|
|
139
|
+
const version = packageJson.version;
|
|
140
|
+
|
|
141
|
+
this.ad = this.bonjour.publish({
|
|
142
|
+
name: `${deviceName}-${deviceId.substring(0, 6)}`,
|
|
143
|
+
type: SYNCSTUFF_SERVICE_TYPE,
|
|
144
|
+
port,
|
|
145
|
+
protocol: SYNCSTUFF_PROTOCOL,
|
|
146
|
+
txt: {
|
|
147
|
+
deviceId,
|
|
148
|
+
deviceName,
|
|
149
|
+
platform,
|
|
150
|
+
version,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
console.log(`Advertising '${deviceName}' on the network...`);
|
|
204
154
|
}
|
|
205
155
|
}
|
|
206
156
|
|
|
207
157
|
export const networkScanner = new NetworkScanner();
|
|
158
|
+
|
|
159
|
+
// Graceful shutdown
|
|
160
|
+
process.on("exit", () => networkScanner.destroy());
|
|
161
|
+
process.on("SIGINT", () => process.exit());
|
|
162
|
+
process.on("SIGTERM", () => process.exit());
|
package/src/utils/ui.ts
CHANGED
|
@@ -55,7 +55,7 @@ export function createTable(data: string[][], headers?: string[]): string {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export function animateText(text: string, delay
|
|
58
|
+
export function animateText(text: string, delay = 50): Promise<void> {
|
|
59
59
|
return new Promise(resolve => {
|
|
60
60
|
let index = 0;
|
|
61
61
|
const interval = setInterval(() => {
|
package/.eslintignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
eslint.config.ts
|