agent-relay-server 0.4.20 → 0.4.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.4.20",
3
+ "version": "0.4.21",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -95,7 +95,7 @@
95
95
 
96
96
  function upsertById(list, item) {
97
97
  const idx = list.findIndex((existing) => existing.id === item.id);
98
- if (idx >= 0) list[idx] = item;
98
+ if (idx >= 0) list.splice(idx, 1, item);
99
99
  else list.push(item);
100
100
  }
101
101
 
@@ -126,11 +126,18 @@
126
126
  function createLifecycleMethods() {
127
127
  return {
128
128
  async init() {
129
+ this.startClock();
130
+ watchPersistedPrefs(this);
131
+
132
+ try {
133
+ this.stats = await this.api("GET", "/stats");
134
+ } catch {
135
+ if (this.authNeeded) return;
136
+ }
137
+
129
138
  await this.refresh();
130
139
  this.connectSSE();
131
- this.startClock();
132
140
  this.startAutoRefresh();
133
- watchPersistedPrefs(this);
134
141
  },
135
142
 
136
143
  save(key, value) {
package/public/index.html CHANGED
@@ -102,7 +102,7 @@
102
102
  <div class="ar-sidebar-footer">
103
103
  <div class="d-flex align-items-center gap-2 mb-2">
104
104
  <span class="status-dot" :class="connected ? 'online' : 'offline'"></span>
105
- <span class="small" x-text="connected ? 'Live' : 'Reconnecting…'"></span>
105
+ <span class="small" x-text="authNeeded ? 'Auth required' : connected ? 'Live' : 'Reconnecting…'"></span>
106
106
  </div>
107
107
  <div class="d-flex align-items-center gap-2 mb-2">
108
108
  <label class="form-check form-switch mb-0">
package/src/security.ts CHANGED
@@ -19,10 +19,21 @@ export function isOriginAllowed(req: Request): boolean {
19
19
  if (!origin) return true;
20
20
  const origins = corsOrigins();
21
21
  if (origins.includes("*")) return true;
22
+ if (origins.includes(origin)) return true;
22
23
 
23
24
  const url = new URL(req.url);
24
25
  const sameOrigin = `${url.protocol}//${url.host}`;
25
- return origin === sameOrigin || origins.includes(origin);
26
+ if (origin === sameOrigin) return true;
27
+
28
+ // Behind a reverse proxy, req.url is the backend address (e.g. http://127.0.0.1:4850)
29
+ // while the browser sends the public origin. Check forwarded headers.
30
+ try {
31
+ const originHost = new URL(origin).host;
32
+ const fwdHost = req.headers.get("x-forwarded-host");
33
+ if (fwdHost && originHost === fwdHost) return true;
34
+ } catch {}
35
+
36
+ return false;
26
37
  }
27
38
 
28
39
  export function applyCors(req: Request, response: Response): Response {
@@ -117,7 +128,7 @@ export function unauthorized(req: Request): Response {
117
128
  }
118
129
 
119
130
  function authToken(): string {
120
- return process.env.AGENT_RELAY_TOKEN || AUTH_TOKEN;
131
+ return process.env.AGENT_RELAY_TOKEN ?? AUTH_TOKEN;
121
132
  }
122
133
 
123
134
  function extractToken(req: Request): string | null {