@suveren/gateway 0.2.0 → 0.2.3

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 (40) hide show
  1. package/dist/control-plane/index.mjs +25 -5
  2. package/dist/mcp-server/http.mjs +48 -17
  3. package/dist/ui/assets/{index-CqecIRqd.js → index-CIhRJ6MD.js} +23 -22
  4. package/dist/ui/index.html +1 -1
  5. package/dist/ui/mockups/intent-redesign.html +1 -1
  6. package/node_modules/eventsource-parser/README.md +31 -0
  7. package/node_modules/eventsource-parser/dist/index.cjs +21 -10
  8. package/node_modules/eventsource-parser/dist/index.cjs.map +1 -1
  9. package/node_modules/eventsource-parser/dist/index.d.cts +33 -10
  10. package/node_modules/eventsource-parser/dist/index.d.ts +33 -10
  11. package/node_modules/eventsource-parser/dist/index.js +21 -10
  12. package/node_modules/eventsource-parser/dist/index.js.map +1 -1
  13. package/node_modules/eventsource-parser/dist/stream.cjs +4 -3
  14. package/node_modules/eventsource-parser/dist/stream.cjs.map +1 -1
  15. package/node_modules/eventsource-parser/dist/stream.d.cts +16 -3
  16. package/node_modules/eventsource-parser/dist/stream.d.ts +16 -3
  17. package/node_modules/eventsource-parser/dist/stream.js +4 -3
  18. package/node_modules/eventsource-parser/dist/stream.js.map +1 -1
  19. package/node_modules/eventsource-parser/package.json +8 -8
  20. package/node_modules/eventsource-parser/src/errors.ts +1 -1
  21. package/node_modules/eventsource-parser/src/index.ts +6 -1
  22. package/node_modules/eventsource-parser/src/parse.ts +55 -13
  23. package/node_modules/eventsource-parser/src/stream.ts +24 -5
  24. package/node_modules/eventsource-parser/src/types.ts +25 -0
  25. package/node_modules/hasown/CHANGELOG.md +7 -0
  26. package/node_modules/hasown/index.d.ts +0 -1
  27. package/node_modules/hasown/package.json +4 -5
  28. package/node_modules/hono/dist/cjs/index.js +3 -0
  29. package/node_modules/hono/dist/cjs/middleware/compress/index.js +10 -4
  30. package/node_modules/hono/dist/cjs/utils/filepath.js +1 -1
  31. package/node_modules/hono/dist/cjs/utils/ipaddr.js +1 -1
  32. package/node_modules/hono/dist/index.js +2 -0
  33. package/node_modules/hono/dist/middleware/compress/index.js +9 -4
  34. package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +1 -1
  35. package/node_modules/hono/dist/types/index.d.ts +2 -1
  36. package/node_modules/hono/dist/types/middleware/compress/index.d.ts +11 -1
  37. package/node_modules/hono/dist/utils/filepath.js +1 -1
  38. package/node_modules/hono/dist/utils/ipaddr.js +1 -1
  39. package/node_modules/hono/package.json +1 -1
  40. package/package.json +1 -1
@@ -197,7 +197,7 @@ var Vault = class {
197
197
  import { Router } from "express";
198
198
 
199
199
  // src/lib/mcp-bridge.ts
200
- var MCP_BASE = process.env.HAP_MCP_INTERNAL_URL ?? "http://127.0.0.1:3430";
200
+ var MCP_BASE = process.env.SUVEREN_MCP_INTERNAL_URL ?? "http://127.0.0.1:3430";
201
201
  var internalSecret = "";
202
202
  function setInternalSecret(secret) {
203
203
  internalSecret = secret;
@@ -854,7 +854,7 @@ ${contextParts.join("\n")}` : "",
854
854
  }
855
855
  }
856
856
  var CHAT_SYSTEM_PROMPTS = {
857
- context: `You help a human author "context.md" \u2014 the standing-orders brief that is prepended to every AI agent session under the Human Agency Protocol (HAP).
857
+ context: `You help a human author "context.md" \u2014 the standing-orders brief that Suveren prepends to every AI agent session it gates.
858
858
 
859
859
  This text goes straight into the system prompt of downstream agents. Keep it operational, concrete, and short. Favor examples the user would recognize from their work.
860
860
 
@@ -870,7 +870,7 @@ When you propose a complete draft (or a full-document rewrite) of the context, w
870
870
  \`\`\`
871
871
 
872
872
  Only use that fence for full-document drafts the user can click "Apply". For partial suggestions, comments, or questions, write prose without the fence.`,
873
- intent: `You help a human write an "Intent" paragraph for an AI agent authorization under the Human Agency Protocol (HAP).
873
+ intent: `You help a human write an "Intent" paragraph for an AI agent authorization issued by Suveren.
874
874
 
875
875
  The Intent is read by two audiences:
876
876
  1. The agent, on demand via list-authorizations(domain), when it's about to act in this domain.
@@ -1391,6 +1391,9 @@ function createApprovedIntentsRouter(vault2) {
1391
1391
  }
1392
1392
 
1393
1393
  // src/lib/update-checker.ts
1394
+ import { execSync } from "child_process";
1395
+ import { dirname as dirname2 } from "path";
1396
+ import { fileURLToPath } from "url";
1394
1397
  var GHCR_IMAGE = "suverenai/suveren-gateway";
1395
1398
  var NPM_PACKAGE = "@suveren/gateway";
1396
1399
  var CHECK_INTERVAL = 60 * 60 * 1e3;
@@ -1454,11 +1457,28 @@ function compareSemver(a, b) {
1454
1457
  }
1455
1458
  return 0;
1456
1459
  }
1460
+ function checkDev() {
1461
+ const cwd = dirname2(fileURLToPath(import.meta.url));
1462
+ try {
1463
+ execSync("git fetch origin --quiet", { cwd, stdio: "ignore", timeout: 15e3 });
1464
+ const out = execSync("git rev-list HEAD..origin/main --count", {
1465
+ cwd,
1466
+ encoding: "utf8",
1467
+ timeout: 5e3
1468
+ }).trim();
1469
+ const behind = parseInt(out, 10) || 0;
1470
+ updateAvailable = behind > 0;
1471
+ latestVersion = behind > 0 ? `${behind} commit${behind === 1 ? "" : "s"} behind origin/main` : null;
1472
+ } catch {
1473
+ updateAvailable = false;
1474
+ latestVersion = null;
1475
+ }
1476
+ lastCheckedAt = Date.now();
1477
+ }
1457
1478
  async function check() {
1458
1479
  try {
1459
1480
  if (installMethod === "dev") {
1460
- updateAvailable = true;
1461
- lastCheckedAt = Date.now();
1481
+ checkDev();
1462
1482
  return;
1463
1483
  }
1464
1484
  if (installMethod === "npm") {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/http.ts
4
- import { randomUUID } from "crypto";
4
+ import { randomUUID as randomUUID2 } from "crypto";
5
5
  import express from "express";
6
6
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
7
7
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
@@ -15,12 +15,19 @@ var SPReceiptError = class extends Error {
15
15
  this.name = "SPReceiptError";
16
16
  }
17
17
  };
18
+ var DEFAULT_RECEIPT_RETRY = {
19
+ maxAttempts: 3,
20
+ delaysMs: [100, 300]
21
+ };
22
+ var sleep = (ms) => ms > 0 ? new Promise((resolve3) => setTimeout(resolve3, ms)) : Promise.resolve();
18
23
  var SPClient = class {
19
- constructor(baseUrl) {
24
+ constructor(baseUrl, receiptRetry = {}) {
20
25
  this.baseUrl = baseUrl;
26
+ this.receiptRetry = { ...DEFAULT_RECEIPT_RETRY, ...receiptRetry };
21
27
  }
22
28
  sessionCookie = "";
23
29
  apiKey = "";
30
+ receiptRetry;
24
31
  setApiKey(key) {
25
32
  this.apiKey = key;
26
33
  }
@@ -89,18 +96,39 @@ var SPClient = class {
89
96
  * Errors throw SPReceiptError with the structured `errors` array in `body`.
90
97
  */
91
98
  async postReceipt(data) {
92
- const res = await this.fetch("/api/as/receipt", {
93
- method: "POST",
94
- body: JSON.stringify(data)
95
- });
96
- const body = await res.json().catch(() => ({}));
97
- if (!res.ok || body.approved === false) {
98
- const errors = body.errors;
99
- const first = errors?.[0];
100
- const message = first?.message ?? first?.code ?? body.error ?? `SP receipt request failed: ${res.status}`;
101
- throw new SPReceiptError(message, res.status, body);
99
+ const body = JSON.stringify(data);
100
+ const maxAttempts = data.idempotencyKey ? this.receiptRetry.maxAttempts : 1;
101
+ let lastError;
102
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
103
+ const isLast = attempt === maxAttempts;
104
+ let res;
105
+ try {
106
+ res = await this.fetch("/api/as/receipt", { method: "POST", body });
107
+ } catch (err) {
108
+ lastError = err;
109
+ if (isLast) throw err;
110
+ await sleep(this.receiptRetry.delaysMs[attempt - 1] ?? 0);
111
+ continue;
112
+ }
113
+ const respBody = await res.json().catch(() => ({}));
114
+ if (res.status >= 500 && !isLast) {
115
+ lastError = new SPReceiptError(
116
+ `SP receipt request failed: ${res.status}`,
117
+ res.status,
118
+ respBody
119
+ );
120
+ await sleep(this.receiptRetry.delaysMs[attempt - 1] ?? 0);
121
+ continue;
122
+ }
123
+ if (!res.ok || respBody.approved === false) {
124
+ const errors = respBody.errors;
125
+ const first = errors?.[0];
126
+ const message = first?.message ?? first?.code ?? respBody.error ?? `SP receipt request failed: ${res.status}`;
127
+ throw new SPReceiptError(message, res.status, respBody);
128
+ }
129
+ return { receipt: respBody.receipt };
102
130
  }
103
- return { receipt: body.receipt };
131
+ throw lastError ?? new Error("postReceipt: retries exhausted");
104
132
  }
105
133
  /**
106
134
  * Submit a proposal for deferred commitment review.
@@ -818,7 +846,8 @@ function countToolsByGating(profileId, integrationManager2) {
818
846
  function buildMandateBrief(opts) {
819
847
  const { authorizations, executionLog, integrationManager: integrationManager2, contextDir } = opts;
820
848
  const lines = [
821
- "You are an agent operating under the Human Agency Protocol (HAP).",
849
+ "You are connected to Suveren \u2014 the gateway that gates every privileged tool call you make.",
850
+ "Suveren implements the bounded-authority model from the open Human Agency Protocol (HAP).",
822
851
  "You have bounded authorities granted by human decision owners.",
823
852
  "You MUST stay within these bounds \u2014 the Gatekeeper will reject actions that exceed them."
824
853
  ];
@@ -878,6 +907,7 @@ import { getProfile as getProfile2 } from "@hap/core";
878
907
  // src/lib/tool-proxy.ts
879
908
  import { readFile } from "fs/promises";
880
909
  import { extname } from "path";
910
+ import { randomUUID } from "crypto";
881
911
  var IMAGE_MIME = {
882
912
  ".jpg": "image/jpeg",
883
913
  ".jpeg": "image/jpeg",
@@ -1048,7 +1078,8 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
1048
1078
  action: tool.namespacedName,
1049
1079
  actionType,
1050
1080
  executionContext: { ...execution },
1051
- amount: typeof execution.amount === "number" ? execution.amount : void 0
1081
+ amount: typeof execution.amount === "number" ? execution.amount : void 0,
1082
+ idempotencyKey: randomUUID()
1052
1083
  });
1053
1084
  } catch (err) {
1054
1085
  if (err instanceof SPReceiptError && err.statusCode === 409) {
@@ -1427,7 +1458,7 @@ function listIntegrationsHandler(state2, integrationManager2) {
1427
1458
  if (matchingAuths.length > 0) {
1428
1459
  const soonestExpiry = Math.min(
1429
1460
  ...matchingAuths.flatMap(
1430
- (a) => a.attestations.map((att) => att.expires_at)
1461
+ (a) => a.attestations.map((att) => att.expiresAt)
1431
1462
  )
1432
1463
  );
1433
1464
  const remainingMs = soonestExpiry * 1e3 - Date.now();
@@ -2497,7 +2528,7 @@ app.all("/mcp", async (req, res) => {
2497
2528
  }
2498
2529
  if (req.method === "POST" && !sessionId) {
2499
2530
  const transport = new StreamableHTTPServerTransport({
2500
- sessionIdGenerator: () => randomUUID()
2531
+ sessionIdGenerator: () => randomUUID2()
2501
2532
  });
2502
2533
  transport.onclose = () => {
2503
2534
  if (transport.sessionId) {