@suveren/gateway 0.7.0 → 0.7.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.
@@ -2067,6 +2067,37 @@ function createGatewaySettingsRouter() {
2067
2067
  return router;
2068
2068
  }
2069
2069
 
2070
+ // src/routes/internal-events.ts
2071
+ import { Router as Router11 } from "express";
2072
+ import { timingSafeEqual as timingSafeEqual2 } from "crypto";
2073
+ var ALLOWED = ["proposal-added", "action-approval-needed"];
2074
+ function secretMatches(provided, expected) {
2075
+ if (!expected) return false;
2076
+ if (!provided) return false;
2077
+ const a = Buffer.from(provided);
2078
+ const b = Buffer.from(expected);
2079
+ if (a.length !== b.length) return false;
2080
+ return timingSafeEqual2(a, b);
2081
+ }
2082
+ function createInternalEventsRouter(getSecret) {
2083
+ const router = Router11();
2084
+ router.post("/event", (req, res) => {
2085
+ if (!secretMatches(req.headers["x-internal-secret"], getSecret())) {
2086
+ res.status(401).json({ error: "Unauthorized" });
2087
+ return;
2088
+ }
2089
+ const type = (req.body ?? {}).type;
2090
+ if (typeof type !== "string" || !ALLOWED.includes(type)) {
2091
+ res.status(400).json({ error: "Unsupported event type" });
2092
+ return;
2093
+ }
2094
+ console.error(`[Control Plane] Internal event received: ${type}`);
2095
+ eventBus.emit(type);
2096
+ res.json({ ok: true });
2097
+ });
2098
+ return router;
2099
+ }
2100
+
2070
2101
  // src/lib/notification-dispatcher.ts
2071
2102
  var TRIGGER_EVENTS = ["proposal-added", "action-approval-needed"];
2072
2103
  var TITLE = "Suveren";
@@ -2132,6 +2163,9 @@ var NotificationDispatcher = class {
2132
2163
  } catch {
2133
2164
  enabled = true;
2134
2165
  }
2166
+ console.error(
2167
+ `[Control Plane] Review pending \u2014 desktop notification ${enabled ? "sent" : "suppressed (turned off)"}`
2168
+ );
2135
2169
  if (enabled) {
2136
2170
  const message = count >= FLOOD_THRESHOLD ? floodMessage(count) : WAITING_MESSAGE;
2137
2171
  this.notifyFn(TITLE, message, process.platform, this.url);
@@ -2420,6 +2454,7 @@ app.get("/auth/oauth/:integrationId/health", authGuard, async (req, res) => {
2420
2454
  }
2421
2455
  });
2422
2456
  app.get("/events", requireAllowedHost, requireAuthQueryOrHeader(vault), createEventsHandler());
2457
+ app.use("/internal", jsonParser, createInternalEventsRouter(() => internalSecret2));
2423
2458
  app.use("/vault", jsonParser, authGuard, createVaultRouter(vault));
2424
2459
  app.use("/ai", jsonParser, authGuard, createAIRouter(vault));
2425
2460
  app.use("/ai-prompts", jsonParser, authGuard, createAIPromptsRouter());
@@ -6,6 +6,33 @@ import express from "express";
6
6
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
7
7
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
8
8
 
9
+ // src/lib/cp-notify.ts
10
+ var CP_PORT = process.env.SUVEREN_CP_PORT ?? "3402";
11
+ var CP_BASE = process.env.SUVEREN_CP_INTERNAL_URL ?? `http://127.0.0.1:${CP_PORT}`;
12
+ var TIMEOUT_MS = 2e3;
13
+ async function notifyControlPlane(type) {
14
+ const secret = process.env.SUVEREN_INTERNAL_SECRET ?? "";
15
+ if (!secret) return;
16
+ try {
17
+ const controller = new AbortController();
18
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
19
+ try {
20
+ await fetch(`${CP_BASE}/internal/event`, {
21
+ method: "POST",
22
+ headers: {
23
+ "Content-Type": "application/json",
24
+ "X-Internal-Secret": secret
25
+ },
26
+ body: JSON.stringify({ type }),
27
+ signal: controller.signal
28
+ });
29
+ } finally {
30
+ clearTimeout(timer);
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+
9
36
  // src/lib/sp-client.ts
10
37
  var SPReceiptError = class extends Error {
11
38
  constructor(message, statusCode, body) {
@@ -167,6 +194,7 @@ var SPClient = class {
167
194
  const body = await res.json().catch(() => ({}));
168
195
  throw new Error(body.error ?? `SP proposal submission failed: ${res.status}`);
169
196
  }
197
+ void notifyControlPlane("proposal-added");
170
198
  return res.json();
171
199
  }
172
200
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suveren/gateway",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Suveren gateway — local agent gateway built in compliance with the Human Agency Protocol (HAP). Runs the UI, control plane, and MCP server in one Node process.",
5
5
  "type": "module",
6
6
  "main": "server.js",