claude-relay 2.0.0 → 2.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/bin/cli.js CHANGED
@@ -1266,6 +1266,10 @@ function showSetupGuide(config, ip, goBack) {
1266
1266
  } else {
1267
1267
  log(sym.bar + " " + a.dim + "Can't connect? Your phone must be on the same Wi-Fi network." + a.reset);
1268
1268
  }
1269
+ if (config.tls) {
1270
+ var httpOnboardUrl = "http://" + (tsIP || ip) + ":" + (config.port + 1) + "/setup";
1271
+ log(sym.bar + " " + a.dim + "Certificate warning? Open " + a.reset + httpOnboardUrl);
1272
+ }
1269
1273
  log(sym.bar);
1270
1274
  log(sym.done + " " + a.dim + "Setup complete." + a.reset);
1271
1275
  log(sym.end);
package/lib/daemon.js CHANGED
@@ -187,6 +187,17 @@ relay.server.listen(config.port, function () {
187
187
  saveConfig(config);
188
188
  });
189
189
 
190
+ // --- HTTP onboarding server (only when TLS is active) ---
191
+ if (relay.onboardingServer) {
192
+ var onboardingPort = config.port + 1;
193
+ relay.onboardingServer.on("error", function (err) {
194
+ console.error("[daemon] Onboarding HTTP server error:", err.message);
195
+ });
196
+ relay.onboardingServer.listen(onboardingPort, function () {
197
+ console.log("[daemon] Onboarding HTTP on http://0.0.0.0:" + onboardingPort);
198
+ });
199
+ }
200
+
190
201
  // --- Caffeinate (macOS) ---
191
202
  var caffeinateProc = null;
192
203
  if (config.keepAwake && process.platform === "darwin") {
@@ -216,6 +227,10 @@ function gracefulShutdown() {
216
227
  }
217
228
  } catch (e) {}
218
229
 
230
+ if (relay.onboardingServer) {
231
+ relay.onboardingServer.close();
232
+ }
233
+
219
234
  relay.server.close(function () {
220
235
  console.log("[daemon] Server closed");
221
236
  process.exit(0);
package/lib/server.js CHANGED
@@ -261,6 +261,67 @@ function createServer(opts) {
261
261
  server = http.createServer(appHandler);
262
262
  }
263
263
 
264
+ // --- HTTP onboarding server (only when TLS is active) ---
265
+ var onboardingServer = null;
266
+ if (tlsOptions) {
267
+ onboardingServer = http.createServer(function (req, res) {
268
+ var url = req.url.split("?")[0];
269
+
270
+ // CA certificate download
271
+ if (url === "/ca/download" && req.method === "GET" && caContent) {
272
+ res.writeHead(200, {
273
+ "Content-Type": "application/x-pem-file",
274
+ "Content-Disposition": 'attachment; filename="claude-relay-ca.pem"',
275
+ });
276
+ res.end(caContent);
277
+ return;
278
+ }
279
+
280
+ // Setup page
281
+ if (url === "/setup" && req.method === "GET") {
282
+ var host = req.headers.host || "localhost";
283
+ var hostname = host.split(":")[0];
284
+ var httpsSetupUrl = "https://" + hostname + ":" + portNum;
285
+ var httpSetupUrl = "http://" + hostname + ":" + (portNum + 1);
286
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
287
+ res.end(setupPageHtml(httpsSetupUrl, httpSetupUrl, !!caContent));
288
+ return;
289
+ }
290
+
291
+ // /https-info — the setup page already fetches this to discover the HTTPS URL
292
+ if (url === "/https-info" && req.method === "GET") {
293
+ var hostname = (req.headers.host || "localhost").split(":")[0];
294
+ res.writeHead(200, { "Content-Type": "application/json" });
295
+ res.end(JSON.stringify({ httpsUrl: "https://" + hostname + ":" + portNum }));
296
+ return;
297
+ }
298
+
299
+ // /info — CORS-enabled, used by setup page to verify HTTPS
300
+ if (url === "/info" && req.method === "GET") {
301
+ res.writeHead(200, {
302
+ "Content-Type": "application/json",
303
+ "Access-Control-Allow-Origin": "*",
304
+ });
305
+ var projectList = [];
306
+ projects.forEach(function (ctx, slug) {
307
+ projectList.push({ slug: slug, project: ctx.project, path: ctx.cwd });
308
+ });
309
+ res.end(JSON.stringify({ projects: projectList, version: currentVersion }));
310
+ return;
311
+ }
312
+
313
+ // Favicon
314
+ if (url === "/favicon.svg" || url === "/favicon.ico") {
315
+ if (serveStatic(url, res)) return;
316
+ }
317
+
318
+ // Everything else → redirect to HTTPS setup
319
+ var hostname = (req.headers.host || "localhost").split(":")[0];
320
+ res.writeHead(302, { "Location": "https://" + hostname + ":" + portNum + "/setup" });
321
+ res.end();
322
+ });
323
+ }
324
+
264
325
  // --- WebSocket ---
265
326
  var wss = new WebSocketServer({ noServer: true });
266
327
 
@@ -334,6 +395,7 @@ function createServer(opts) {
334
395
 
335
396
  return {
336
397
  server: server,
398
+ onboardingServer: onboardingServer,
337
399
  isTLS: !!tlsOptions,
338
400
  addProject: addProject,
339
401
  removeProject: removeProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-relay",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "claude-relay": "./bin/cli.js"