nikcli-remote 1.0.8 → 1.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/dist/index.js CHANGED
@@ -2,15 +2,233 @@ import {
2
2
  DEFAULT_CONFIG,
3
3
  MessageTypes,
4
4
  RemoteServer,
5
- TerminalManager,
6
- getWebClient
7
- } from "./chunk-FYVPBMXV.js";
8
- import "./chunk-MCKGQKYU.js";
5
+ getWebClient,
6
+ init_web_client
7
+ } from "./chunk-TIYMAVGV.js";
8
+ import "./chunk-GI5RMYH6.js";
9
+
10
+ // src/tunnel.ts
11
+ import { spawn } from "child_process";
12
+ async function createTunnel(port, provider = "cloudflared") {
13
+ const manager = new TunnelManager(provider);
14
+ const url = await manager.create(port);
15
+ return {
16
+ url,
17
+ provider,
18
+ close: () => manager.close()
19
+ };
20
+ }
21
+ var TunnelManager = class {
22
+ provider;
23
+ process = null;
24
+ url = null;
25
+ tunnelInstance = null;
26
+ constructor(provider) {
27
+ this.provider = provider;
28
+ }
29
+ /**
30
+ * Create tunnel and return public URL
31
+ */
32
+ async create(port) {
33
+ switch (this.provider) {
34
+ case "localtunnel":
35
+ return this.createLocaltunnel(port);
36
+ case "cloudflared":
37
+ return this.createCloudflared(port);
38
+ case "ngrok":
39
+ return this.createNgrok(port);
40
+ default:
41
+ throw new Error(`Unknown tunnel provider: ${this.provider}`);
42
+ }
43
+ }
44
+ /**
45
+ * Close tunnel
46
+ */
47
+ async close() {
48
+ if (this.tunnelInstance?.close) {
49
+ this.tunnelInstance.close();
50
+ this.tunnelInstance = null;
51
+ }
52
+ if (this.process) {
53
+ this.process.kill();
54
+ this.process = null;
55
+ }
56
+ this.url = null;
57
+ }
58
+ /**
59
+ * Get tunnel URL
60
+ */
61
+ getUrl() {
62
+ return this.url;
63
+ }
64
+ /**
65
+ * Create localtunnel
66
+ */
67
+ async createLocaltunnel(port) {
68
+ try {
69
+ const localtunnel = await import("./localtunnel-6DCQIYU6.js");
70
+ const tunnel = await localtunnel.default({ port });
71
+ this.tunnelInstance = tunnel;
72
+ this.url = tunnel.url;
73
+ tunnel.on("close", () => {
74
+ this.url = null;
75
+ });
76
+ return tunnel.url;
77
+ } catch {
78
+ return this.createLocaltunnelCli(port);
79
+ }
80
+ }
81
+ /**
82
+ * Create localtunnel via CLI
83
+ */
84
+ createLocaltunnelCli(port) {
85
+ return new Promise((resolve, reject) => {
86
+ this.process = spawn("npx", ["localtunnel", "--port", port.toString(), "--print-requests", "false"], {
87
+ stdio: ["pipe", "pipe", "pipe"],
88
+ shell: true
89
+ });
90
+ let output = "";
91
+ const timeout = setTimeout(() => {
92
+ reject(new Error("Localtunnel timeout"));
93
+ }, 3e4);
94
+ this.process.stdout?.on("data", (data) => {
95
+ output += data.toString();
96
+ const match = output.match(/your url is:\s*(https?:\/\/[^\s]+)/i);
97
+ if (match) {
98
+ clearTimeout(timeout);
99
+ this.url = match[1];
100
+ resolve(match[1]);
101
+ }
102
+ });
103
+ this.process.stderr?.on("data", () => {
104
+ });
105
+ this.process.on("error", (error) => {
106
+ clearTimeout(timeout);
107
+ reject(error);
108
+ });
109
+ this.process.on("exit", (code) => {
110
+ if (code !== 0 && !this.url) {
111
+ clearTimeout(timeout);
112
+ reject(new Error(`Localtunnel exited with code ${code}`));
113
+ }
114
+ });
115
+ });
116
+ }
117
+ /**
118
+ * Create cloudflared tunnel
119
+ */
120
+ createCloudflared(port) {
121
+ return new Promise((resolve, reject) => {
122
+ this.process = spawn(
123
+ "cloudflared",
124
+ ["tunnel", "--url", `http://localhost:${port}`, "--metrics", "localhost:0"],
125
+ {
126
+ stdio: ["pipe", "pipe", "pipe"]
127
+ }
128
+ );
129
+ let output = "";
130
+ const timeout = setTimeout(() => {
131
+ reject(new Error("Cloudflared timeout"));
132
+ }, 3e4);
133
+ const handleData = (data) => {
134
+ output += data.toString();
135
+ const match = output.match(/(https:\/\/[^\s]+\.trycloudflare\.com)/i);
136
+ if (match) {
137
+ clearTimeout(timeout);
138
+ this.url = match[1];
139
+ resolve(match[1]);
140
+ }
141
+ };
142
+ this.process.stdout?.on("data", handleData);
143
+ this.process.stderr?.on("data", handleData);
144
+ this.process.on("error", (error) => {
145
+ clearTimeout(timeout);
146
+ reject(error);
147
+ });
148
+ this.process.on("exit", (code) => {
149
+ if (code !== 0 && !this.url) {
150
+ clearTimeout(timeout);
151
+ reject(new Error(`Cloudflared exited with code ${code}`));
152
+ }
153
+ });
154
+ });
155
+ }
156
+ /**
157
+ * Create ngrok tunnel
158
+ */
159
+ createNgrok(port) {
160
+ return new Promise((resolve, reject) => {
161
+ this.process = spawn("ngrok", ["http", port.toString(), "--log=stdout", "--log-level=info"], {
162
+ stdio: ["pipe", "pipe", "pipe"]
163
+ });
164
+ let output = "";
165
+ const timeout = setTimeout(() => {
166
+ reject(new Error("Ngrok timeout"));
167
+ }, 3e4);
168
+ this.process.stdout?.on("data", (data) => {
169
+ output += data.toString();
170
+ const match = output.match(/url=(https?:\/\/[^\s]+)/i);
171
+ if (match) {
172
+ clearTimeout(timeout);
173
+ this.url = match[1];
174
+ resolve(match[1]);
175
+ }
176
+ });
177
+ this.process.stderr?.on("data", () => {
178
+ });
179
+ this.process.on("error", (error) => {
180
+ clearTimeout(timeout);
181
+ reject(error);
182
+ });
183
+ this.process.on("exit", (code) => {
184
+ if (code !== 0 && !this.url) {
185
+ clearTimeout(timeout);
186
+ reject(new Error(`Ngrok exited with code ${code}`));
187
+ }
188
+ });
189
+ });
190
+ }
191
+ };
192
+ async function checkTunnelAvailability(provider) {
193
+ try {
194
+ const { execSync } = await import("child_process");
195
+ switch (provider) {
196
+ case "localtunnel":
197
+ try {
198
+ await import("./localtunnel-6DCQIYU6.js");
199
+ return true;
200
+ } catch {
201
+ execSync("npx localtunnel --version", { stdio: "pipe" });
202
+ return true;
203
+ }
204
+ case "cloudflared":
205
+ execSync("cloudflared --version", { stdio: "pipe" });
206
+ return true;
207
+ case "ngrok":
208
+ execSync("ngrok version", { stdio: "pipe" });
209
+ return true;
210
+ default:
211
+ return false;
212
+ }
213
+ } catch {
214
+ return false;
215
+ }
216
+ }
217
+ async function findAvailableTunnel() {
218
+ const providers = ["localtunnel", "cloudflared", "ngrok"];
219
+ for (const provider of providers) {
220
+ if (await checkTunnelAvailability(provider)) {
221
+ return provider;
222
+ }
223
+ }
224
+ return null;
225
+ }
9
226
 
10
227
  // src/index.ts
228
+ init_web_client();
11
229
  async function createRemoteServer(config = {}) {
12
- const { RemoteServer: RemoteServer2 } = await import("./server-OYMSDTRP.js");
13
- const server = new RemoteServer2(config);
230
+ const { RemoteServer: RemoteServerCls } = await import("./server-O3KTQ4KJ.js");
231
+ const server = new RemoteServerCls(config);
14
232
  const session = await server.start();
15
233
  return { server, session };
16
234
  }
@@ -18,7 +236,10 @@ export {
18
236
  DEFAULT_CONFIG,
19
237
  MessageTypes,
20
238
  RemoteServer,
21
- TerminalManager,
239
+ TunnelManager,
240
+ checkTunnelAvailability,
22
241
  createRemoteServer,
242
+ createTunnel,
243
+ findAvailableTunnel,
23
244
  getWebClient
24
245
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __commonJS,
3
3
  __require
4
- } from "./chunk-MCKGQKYU.js";
4
+ } from "./chunk-GI5RMYH6.js";
5
5
 
6
6
  // node_modules/axios/lib/helpers/bind.js
7
7
  var require_bind = __commonJS({
@@ -0,0 +1,7 @@
1
+ import {
2
+ RemoteServer
3
+ } from "./chunk-TIYMAVGV.js";
4
+ import "./chunk-GI5RMYH6.js";
5
+ export {
6
+ RemoteServer
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nikcli-remote",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Native remote terminal server for NikCLI - Mobile control via WebSocket",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -1,25 +1,70 @@
1
1
  /**
2
- * @nikcli/remote
3
- * Native remote terminal server for NikCLI
2
+ * @nikcli/remote - Enterprise Terminal Streaming
4
3
  *
5
- * Provides WebSocket-based remote access to NikCLI from mobile devices.
4
+ * Direct stdin/stdout streaming for true real-time terminal access.
5
+ * No fake PTY - mobile sees your actual NikCLI terminal.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { RemoteServer, createTunnel } from '@nikcli/remote'
10
+ *
11
+ * const server = new RemoteServer()
12
+ * const session = await server.start({
13
+ * name: 'my-terminal',
14
+ * processForStreaming: {
15
+ * stdout: process.stdout,
16
+ * stdin: process.stdin,
17
+ * },
18
+ * })
19
+ *
20
+ * // Create public tunnel
21
+ * const tunnelUrl = await createTunnel(session.port, 'cloudflared')
22
+ * console.log('Access your terminal:', tunnelUrl)
23
+ * ```
6
24
  */
7
25
 
8
- export { RemoteServer, type RemoteServerEvents } from './server'
9
- export { TerminalManager, type TerminalConfig } from './terminal'
26
+ // Core server
27
+ export { RemoteServer } from './server'
28
+ export type { RemoteServerEvents } from './server'
29
+
30
+ // Tunnel management
31
+ export {
32
+ TunnelManager,
33
+ createTunnel,
34
+ checkTunnelAvailability,
35
+ findAvailableTunnel,
36
+ type TunnelResult,
37
+ } from './tunnel'
38
+
39
+ // Web client
10
40
  export { getWebClient } from './web-client'
41
+
42
+ // Types - re-export for convenience
11
43
  export type {
12
- SessionStatus, TunnelProvider, DeviceInfo, RemoteSession,
13
- ServerConfig, BroadcastMessage, RemoteNotification, ClientMessage,
14
- ServerMessage, TerminalData, TerminalResize, CommandMessage,
44
+ DeviceInfo,
45
+ SessionStatus,
46
+ RemoteNotification,
47
+ ClientMessage,
48
+ BroadcastMessage,
49
+ ServerConfig,
50
+ RemoteSession,
51
+ TunnelProvider,
15
52
  } from './types'
53
+
54
+ // Constants
16
55
  export { DEFAULT_CONFIG, MessageTypes } from './types'
17
56
 
57
+ import type { RemoteServer } from './server'
58
+ import type { ServerConfig, RemoteSession } from './types'
59
+
60
+ /**
61
+ * Create a remote server with streaming in one call
62
+ */
18
63
  export async function createRemoteServer(
19
- config: Partial<import('./types').ServerConfig> = {}
20
- ) {
21
- const { RemoteServer } = await import('./server')
22
- const server = new RemoteServer(config)
64
+ config: Partial<ServerConfig> = {}
65
+ ): Promise<{ server: RemoteServer; session: RemoteSession }> {
66
+ const { RemoteServer: RemoteServerCls } = await import('./server')
67
+ const server = new RemoteServerCls(config)
23
68
  const session = await server.start()
24
69
  return { server, session }
25
70
  }