herdr-remote-relay 0.3.25 → 0.3.27

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.
Files changed (111) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/dist/protocol/index.d.ts +1 -0
  4. package/dist/protocol/index.js +1 -0
  5. package/dist/protocol/release.d.ts +8 -0
  6. package/dist/protocol/release.js +17 -0
  7. package/dist/relay-server.d.ts +3 -0
  8. package/dist/relay-server.js +3 -1
  9. package/dist/server/http-api.d.ts +1 -0
  10. package/dist/server/http-api.js +12 -7
  11. package/dist/server/types.d.ts +2 -0
  12. package/package.json +1 -1
  13. package/web/dist/assets/index-DkFcSEuU.js +61 -0
  14. package/web/dist/assets/index-DznFLD5G.css +32 -0
  15. package/web/dist/fonts/maple-mono/OFL.txt +93 -0
  16. package/web/dist/fonts/maple-mono/maple-mono-cjk-0-400.woff2 +0 -0
  17. package/web/dist/fonts/maple-mono/maple-mono-cjk-0-700.woff2 +0 -0
  18. package/web/dist/fonts/maple-mono/maple-mono-cjk-1-400.woff2 +0 -0
  19. package/web/dist/fonts/maple-mono/maple-mono-cjk-1-700.woff2 +0 -0
  20. package/web/dist/fonts/maple-mono/maple-mono-cjk-10-400.woff2 +0 -0
  21. package/web/dist/fonts/maple-mono/maple-mono-cjk-10-700.woff2 +0 -0
  22. package/web/dist/fonts/maple-mono/maple-mono-cjk-11-400.woff2 +0 -0
  23. package/web/dist/fonts/maple-mono/maple-mono-cjk-11-700.woff2 +0 -0
  24. package/web/dist/fonts/maple-mono/maple-mono-cjk-12-400.woff2 +0 -0
  25. package/web/dist/fonts/maple-mono/maple-mono-cjk-12-700.woff2 +0 -0
  26. package/web/dist/fonts/maple-mono/maple-mono-cjk-13-400.woff2 +0 -0
  27. package/web/dist/fonts/maple-mono/maple-mono-cjk-13-700.woff2 +0 -0
  28. package/web/dist/fonts/maple-mono/maple-mono-cjk-14-400.woff2 +0 -0
  29. package/web/dist/fonts/maple-mono/maple-mono-cjk-14-700.woff2 +0 -0
  30. package/web/dist/fonts/maple-mono/maple-mono-cjk-15-400.woff2 +0 -0
  31. package/web/dist/fonts/maple-mono/maple-mono-cjk-15-700.woff2 +0 -0
  32. package/web/dist/fonts/maple-mono/maple-mono-cjk-16-400.woff2 +0 -0
  33. package/web/dist/fonts/maple-mono/maple-mono-cjk-16-700.woff2 +0 -0
  34. package/web/dist/fonts/maple-mono/maple-mono-cjk-17-400.woff2 +0 -0
  35. package/web/dist/fonts/maple-mono/maple-mono-cjk-17-700.woff2 +0 -0
  36. package/web/dist/fonts/maple-mono/maple-mono-cjk-18-400.woff2 +0 -0
  37. package/web/dist/fonts/maple-mono/maple-mono-cjk-18-700.woff2 +0 -0
  38. package/web/dist/fonts/maple-mono/maple-mono-cjk-19-400.woff2 +0 -0
  39. package/web/dist/fonts/maple-mono/maple-mono-cjk-19-700.woff2 +0 -0
  40. package/web/dist/fonts/maple-mono/maple-mono-cjk-2-400.woff2 +0 -0
  41. package/web/dist/fonts/maple-mono/maple-mono-cjk-2-700.woff2 +0 -0
  42. package/web/dist/fonts/maple-mono/maple-mono-cjk-3-400.woff2 +0 -0
  43. package/web/dist/fonts/maple-mono/maple-mono-cjk-3-700.woff2 +0 -0
  44. package/web/dist/fonts/maple-mono/maple-mono-cjk-4-400.woff2 +0 -0
  45. package/web/dist/fonts/maple-mono/maple-mono-cjk-4-700.woff2 +0 -0
  46. package/web/dist/fonts/maple-mono/maple-mono-cjk-5-400.woff2 +0 -0
  47. package/web/dist/fonts/maple-mono/maple-mono-cjk-5-700.woff2 +0 -0
  48. package/web/dist/fonts/maple-mono/maple-mono-cjk-6-400.woff2 +0 -0
  49. package/web/dist/fonts/maple-mono/maple-mono-cjk-6-700.woff2 +0 -0
  50. package/web/dist/fonts/maple-mono/maple-mono-cjk-7-400.woff2 +0 -0
  51. package/web/dist/fonts/maple-mono/maple-mono-cjk-7-700.woff2 +0 -0
  52. package/web/dist/fonts/maple-mono/maple-mono-cjk-8-400.woff2 +0 -0
  53. package/web/dist/fonts/maple-mono/maple-mono-cjk-8-700.woff2 +0 -0
  54. package/web/dist/fonts/maple-mono/maple-mono-cjk-9-400.woff2 +0 -0
  55. package/web/dist/fonts/maple-mono/maple-mono-cjk-9-700.woff2 +0 -0
  56. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-0-400.woff2 +0 -0
  57. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-0-700.woff2 +0 -0
  58. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-1-400.woff2 +0 -0
  59. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-1-700.woff2 +0 -0
  60. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-10-400.woff2 +0 -0
  61. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-10-700.woff2 +0 -0
  62. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-11-400.woff2 +0 -0
  63. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-11-700.woff2 +0 -0
  64. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-12-400.woff2 +0 -0
  65. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-12-700.woff2 +0 -0
  66. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-13-400.woff2 +0 -0
  67. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-13-700.woff2 +0 -0
  68. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-14-400.woff2 +0 -0
  69. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-14-700.woff2 +0 -0
  70. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-2-400.woff2 +0 -0
  71. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-2-700.woff2 +0 -0
  72. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-3-400.woff2 +0 -0
  73. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-3-700.woff2 +0 -0
  74. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-4-400.woff2 +0 -0
  75. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-4-700.woff2 +0 -0
  76. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-5-400.woff2 +0 -0
  77. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-5-700.woff2 +0 -0
  78. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-6-400.woff2 +0 -0
  79. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-6-700.woff2 +0 -0
  80. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-7-400.woff2 +0 -0
  81. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-7-700.woff2 +0 -0
  82. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-8-400.woff2 +0 -0
  83. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-8-700.woff2 +0 -0
  84. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-9-400.woff2 +0 -0
  85. package/web/dist/fonts/maple-mono/maple-mono-cjk-rare-9-700.woff2 +0 -0
  86. package/web/dist/fonts/maple-mono/maple-mono-icons-0-400.woff2 +0 -0
  87. package/web/dist/fonts/maple-mono/maple-mono-icons-1-400.woff2 +0 -0
  88. package/web/dist/fonts/maple-mono/maple-mono-icons-10-400.woff2 +0 -0
  89. package/web/dist/fonts/maple-mono/maple-mono-icons-11-400.woff2 +0 -0
  90. package/web/dist/fonts/maple-mono/maple-mono-icons-12-400.woff2 +0 -0
  91. package/web/dist/fonts/maple-mono/maple-mono-icons-13-400.woff2 +0 -0
  92. package/web/dist/fonts/maple-mono/maple-mono-icons-14-400.woff2 +0 -0
  93. package/web/dist/fonts/maple-mono/maple-mono-icons-15-400.woff2 +0 -0
  94. package/web/dist/fonts/maple-mono/maple-mono-icons-16-400.woff2 +0 -0
  95. package/web/dist/fonts/maple-mono/maple-mono-icons-17-400.woff2 +0 -0
  96. package/web/dist/fonts/maple-mono/maple-mono-icons-2-400.woff2 +0 -0
  97. package/web/dist/fonts/maple-mono/maple-mono-icons-3-400.woff2 +0 -0
  98. package/web/dist/fonts/maple-mono/maple-mono-icons-4-400.woff2 +0 -0
  99. package/web/dist/fonts/maple-mono/maple-mono-icons-5-400.woff2 +0 -0
  100. package/web/dist/fonts/maple-mono/maple-mono-icons-6-400.woff2 +0 -0
  101. package/web/dist/fonts/maple-mono/maple-mono-icons-7-400.woff2 +0 -0
  102. package/web/dist/fonts/maple-mono/maple-mono-icons-8-400.woff2 +0 -0
  103. package/web/dist/fonts/maple-mono/maple-mono-icons-9-400.woff2 +0 -0
  104. package/web/dist/fonts/maple-mono/maple-mono-latin-400.woff2 +0 -0
  105. package/web/dist/fonts/maple-mono/maple-mono-latin-700.woff2 +0 -0
  106. package/web/dist/fonts/maple-mono/maple-mono-symbols-400.woff2 +0 -0
  107. package/web/dist/fonts/maple-mono/maple-mono-symbols-700.woff2 +0 -0
  108. package/web/dist/fonts/maple-mono/maple-mono.css +992 -0
  109. package/web/dist/index.html +5 -2
  110. package/web/dist/assets/index-XYYRsgSb.css +0 -32
  111. package/web/dist/assets/index-k4NH1O2l.js +0 -61
package/README.md CHANGED
@@ -11,10 +11,12 @@ Brokers WebSocket connections between browsers and workstation host connectors.
11
11
  ## Installation
12
12
 
13
13
  ```bash
14
- npm install -g herdr-remote-relay
14
+ npm install -g https://github.com/dibin666/herdr-remote/releases/latest/download/herdr-remote-relay.tgz
15
15
  herdr-remote-relay --public-url https://herdr.example.com --password <password>
16
16
  ```
17
17
 
18
+ From npm instead: `npm install -g herdr-remote-relay` (it can lag a new release by a while).
19
+
18
20
  Requirements: Node.js 22+, TLS reverse proxy (nginx, Caddy, Cloudflare Tunnel).
19
21
 
20
22
  ## Docker
package/README.zh-CN.md CHANGED
@@ -11,10 +11,12 @@
11
11
  ## 安装
12
12
 
13
13
  ```bash
14
- npm install -g herdr-remote-relay
14
+ npm install -g https://github.com/dibin666/herdr-remote/releases/latest/download/herdr-remote-relay.tgz
15
15
  herdr-remote-relay --public-url https://herdr.example.com --password <密码>
16
16
  ```
17
17
 
18
+ 也可从 npm 安装:`npm install -g herdr-remote-relay`(新版本上线后 npm 可能要过一段时间才同步)。
19
+
18
20
  前置要求:Node.js 22+、TLS 反向代理(nginx、Caddy、Cloudflare Tunnel 等)。
19
21
 
20
22
  ## Docker 运行
@@ -3,4 +3,5 @@ export * from './terminal.js';
3
3
  export * from './herdr-keys.js';
4
4
  export * from './messages.js';
5
5
  export * from './paste.js';
6
+ export * from './release.js';
6
7
  export type * from './http.js';
@@ -6,3 +6,4 @@ export * from './terminal.js';
6
6
  export * from './herdr-keys.js';
7
7
  export * from './messages.js';
8
8
  export * from './paste.js';
9
+ export * from './release.js';
@@ -0,0 +1,8 @@
1
+ /** Also the name an update check reports as its source. */
2
+ export declare const GITHUB_RELEASES_URL = "https://github.com/dibin666/herdr-remote/releases";
3
+ /** `{ schema, version, tag, relayVersion, tarball }`, attached to every release. */
4
+ export declare const LATEST_RELEASE_MANIFEST_URL = "https://github.com/dibin666/herdr-remote/releases/latest/download/latest.json";
5
+ /** The newest self-contained CLI tarball, for a workstation that cannot say which it needs. */
6
+ export declare const LATEST_CLI_TARBALL_URL = "https://github.com/dibin666/herdr-remote/releases/latest/download/herdr-remote.tgz";
7
+ /** One CLI release's self-contained tarball; it bundles the relay it was released with. */
8
+ export declare function cliTarballUrl(version: string): string;
@@ -0,0 +1,17 @@
1
+ // Where herdr-remote is released. The CLI updates from here and the browser
2
+ // shows the same addresses in its manual steps, so there is one definition.
3
+ //
4
+ // GitHub Releases is the primary channel: a release is downloadable the moment
5
+ // it is created, whereas npm can take many minutes after `npm publish` before
6
+ // a new version installs. npm carries the same tarballs as a fallback.
7
+ const RELEASE_REPOSITORY = 'dibin666/herdr-remote';
8
+ /** Also the name an update check reports as its source. */
9
+ export const GITHUB_RELEASES_URL = `https://github.com/${RELEASE_REPOSITORY}/releases`;
10
+ /** `{ schema, version, tag, relayVersion, tarball }`, attached to every release. */
11
+ export const LATEST_RELEASE_MANIFEST_URL = `${GITHUB_RELEASES_URL}/latest/download/latest.json`;
12
+ /** The newest self-contained CLI tarball, for a workstation that cannot say which it needs. */
13
+ export const LATEST_CLI_TARBALL_URL = `${GITHUB_RELEASES_URL}/latest/download/herdr-remote.tgz`;
14
+ /** One CLI release's self-contained tarball; it bundles the relay it was released with. */
15
+ export function cliTarballUrl(version) {
16
+ return `${GITHUB_RELEASES_URL}/download/herdr-remote-v${version}/herdr-remote-${version}.tgz`;
17
+ }
@@ -21,6 +21,8 @@ export interface RelayServerOptions {
21
21
  devLatencyMs?: number | string;
22
22
  metrics?: RelayMetrics;
23
23
  auth?: AuthStore;
24
+ /** The built web client to serve; defaults to the package's `web/dist`. */
25
+ publicDir?: string;
24
26
  }
25
27
  export type RelayAddress = {
26
28
  host: string;
@@ -47,6 +49,7 @@ declare class RelayServer implements RelayContext {
47
49
  trustProxy: boolean;
48
50
  devLatencyMs: number;
49
51
  devDelayMs: number;
52
+ publicDir: string;
50
53
  sendQueues: WeakMap<RelaySocket, SendQueue>;
51
54
  activeDelayTimers: Set<NodeJS.Timeout>;
52
55
  auth: AuthStore;
@@ -10,7 +10,7 @@ import { PROTOCOL_VERSION, WS_CLIENT_PATH, WS_HOST_PATH } from './protocol/index
10
10
  import { DEFAULTS, defaultStateDir, loadRelayConfig } from './relay-config.js';
11
11
  import { handleClientConnection } from './server/client-channel.js';
12
12
  import { handleHostConnection } from './server/host-channel.js';
13
- import { handleHttp } from './server/http-api.js';
13
+ import { handleHttp, PUBLIC_DIR } from './server/http-api.js';
14
14
  import { heartbeat, sweep } from './server/maintenance.js';
15
15
  import { isAllowedOrigin } from './server/requests.js';
16
16
  import { detachClient, detachHost } from './server/sessions.js';
@@ -35,6 +35,7 @@ class RelayServer {
35
35
  trustProxy;
36
36
  devLatencyMs;
37
37
  devDelayMs;
38
+ publicDir;
38
39
  sendQueues = new WeakMap();
39
40
  activeDelayTimers = new Set();
40
41
  auth;
@@ -57,6 +58,7 @@ class RelayServer {
57
58
  this.password = options.password ?? auth.password ?? null;
58
59
  this.adminToken = options.adminToken ?? auth.adminToken ?? null;
59
60
  this.trustProxy = Boolean(options.trustProxy ?? relay.trustProxy);
61
+ this.publicDir = path.resolve(options.publicDir ?? PUBLIC_DIR);
60
62
  // Development-only artificial latency switch for local responsiveness profiling.
61
63
  // When unset or 0, this incurs zero overhead and avoids entering the delayed path.
62
64
  // RELAY_DEV_LATENCY_MS specifies round-trip delay, so each one-way leg
@@ -1,3 +1,4 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import type { RelayContext } from './types.js';
3
+ export declare const PUBLIC_DIR: string;
3
4
  export declare function handleHttp(relay: RelayContext, req: IncomingMessage, res: ServerResponse): void;
@@ -10,7 +10,8 @@ import { detachDeviceSessions } from './sessions.js';
10
10
  import { isOpen } from './sockets.js';
11
11
  import { statusSnapshot } from './status.js';
12
12
  import { VERSION } from './version.js';
13
- const PUBLIC_DIR = path.join(PACKAGE_ROOT, 'web', 'dist');
13
+ export const PUBLIC_DIR = path.join(PACKAGE_ROOT, 'web', 'dist');
14
+ const FONT_CACHE_SECONDS = 7 * 24 * 60 * 60;
14
15
  const MIME_TYPES = {
15
16
  '.html': 'text/html; charset=utf-8',
16
17
  '.js': 'text/javascript; charset=utf-8',
@@ -179,21 +180,21 @@ export function handleHttp(relay, req, res) {
179
180
  sendError(res, 404, 'not_found', 'API route not found');
180
181
  return;
181
182
  }
182
- serveStatic(pathname, res);
183
+ serveStatic(relay.publicDir, pathname, res);
183
184
  }
184
- function serveStatic(requestPath, res) {
185
+ function serveStatic(publicDir, requestPath, res) {
185
186
  const relative = requestPath === '/' || requestPath === '/admin'
186
187
  ? 'index.html'
187
188
  : requestPath.replace(/^\/+/, '');
188
- const candidate = path.resolve(PUBLIC_DIR, relative);
189
- if (!candidate.startsWith(`${PUBLIC_DIR}${path.sep}`) &&
190
- candidate !== path.join(PUBLIC_DIR, 'index.html')) {
189
+ const candidate = path.resolve(publicDir, relative);
190
+ if (!candidate.startsWith(`${publicDir}${path.sep}`) &&
191
+ candidate !== path.join(publicDir, 'index.html')) {
191
192
  sendError(res, 403, 'forbidden', 'path is not allowed');
192
193
  return;
193
194
  }
194
195
  fs.readFile(candidate, (error, data) => {
195
196
  if (error && !path.extname(relative)) {
196
- fs.readFile(path.join(PUBLIC_DIR, 'index.html'), (fallbackError, fallbackData) => {
197
+ fs.readFile(path.join(publicDir, 'index.html'), (fallbackError, fallbackData) => {
197
198
  if (fallbackError) {
198
199
  sendError(res, 503, 'web_not_built', 'frontend has not been built');
199
200
  return;
@@ -209,6 +210,10 @@ function serveStatic(requestPath, res) {
209
210
  }
210
211
  const extension = path.extname(candidate).toLowerCase();
211
212
  setResponseHeaders(res, MIME_TYPES[extension] || 'application/octet-stream');
213
+ // The bundled fonts run to megabytes and only change with a release; a
214
+ // week is short enough that a font upgrade still arrives.
215
+ if (relative.startsWith('fonts/'))
216
+ res.setHeader('Cache-Control', `public, max-age=${FONT_CACHE_SECONDS}`);
212
217
  res.end(data);
213
218
  });
214
219
  }
@@ -118,6 +118,8 @@ export interface RelayContext {
118
118
  trustProxy: boolean;
119
119
  devLatencyMs: number;
120
120
  devDelayMs: number;
121
+ /** Where the built web client is served from. */
122
+ publicDir: string;
121
123
  sendQueues: WeakMap<RelaySocket, SendQueue>;
122
124
  activeDelayTimers: Set<NodeJS.Timeout>;
123
125
  finishHandshake(ws: RelaySocket): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "herdr-remote-relay",
3
- "version": "0.3.25",
3
+ "version": "0.3.27",
4
4
  "description": "Standalone relay server and web terminal for Herdr Remote",
5
5
  "license": "MIT",
6
6
  "type": "module",