@alfe.ai/gateway 0.10.4 → 0.10.5

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 (2) hide show
  1. package/dist/health.js +41 -0
  2. package/package.json +2 -2
package/dist/health.js CHANGED
@@ -7633,9 +7633,13 @@ async function stopExistingDaemon() {
7633
7633
  * Each connected plugin registers with its name/version and receives
7634
7634
  * commands from the daemon (forwarded from cloud).
7635
7635
  */
7636
+ /** Same-PID re-registrations inside this window before the flap warning fires. */
7637
+ const SAME_PID_FLAP_WINDOW_MS = 6e4;
7636
7638
  var IPCServer = class {
7637
7639
  server = null;
7638
7640
  connections = /* @__PURE__ */ new Map();
7641
+ samePidReplacements = /* @__PURE__ */ new Map();
7642
+ samePidFlapWarnedAt = /* @__PURE__ */ new Map();
7639
7643
  socketPath;
7640
7644
  requestHandler = null;
7641
7645
  constructor(socketPath, daemonVersion = "unknown") {
@@ -7696,6 +7700,8 @@ var IPCServer = class {
7696
7700
  });
7697
7701
  for (const conn of this.connections.values()) conn.socket.destroy();
7698
7702
  this.connections.clear();
7703
+ this.samePidReplacements.clear();
7704
+ this.samePidFlapWarnedAt.clear();
7699
7705
  });
7700
7706
  }
7701
7707
  /**
@@ -7871,6 +7877,40 @@ var IPCServer = class {
7871
7877
  }, "IPC: unhandled message");
7872
7878
  }
7873
7879
  }
7880
+ /**
7881
+ * A plugin that keeps re-registering from the SAME process is two live
7882
+ * clients in one process evicting each other (two module instances of
7883
+ * the plugin, each with its own socket), not a reconnect after a fault.
7884
+ * Each eviction fails every request in flight on the evicted socket, so
7885
+ * the symptom downstream is "Connection closed" on any call longer than
7886
+ * the client's reconnect backoff (Wibke Jnr, 2026-09-21: 2 evictions/s,
7887
+ * every per-business MYOB call dead). The dedupe above is still right
7888
+ * (a genuinely stale socket must be dropped), so make the flap loud
7889
+ * instead: one warning per plugin per minute once it exceeds the rate.
7890
+ */
7891
+ noteSamePidReplacement(name, pid) {
7892
+ const key = `${name}:${String(pid)}`;
7893
+ const now = Date.now();
7894
+ for (const [k, ts] of this.samePidReplacements) {
7895
+ if (k === key) continue;
7896
+ if (now - (ts[ts.length - 1] ?? 0) >= 6e4) {
7897
+ this.samePidReplacements.delete(k);
7898
+ this.samePidFlapWarnedAt.delete(k);
7899
+ }
7900
+ }
7901
+ const times = (this.samePidReplacements.get(key) ?? []).filter((t) => now - t < SAME_PID_FLAP_WINDOW_MS);
7902
+ times.push(now);
7903
+ this.samePidReplacements.set(key, times);
7904
+ if (times.length < 10) return;
7905
+ if (now - (this.samePidFlapWarnedAt.get(key) ?? 0) < 6e4) return;
7906
+ this.samePidFlapWarnedAt.set(key, now);
7907
+ logger.warn({
7908
+ plugin: name,
7909
+ pid,
7910
+ replacements: times.length,
7911
+ windowMs: SAME_PID_FLAP_WINDOW_MS
7912
+ }, "IPC: plugin is re-registering from the same process in a loop — two IPC clients in one process are evicting each other; in-flight requests fail with \"Connection closed\"");
7913
+ }
7874
7914
  closeOversizedConnection(conn) {
7875
7915
  logger.warn({
7876
7916
  connId: conn.id,
@@ -7923,6 +7963,7 @@ var IPCServer = class {
7923
7963
  plugin: name,
7924
7964
  pid
7925
7965
  }, "IPC: closing stale duplicate connection (same PID)");
7966
+ this.noteSamePidReplacement(name, pid);
7926
7967
  existing.socket.destroy();
7927
7968
  staleIds.push(existingId);
7928
7969
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/gateway",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "description": "Alfe local gateway daemon — persistent control plane for agent integrations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "@alfe.ai/ai-proxy-local": "^0.0.17",
28
28
  "@alfe.ai/config": "^0.4.1",
29
29
  "@alfe.ai/integration-manifest": "^0.4.2",
30
- "@alfe.ai/integrations": "^0.6.10",
30
+ "@alfe.ai/integrations": "^0.6.11",
31
31
  "@alfe.ai/mcp-bundler": "^0.4.2"
32
32
  },
33
33
  "license": "UNLICENSED",