replica-bridge 0.3.1 → 0.3.2

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": "replica-bridge",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Lets the ChatReplica iPhone app use Codex on this computer through a relay, end-to-end encrypted.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@ import { loadState, saveState } from "./state.js";
8
8
 
9
9
 
10
10
  /** The project's public relay, which the app also signs in to by default (Sources/Core/RelayPairing.swift). */
11
- export const PUBLIC_RELAY = "https://agens.office-cli.onl";
11
+ export const PUBLIC_RELAY = "https://agensrelay.office-cli.onl";
12
12
 
13
13
  /** With no --relay: REPLICA_RELAY, else the relay on this machine over loopback, else the public relay. */
14
14
  export function defaultRelayURL() {
@@ -100,7 +100,14 @@ export class BridgeService {
100
100
  try { envelope = JSON.parse(data.toString()); } catch { return; }
101
101
  this.onEnvelope(envelope);
102
102
  });
103
- ws.on("unexpected-response", (_req, res) => this.log(`relay refused the host connection: HTTP ${res.statusCode}`));
103
+ // Something other than the relay answered (a web page where the relay used to be, a proxy error, a revoked
104
+ // token). With this listener ws leaves the socket half-open and emits no close, so nothing retried and the
105
+ // process ran out of work and exited 0, which the background services read as "replaced" and left stopped.
106
+ // Ending the socket goes through close and the usual backoff instead.
107
+ ws.on("unexpected-response", (_req, res) => {
108
+ this.log(`relay refused the host connection: HTTP ${res.statusCode}; retrying`);
109
+ ws.terminate();
110
+ });
104
111
  ws.on("error", (error) => this.log(`relay connection error: ${error.message}`));
105
112
  ws.on("close", (code) => {
106
113
  if (ws !== this.relay) return; // a socket this bridge already replaced itself
@@ -40,6 +40,8 @@ export function readEnvFile(file ) {
40
40
 
41
41
 
42
42
 
43
+
44
+
43
45
 
44
46
 
45
47
  /** "github:583231, 12345, *" → ["583231", "12345", "*"]; anything that is not a numeric id or * is refused. */
@@ -51,6 +53,30 @@ export function parseAllowedIds(text ) {
51
53
  });
52
54
  }
53
55
 
56
+ /** "~/repos/minim/deploy/minim.env:MINIM_ALLOW" → { file, name }. */
57
+ export function parseAllowedFrom(text ) {
58
+ const colon = text.lastIndexOf(":");
59
+ const file = text.slice(0, colon).trim();
60
+ const name = text.slice(colon + 1).trim();
61
+ if (colon < 1 || !file || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(`GITHUB_ALLOWED_USERS_FROM takes <env file>:<VARIABLE>, not "${text}"`);
62
+ return { file: expandHome(file), name };
63
+ }
64
+
65
+ /**
66
+ * The allowed GitHub ids: GITHUB_ALLOWED_USERS plus, when set, the list in GITHUB_ALLOWED_USERS_FROM, read again on
67
+ * every call so editing that file takes effect without a restart. A missing file or variable throws (nobody gets in).
68
+ */
69
+ export function allowedIdsReader(config ) {
70
+ const from = config.githubAllowedFrom;
71
+ if (!from) return () => config.githubAllowedIds;
72
+ return () => {
73
+ if (!fs.existsSync(from.file)) throw new Error(`GITHUB_ALLOWED_USERS_FROM: ${from.file} does not exist`);
74
+ const list = readEnvFile(from.file)[from.name];
75
+ if (list === undefined) throw new Error(`GITHUB_ALLOWED_USERS_FROM: ${from.file} has no ${from.name}`);
76
+ return [...new Set([...config.githubAllowedIds, ...parseAllowedIds(list)])];
77
+ };
78
+ }
79
+
54
80
  const expandHome = (value ) => (value.startsWith("~/") ? path.join(os.homedir(), value.slice(2)) : value);
55
81
 
56
82
  export function loadRelayConfig(envPath = defaultEnvPath()) {
@@ -72,5 +98,6 @@ export function loadRelayConfig(envPath = defaultEnvPath()) {
72
98
  githubClientSecret: get("GITHUB_CLIENT_SECRET"),
73
99
  githubCallbackUrl: get("GITHUB_CALLBACK_URL"),
74
100
  githubAllowedIds: parseAllowedIds(get("GITHUB_ALLOWED_USERS") ?? ""),
101
+ githubAllowedFrom: get("GITHUB_ALLOWED_USERS_FROM") ? parseAllowedFrom(get("GITHUB_ALLOWED_USERS_FROM") ) : null,
75
102
  };
76
103
  }