@suveren/gateway 0.7.1 → 0.7.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.
- package/README.md +10 -1
- package/bin/suveren-gateway.js +24 -5
- package/dist/control-plane/index.mjs +191 -67
- package/dist/ui/assets/index-DdJeSfV9.js +110 -0
- package/dist/ui/index.html +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@types/node/v8.d.ts +20 -23
- package/package.json +1 -1
- package/dist/ui/assets/index-DHT9QCrE.js +0 -110
package/README.md
CHANGED
|
@@ -119,7 +119,16 @@ suveren-gateway stop # stop a detached run
|
|
|
119
119
|
|
|
120
120
|
Open `http://localhost:3400`. The MCP server is at `http://localhost:3430`.
|
|
121
121
|
|
|
122
|
-
To upgrade later
|
|
122
|
+
To upgrade later, run these two commands:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
npm install -g @suveren/gateway@latest
|
|
126
|
+
suveren-gateway restart
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
(Written as two lines on purpose: `&&` is not a valid separator in Windows
|
|
130
|
+
PowerShell 5.1, which is what ships with Windows. Use `;` there if you want
|
|
131
|
+
them on one line.)
|
|
123
132
|
|
|
124
133
|
### Connecting an MCP client
|
|
125
134
|
|
package/bin/suveren-gateway.js
CHANGED
|
@@ -323,8 +323,14 @@ function serviceRunning() {
|
|
|
323
323
|
return p.status === 0 && /state = running/.test(p.stdout || '');
|
|
324
324
|
}
|
|
325
325
|
if (os === 'win32') {
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
// NOT schtasks /Query: its LIST output is localized — a German Windows
|
|
327
|
+
// prints "Wird ausgeführt", so matching the English word "Running" reports
|
|
328
|
+
// every non-English machine as stopped, and restart silently falls back to
|
|
329
|
+
// the manual path. Get-ScheduledTask's State is a .NET enum; its name is
|
|
330
|
+
// English on every locale.
|
|
331
|
+
const p = runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
332
|
+
`(Get-ScheduledTask -TaskName '${WIN_TASK_NAME}' -ErrorAction Stop).State`]);
|
|
333
|
+
return p.status === 0 && /^Running/m.test((p.stdout || '').trim());
|
|
328
334
|
}
|
|
329
335
|
const p = runQuiet('systemctl', ['--user', 'is-active', SYSTEMD_UNIT]);
|
|
330
336
|
return (p.stdout || '').trim() === 'active';
|
|
@@ -344,7 +350,16 @@ function serviceRestart() {
|
|
|
344
350
|
if (os === 'darwin') {
|
|
345
351
|
runQuiet('launchctl', ['kickstart', '-k', `gui/${process.getuid()}/${LAUNCH_AGENT_LABEL}`]);
|
|
346
352
|
} else if (os === 'win32') {
|
|
347
|
-
|
|
353
|
+
// NOT schtasks /End: it TerminateProcess()es only the task's ROOT process
|
|
354
|
+
// (node server.js). No signal is delivered, so the shutdown handlers never
|
|
355
|
+
// run and the control-plane / MCP children survive — still holding ports
|
|
356
|
+
// 3400/3430, which makes the relaunched instance die on EADDRINUSE and
|
|
357
|
+
// "restart" quietly become "stop". taskkill /T takes the whole tree.
|
|
358
|
+
const like = SERVER_ENTRY.replace(/'/g, "''").replace(/([\[\]*?])/g, '`$1');
|
|
359
|
+
runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
360
|
+
`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | ` +
|
|
361
|
+
`Where-Object { $_.CommandLine -like '*${like}*' } | ` +
|
|
362
|
+
`ForEach-Object { taskkill.exe /PID $_.ProcessId /T /F } | Out-Null`]);
|
|
348
363
|
runQuiet('schtasks', ['/Run', '/TN', WIN_TASK_NAME]);
|
|
349
364
|
} else {
|
|
350
365
|
runQuiet('systemctl', ['--user', 'restart', SYSTEMD_UNIT]);
|
|
@@ -573,8 +588,12 @@ async function serviceStatusWindows() {
|
|
|
573
588
|
console.log(`Login service: ${installed ? 'installed' : 'not installed'}`);
|
|
574
589
|
if (installed) {
|
|
575
590
|
console.log(` Task: ${WIN_TASK_NAME}`);
|
|
576
|
-
|
|
577
|
-
|
|
591
|
+
// Locale-independent state (see serviceRunning): the schtasks LIST value
|
|
592
|
+
// is localized; the PowerShell enum name is not.
|
|
593
|
+
const st = runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
594
|
+
`(Get-ScheduledTask -TaskName '${WIN_TASK_NAME}' -ErrorAction Stop).State`]);
|
|
595
|
+
const state = (st.stdout || '').trim();
|
|
596
|
+
if (st.status === 0 && state) console.log(` State: ${state}`);
|
|
578
597
|
}
|
|
579
598
|
}
|
|
580
599
|
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import { dirname as
|
|
10
|
-
import { homedir as
|
|
8
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, renameSync } from "fs";
|
|
9
|
+
import { dirname as dirname5, join as join6 } from "path";
|
|
10
|
+
import { homedir as homedir5 } from "os";
|
|
11
11
|
import express from "express";
|
|
12
12
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
13
13
|
|
|
@@ -685,6 +685,64 @@ function createAuthRouter(vault2, logoutAuth, loginRateLimit2) {
|
|
|
685
685
|
|
|
686
686
|
// src/routes/vault.ts
|
|
687
687
|
import { Router as Router2 } from "express";
|
|
688
|
+
|
|
689
|
+
// src/lib/credential-meta.ts
|
|
690
|
+
var META_KEY = "__updatedAt";
|
|
691
|
+
var MIN_PREVIEW_LENGTH = 12;
|
|
692
|
+
var PREFIX_RE = /^([A-Za-z][A-Za-z0-9]*(?:[-_][A-Za-z0-9]+)*[-_])/;
|
|
693
|
+
var MAX_PREFIX_LENGTH = 12;
|
|
694
|
+
var HIDDEN_FLOOR = 12;
|
|
695
|
+
function previewSecret(value) {
|
|
696
|
+
if (value.length < MIN_PREVIEW_LENGTH) return { preview: null };
|
|
697
|
+
const match = PREFIX_RE.exec(value)?.[1] ?? "";
|
|
698
|
+
const prefix = match && match.length <= MAX_PREFIX_LENGTH && value.length - match.length - 4 >= HIDDEN_FLOOR ? match : "";
|
|
699
|
+
if (!prefix && value.length - 4 < 8) return { preview: null };
|
|
700
|
+
return { preview: `${prefix}\u2026${value.slice(-4)}` };
|
|
701
|
+
}
|
|
702
|
+
var AI_CONFIG_TEXT_FIELDS = /* @__PURE__ */ new Set(["provider", "endpoint", "model"]);
|
|
703
|
+
function textFieldsFor(name, manifests) {
|
|
704
|
+
if (name === "ai-config") return AI_CONFIG_TEXT_FIELDS;
|
|
705
|
+
const list = Array.isArray(manifests) ? manifests : [];
|
|
706
|
+
const manifest = list.find((m) => m?.id === name);
|
|
707
|
+
const out = /* @__PURE__ */ new Set();
|
|
708
|
+
for (const f of manifest?.credentials?.fields ?? []) {
|
|
709
|
+
if (typeof f?.key === "string" && f?.type === "text") out.add(f.key);
|
|
710
|
+
}
|
|
711
|
+
return out;
|
|
712
|
+
}
|
|
713
|
+
function credentialView(cred, textFields) {
|
|
714
|
+
const fields = {};
|
|
715
|
+
const secrets = {};
|
|
716
|
+
let updatedAt;
|
|
717
|
+
for (const [key, value] of Object.entries(cred)) {
|
|
718
|
+
if (key === META_KEY) {
|
|
719
|
+
updatedAt = value;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
if (textFields.has(key)) fields[key] = value;
|
|
723
|
+
else secrets[key] = previewSecret(value);
|
|
724
|
+
}
|
|
725
|
+
return {
|
|
726
|
+
configured: true,
|
|
727
|
+
fieldNames: Object.keys(fields).concat(Object.keys(secrets)),
|
|
728
|
+
fields,
|
|
729
|
+
secrets,
|
|
730
|
+
...updatedAt ? { updatedAt } : {}
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/routes/vault.ts
|
|
735
|
+
var manifestCache = null;
|
|
736
|
+
async function cachedManifests() {
|
|
737
|
+
if (manifestCache && Date.now() - manifestCache.at < 6e4) return manifestCache.value;
|
|
738
|
+
try {
|
|
739
|
+
const m = await getManifests();
|
|
740
|
+
manifestCache = { at: Date.now(), value: m?.manifests ?? m };
|
|
741
|
+
} catch {
|
|
742
|
+
manifestCache = { at: Date.now(), value: [] };
|
|
743
|
+
}
|
|
744
|
+
return manifestCache.value;
|
|
745
|
+
}
|
|
688
746
|
function createVaultRouter(vault2) {
|
|
689
747
|
const router = Router2();
|
|
690
748
|
router.get("/status", (_req, res) => {
|
|
@@ -696,14 +754,14 @@ function createVaultRouter(vault2) {
|
|
|
696
754
|
serviceCount: services.length
|
|
697
755
|
});
|
|
698
756
|
});
|
|
699
|
-
router.get("/credentials/:name", (req, res) => {
|
|
757
|
+
router.get("/credentials/:name", async (req, res) => {
|
|
700
758
|
const { name } = req.params;
|
|
701
759
|
const cred = vault2.getCredential(name);
|
|
702
760
|
if (!cred) {
|
|
703
761
|
res.json({ configured: false });
|
|
704
762
|
return;
|
|
705
763
|
}
|
|
706
|
-
res.json(
|
|
764
|
+
res.json(credentialView(cred, textFieldsFor(name, await cachedManifests())));
|
|
707
765
|
});
|
|
708
766
|
router.put("/credentials/:name", async (req, res) => {
|
|
709
767
|
const { name } = req.params;
|
|
@@ -714,6 +772,7 @@ function createVaultRouter(vault2) {
|
|
|
714
772
|
if (existing) fields = { ...existing, ...incoming };
|
|
715
773
|
} catch {
|
|
716
774
|
}
|
|
775
|
+
fields = { ...fields, [META_KEY]: (/* @__PURE__ */ new Date()).toISOString() };
|
|
717
776
|
vault2.setCredential(name, fields);
|
|
718
777
|
try {
|
|
719
778
|
await pushServiceCredentials(name, fields);
|
|
@@ -1540,15 +1599,15 @@ import { promisify } from "util";
|
|
|
1540
1599
|
var run = promisify(execFile);
|
|
1541
1600
|
var SUPPORTED = /* @__PURE__ */ new Set(["darwin", "win32", "linux"]);
|
|
1542
1601
|
var MODULE_DIR = pathDirname(fileURLToPath(import.meta.url));
|
|
1543
|
-
function findCli(
|
|
1602
|
+
function findCli(dirname6 = MODULE_DIR) {
|
|
1544
1603
|
const candidates = [
|
|
1545
1604
|
// Bundled (the shipped layout): dist/control-plane → dist → root → bin
|
|
1546
|
-
resolve(
|
|
1605
|
+
resolve(dirname6, "..", "..", "bin", "suveren-gateway.js"),
|
|
1547
1606
|
// Bundled, were the routes/ directory ever preserved.
|
|
1548
|
-
resolve(
|
|
1607
|
+
resolve(dirname6, "..", "..", "..", "bin", "suveren-gateway.js"),
|
|
1549
1608
|
// Dev, running from source: the repo's own bundle directory.
|
|
1550
|
-
resolve(
|
|
1551
|
-
resolve(
|
|
1609
|
+
resolve(dirname6, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
|
|
1610
|
+
resolve(dirname6, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
|
|
1552
1611
|
// Deliberately NO process.cwd() fallback: it makes the result depend on
|
|
1553
1612
|
// where the process happened to be launched from, so the same install
|
|
1554
1613
|
// resolves differently between a shell and a login service — and it would
|
|
@@ -1633,38 +1692,86 @@ function createAutostartRouter() {
|
|
|
1633
1692
|
|
|
1634
1693
|
// src/lib/desktop-notify.ts
|
|
1635
1694
|
import { spawn, spawnSync } from "child_process";
|
|
1695
|
+
|
|
1696
|
+
// src/lib/notifier-icon.ts
|
|
1697
|
+
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
|
|
1698
|
+
import { homedir as homedir2 } from "os";
|
|
1699
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
1700
|
+
var ICON_BASE64 = "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";
|
|
1701
|
+
function ensureNotifierIcon(dataDir) {
|
|
1702
|
+
try {
|
|
1703
|
+
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join2(homedir2(), ".suveren");
|
|
1704
|
+
const path = join2(dir, "notifier-icon.png");
|
|
1705
|
+
if (!existsSync3(path)) {
|
|
1706
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
1707
|
+
writeFileSync2(path, Buffer.from(ICON_BASE64, "base64"));
|
|
1708
|
+
}
|
|
1709
|
+
return path;
|
|
1710
|
+
} catch {
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// src/lib/desktop-notify.ts
|
|
1636
1716
|
function osaQuote(value) {
|
|
1637
1717
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1638
1718
|
}
|
|
1639
1719
|
function psQuote(value) {
|
|
1640
1720
|
return `'${value.replace(/'/g, "''")}'`;
|
|
1641
1721
|
}
|
|
1722
|
+
function xmlEscape(value) {
|
|
1723
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1724
|
+
}
|
|
1725
|
+
var WINDOWS_AUMID = "Suveren.Gateway";
|
|
1726
|
+
function windowsToastScript(title, message, url, iconPath) {
|
|
1727
|
+
const toastXml = `<toast${url ? ` activationType="protocol" launch="${xmlEscape(url)}"` : ""}><visual><binding template="ToastGeneric"><text>${xmlEscape(title)}</text><text>${xmlEscape(message)}</text>` + (iconPath ? `<image placement="appLogoOverride" src="${xmlEscape(iconPath)}"/>` : "") + `</binding></visual><audio src="ms-winsoundevent:Notification.Default"/></toast>`;
|
|
1728
|
+
return `$ErrorActionPreference='SilentlyContinue'; $aumid=${psQuote(WINDOWS_AUMID)}; $reg="HKCU:\\Software\\Classes\\AppUserModelId\\$aumid"; if (-not (Test-Path $reg)) { New-Item -Path $reg -Force | Out-Null }; New-ItemProperty -Path $reg -Name DisplayName -Value 'Suveren' -PropertyType String -Force | Out-Null; ` + (iconPath ? `New-ItemProperty -Path $reg -Name IconUri -Value ${psQuote(iconPath)} -PropertyType String -Force | Out-Null; ` : "") + `[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] | Out-Null; [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom, ContentType=WindowsRuntime] | Out-Null; $doc = New-Object Windows.Data.Xml.Dom.XmlDocument; $doc.LoadXml(${psQuote(toastXml)}); $toast = New-Object Windows.UI.Notifications.ToastNotification $doc; [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($aumid).Show($toast)`;
|
|
1729
|
+
}
|
|
1730
|
+
var MAC_SOUND = "Glass";
|
|
1642
1731
|
function buildNotifyCommand(platform, title, message, options = {}) {
|
|
1643
|
-
const { url, hasTerminalNotifier: hasTerminalNotifier2 = false } = options;
|
|
1732
|
+
const { url, hasTerminalNotifier: hasTerminalNotifier2 = false, iconPath } = options;
|
|
1644
1733
|
switch (platform) {
|
|
1645
1734
|
case "darwin":
|
|
1646
1735
|
if (url && hasTerminalNotifier2) {
|
|
1647
1736
|
return {
|
|
1648
1737
|
cmd: "terminal-notifier",
|
|
1649
|
-
args: [
|
|
1738
|
+
args: [
|
|
1739
|
+
"-title",
|
|
1740
|
+
title,
|
|
1741
|
+
"-message",
|
|
1742
|
+
message,
|
|
1743
|
+
"-open",
|
|
1744
|
+
url,
|
|
1745
|
+
"-sound",
|
|
1746
|
+
MAC_SOUND,
|
|
1747
|
+
...iconPath ? ["-appIcon", iconPath] : [],
|
|
1748
|
+
"-group",
|
|
1749
|
+
"ai.suveren.gateway"
|
|
1750
|
+
]
|
|
1650
1751
|
};
|
|
1651
1752
|
}
|
|
1652
1753
|
return {
|
|
1653
1754
|
cmd: "osascript",
|
|
1654
|
-
args: [
|
|
1755
|
+
args: [
|
|
1756
|
+
"-e",
|
|
1757
|
+
`display notification ${osaQuote(message)} with title ${osaQuote(title)} sound name ${osaQuote(MAC_SOUND)}`
|
|
1758
|
+
]
|
|
1655
1759
|
};
|
|
1656
1760
|
case "win32":
|
|
1657
1761
|
return {
|
|
1658
1762
|
cmd: "powershell",
|
|
1763
|
+
args: ["-NoProfile", "-NonInteractive", "-Command", windowsToastScript(title, message, url, iconPath)]
|
|
1764
|
+
};
|
|
1765
|
+
case "linux":
|
|
1766
|
+
return {
|
|
1767
|
+
cmd: "notify-send",
|
|
1659
1768
|
args: [
|
|
1660
|
-
"-
|
|
1661
|
-
"-
|
|
1662
|
-
|
|
1663
|
-
|
|
1769
|
+
"--app-name=Suveren",
|
|
1770
|
+
...iconPath ? ["-i", iconPath] : [],
|
|
1771
|
+
title,
|
|
1772
|
+
message
|
|
1664
1773
|
]
|
|
1665
1774
|
};
|
|
1666
|
-
case "linux":
|
|
1667
|
-
return { cmd: "notify-send", args: ["--app-name=Suveren", title, message] };
|
|
1668
1775
|
default:
|
|
1669
1776
|
return null;
|
|
1670
1777
|
}
|
|
@@ -1688,15 +1795,32 @@ function hasTerminalNotifier() {
|
|
|
1688
1795
|
}
|
|
1689
1796
|
return terminalNotifierCache;
|
|
1690
1797
|
}
|
|
1798
|
+
function notifySpawnOptions(platform) {
|
|
1799
|
+
return {
|
|
1800
|
+
detached: platform !== "win32",
|
|
1801
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1691
1804
|
function notify(title, message, platform = process.platform, url) {
|
|
1692
1805
|
const command = buildNotifyCommand(platform, title, message, {
|
|
1693
1806
|
url,
|
|
1694
|
-
|
|
1695
|
-
|
|
1807
|
+
hasTerminalNotifier: platform === "darwin" ? hasTerminalNotifier() : false,
|
|
1808
|
+
// Windows and Linux show it on the toast itself; macOS only via
|
|
1809
|
+
// terminal-notifier. Failure to write it must never block the sound.
|
|
1810
|
+
iconPath: ensureNotifierIcon()
|
|
1696
1811
|
});
|
|
1697
1812
|
if (!command) return;
|
|
1698
1813
|
try {
|
|
1699
|
-
const child = spawn(command.cmd, command.args,
|
|
1814
|
+
const child = spawn(command.cmd, command.args, notifySpawnOptions(platform));
|
|
1815
|
+
let stderr = "";
|
|
1816
|
+
child.stderr?.on("data", (d) => {
|
|
1817
|
+
stderr += d.toString().slice(0, 500);
|
|
1818
|
+
});
|
|
1819
|
+
child.on("close", (code) => {
|
|
1820
|
+
if (code !== 0) {
|
|
1821
|
+
console.error(`[notify] ${command.cmd} exited ${code}${stderr ? `: ${stderr.trim()}` : ""}`);
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1700
1824
|
child.on("error", () => {
|
|
1701
1825
|
});
|
|
1702
1826
|
child.unref();
|
|
@@ -1812,13 +1936,13 @@ function createDecryptIntentRouter(vault2) {
|
|
|
1812
1936
|
|
|
1813
1937
|
// src/routes/approved-intents.ts
|
|
1814
1938
|
import { Router as Router9 } from "express";
|
|
1815
|
-
import { readFileSync as readFileSync2, writeFileSync as
|
|
1816
|
-
import { homedir as
|
|
1817
|
-
import { join as
|
|
1818
|
-
var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
1819
|
-
var FILE_PATH =
|
|
1939
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1940
|
+
import { homedir as homedir3 } from "os";
|
|
1941
|
+
import { join as join3 } from "path";
|
|
1942
|
+
var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join3(homedir3(), ".suveren");
|
|
1943
|
+
var FILE_PATH = join3(SUVEREN_DATA_DIR, "approved-intents.enc.json");
|
|
1820
1944
|
function readFile() {
|
|
1821
|
-
if (!
|
|
1945
|
+
if (!existsSync4(FILE_PATH)) {
|
|
1822
1946
|
return { version: 1, entries: {} };
|
|
1823
1947
|
}
|
|
1824
1948
|
try {
|
|
@@ -1828,8 +1952,8 @@ function readFile() {
|
|
|
1828
1952
|
}
|
|
1829
1953
|
}
|
|
1830
1954
|
function writeFile(data) {
|
|
1831
|
-
|
|
1832
|
-
|
|
1955
|
+
mkdirSync3(SUVEREN_DATA_DIR, { recursive: true });
|
|
1956
|
+
writeFileSync3(FILE_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
1833
1957
|
}
|
|
1834
1958
|
function createApprovedIntentsRouter(vault2) {
|
|
1835
1959
|
const router = Router9();
|
|
@@ -1875,7 +1999,7 @@ function createApprovedIntentsRouter(vault2) {
|
|
|
1875
1999
|
|
|
1876
2000
|
// src/lib/update-checker.ts
|
|
1877
2001
|
import { execSync } from "child_process";
|
|
1878
|
-
import { dirname as
|
|
2002
|
+
import { dirname as dirname3 } from "path";
|
|
1879
2003
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1880
2004
|
var GHCR_IMAGE = "suverenai/suveren-gateway";
|
|
1881
2005
|
var NPM_PACKAGE = "@suveren/gateway";
|
|
@@ -1941,7 +2065,7 @@ function compareSemver(a, b) {
|
|
|
1941
2065
|
return 0;
|
|
1942
2066
|
}
|
|
1943
2067
|
function checkDev() {
|
|
1944
|
-
const cwd =
|
|
2068
|
+
const cwd = dirname3(fileURLToPath2(import.meta.url));
|
|
1945
2069
|
try {
|
|
1946
2070
|
execSync("git fetch origin --quiet", { cwd, stdio: "ignore", timeout: 15e3 });
|
|
1947
2071
|
const out = execSync("git rev-list HEAD..origin/main --count", {
|
|
@@ -2012,15 +2136,15 @@ data: null
|
|
|
2012
2136
|
import { Router as Router10 } from "express";
|
|
2013
2137
|
|
|
2014
2138
|
// src/lib/gateway-settings.ts
|
|
2015
|
-
import { readFileSync as readFileSync3, writeFileSync as
|
|
2016
|
-
import { homedir as
|
|
2017
|
-
import { join as
|
|
2139
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
2140
|
+
import { homedir as homedir4 } from "os";
|
|
2141
|
+
import { join as join4, dirname as dirname4 } from "path";
|
|
2018
2142
|
var DEFAULT_SETTINGS = {
|
|
2019
2143
|
desktopNotifications: true
|
|
2020
2144
|
};
|
|
2021
2145
|
function settingsPath(dataDir) {
|
|
2022
|
-
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ??
|
|
2023
|
-
return
|
|
2146
|
+
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join4(homedir4(), ".suveren");
|
|
2147
|
+
return join4(dir, "settings.json");
|
|
2024
2148
|
}
|
|
2025
2149
|
function readSettings(dataDir) {
|
|
2026
2150
|
try {
|
|
@@ -2038,8 +2162,8 @@ function writeSettings(patch, dataDir) {
|
|
|
2038
2162
|
...typeof patch.desktopNotifications === "boolean" ? { desktopNotifications: patch.desktopNotifications } : {}
|
|
2039
2163
|
};
|
|
2040
2164
|
const path = settingsPath(dataDir);
|
|
2041
|
-
|
|
2042
|
-
|
|
2165
|
+
mkdirSync4(dirname4(path), { recursive: true });
|
|
2166
|
+
writeFileSync4(path, JSON.stringify(next, null, 2) + "\n", "utf8");
|
|
2043
2167
|
return next;
|
|
2044
2168
|
}
|
|
2045
2169
|
|
|
@@ -2184,16 +2308,16 @@ function startNotificationDispatcher(opts = {}) {
|
|
|
2184
2308
|
}
|
|
2185
2309
|
|
|
2186
2310
|
// src/lib/denials-reader.ts
|
|
2187
|
-
import { existsSync as
|
|
2188
|
-
import { join as
|
|
2311
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
2312
|
+
import { join as join5 } from "path";
|
|
2189
2313
|
function loadDenials(dataDir, decrypt) {
|
|
2190
|
-
const encPath =
|
|
2191
|
-
const plainPath =
|
|
2192
|
-
if (
|
|
2314
|
+
const encPath = join5(dataDir, "denials.enc.json");
|
|
2315
|
+
const plainPath = join5(dataDir, "denials.json");
|
|
2316
|
+
if (existsSync5(encPath)) {
|
|
2193
2317
|
const { blob } = JSON.parse(readFileSync4(encPath, "utf-8"));
|
|
2194
2318
|
return JSON.parse(decrypt(blob)).records ?? [];
|
|
2195
2319
|
}
|
|
2196
|
-
if (
|
|
2320
|
+
if (existsSync5(plainPath)) {
|
|
2197
2321
|
return JSON.parse(readFileSync4(plainPath, "utf-8")).records ?? [];
|
|
2198
2322
|
}
|
|
2199
2323
|
return [];
|
|
@@ -2209,9 +2333,9 @@ function selectDenials(records, opts = {}) {
|
|
|
2209
2333
|
// src/index.ts
|
|
2210
2334
|
(function migrateDataDir() {
|
|
2211
2335
|
if (process.env.SUVEREN_DATA_DIR) return;
|
|
2212
|
-
const oldDir =
|
|
2213
|
-
const newDir =
|
|
2214
|
-
if (!
|
|
2336
|
+
const oldDir = join6(homedir5(), ".hap");
|
|
2337
|
+
const newDir = join6(homedir5(), ".suveren");
|
|
2338
|
+
if (!existsSync6(newDir) && existsSync6(oldDir)) {
|
|
2215
2339
|
try {
|
|
2216
2340
|
renameSync(oldDir, newDir);
|
|
2217
2341
|
console.error(`[Control Plane] Migrated data directory: ${oldDir} \u2192 ${newDir}`);
|
|
@@ -2224,7 +2348,7 @@ function selectDenials(records, opts = {}) {
|
|
|
2224
2348
|
var SP_URL2 = process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai";
|
|
2225
2349
|
var port = parseInt(process.env.SUVEREN_CP_PORT ?? "3402", 10);
|
|
2226
2350
|
var HAP_MODE = process.env.HAP_MODE ?? "personal";
|
|
2227
|
-
var UI_DIST = process.env.HAP_UI_DIST ??
|
|
2351
|
+
var UI_DIST = process.env.HAP_UI_DIST ?? join6(import.meta.dirname ?? __dirname, "../../ui/dist");
|
|
2228
2352
|
var vault = new Vault();
|
|
2229
2353
|
var internalSecret2 = process.env.SUVEREN_INTERNAL_SECRET ?? randomBytes2(32).toString("hex");
|
|
2230
2354
|
setInternalSecret(internalSecret2);
|
|
@@ -2262,7 +2386,7 @@ function resolveOrigin(req) {
|
|
|
2262
2386
|
return `${req.protocol}://${req.get("host")}`;
|
|
2263
2387
|
}
|
|
2264
2388
|
var oauthRedirectUris = /* @__PURE__ */ new Map();
|
|
2265
|
-
var
|
|
2389
|
+
var manifestCache2 = null;
|
|
2266
2390
|
function resolvePath(obj, path) {
|
|
2267
2391
|
const v = path.split(".").reduce((acc, key) => {
|
|
2268
2392
|
return acc && typeof acc === "object" ? acc[key] : void 0;
|
|
@@ -2282,15 +2406,15 @@ function decodeJwtEmail(idToken) {
|
|
|
2282
2406
|
}
|
|
2283
2407
|
}
|
|
2284
2408
|
async function getOAuthManifest(integrationId) {
|
|
2285
|
-
if (!
|
|
2409
|
+
if (!manifestCache2) {
|
|
2286
2410
|
try {
|
|
2287
2411
|
const data = await getManifests();
|
|
2288
|
-
|
|
2412
|
+
manifestCache2 = data.manifests;
|
|
2289
2413
|
} catch {
|
|
2290
2414
|
return null;
|
|
2291
2415
|
}
|
|
2292
2416
|
}
|
|
2293
|
-
return
|
|
2417
|
+
return manifestCache2?.find((m) => m.id === integrationId && m.oauth) ?? null;
|
|
2294
2418
|
}
|
|
2295
2419
|
app.get("/auth/oauth/:integrationId/start", async (req, res) => {
|
|
2296
2420
|
const { integrationId } = req.params;
|
|
@@ -2592,7 +2716,7 @@ app.get("/active-authorizations", authGuard, async (_req, res) => {
|
|
|
2592
2716
|
});
|
|
2593
2717
|
app.get("/denials", authGuard, (req, res) => {
|
|
2594
2718
|
try {
|
|
2595
|
-
const dataDir = process.env.SUVEREN_DATA_DIR ??
|
|
2719
|
+
const dataDir = process.env.SUVEREN_DATA_DIR ?? join6(homedir5(), ".suveren");
|
|
2596
2720
|
const all = loadDenials(dataDir, (blob) => vault.decrypt(blob));
|
|
2597
2721
|
const since = Number(req.query.since);
|
|
2598
2722
|
const limit = Number(req.query.limit);
|
|
@@ -2625,11 +2749,11 @@ app.post("/resync-gates", authGuard, async (_req, res) => {
|
|
|
2625
2749
|
}
|
|
2626
2750
|
});
|
|
2627
2751
|
var AGENT_CONTEXT_MAX_BYTES = 16 * 1024;
|
|
2628
|
-
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
2752
|
+
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join6(homedir5(), ".suveren");
|
|
2629
2753
|
app.get("/agent-brief/context", authGuard, async (_req, res) => {
|
|
2630
2754
|
try {
|
|
2631
2755
|
const { readFileSync: readFileSync6, existsSync: fileExists } = await import("fs");
|
|
2632
|
-
const filePath =
|
|
2756
|
+
const filePath = join6(SUVEREN_DATA_DIR2, "context.md");
|
|
2633
2757
|
if (!fileExists(filePath)) {
|
|
2634
2758
|
res.json({ content: "" });
|
|
2635
2759
|
return;
|
|
@@ -2652,11 +2776,11 @@ app.put("/agent-brief/context", jsonParser, authGuard, async (req, res) => {
|
|
|
2652
2776
|
res.status(413).json({ error: `Context exceeds ${AGENT_CONTEXT_MAX_BYTES}-byte cap` });
|
|
2653
2777
|
return;
|
|
2654
2778
|
}
|
|
2655
|
-
const { mkdirSync:
|
|
2656
|
-
|
|
2657
|
-
const filePath =
|
|
2779
|
+
const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync5, renameSync: renameSync2 } = await import("fs");
|
|
2780
|
+
mkdirSync5(SUVEREN_DATA_DIR2, { recursive: true });
|
|
2781
|
+
const filePath = join6(SUVEREN_DATA_DIR2, "context.md");
|
|
2658
2782
|
const tmpPath = `${filePath}.tmp`;
|
|
2659
|
-
|
|
2783
|
+
writeFileSync5(tmpPath, content, "utf-8");
|
|
2660
2784
|
renameSync2(tmpPath, filePath);
|
|
2661
2785
|
res.json({ ok: true });
|
|
2662
2786
|
} catch (err) {
|
|
@@ -2706,13 +2830,13 @@ app.use(
|
|
|
2706
2830
|
})
|
|
2707
2831
|
);
|
|
2708
2832
|
function detectInstallMethod() {
|
|
2709
|
-
if (
|
|
2833
|
+
if (existsSync6("/.dockerenv")) return "docker";
|
|
2710
2834
|
const dir = import.meta.dirname ?? __dirname;
|
|
2711
2835
|
if (dir.includes("/node_modules/@suveren/gateway/")) return "npm";
|
|
2712
2836
|
let cursor = dir;
|
|
2713
2837
|
for (let i = 0; i < 8; i++) {
|
|
2714
|
-
if (
|
|
2715
|
-
const parent =
|
|
2838
|
+
if (existsSync6(join6(cursor, ".git"))) return "dev";
|
|
2839
|
+
const parent = dirname5(cursor);
|
|
2716
2840
|
if (parent === cursor) break;
|
|
2717
2841
|
cursor = parent;
|
|
2718
2842
|
}
|
|
@@ -2724,8 +2848,8 @@ function detectRunningVersion() {
|
|
|
2724
2848
|
return process.env.HAP_BUILD_SHA ?? "dev";
|
|
2725
2849
|
}
|
|
2726
2850
|
const dir = import.meta.dirname ?? __dirname;
|
|
2727
|
-
const bundlePkg =
|
|
2728
|
-
if (
|
|
2851
|
+
const bundlePkg = join6(dir, "..", "..", "package.json");
|
|
2852
|
+
if (existsSync6(bundlePkg)) {
|
|
2729
2853
|
try {
|
|
2730
2854
|
const pkg = JSON.parse(readFileSync5(bundlePkg, "utf8"));
|
|
2731
2855
|
if (pkg.name === "@suveren/gateway" && typeof pkg.version === "string") {
|
|
@@ -2755,7 +2879,7 @@ app.get("/health", async (req, res) => {
|
|
|
2755
2879
|
}
|
|
2756
2880
|
});
|
|
2757
2881
|
});
|
|
2758
|
-
if (
|
|
2882
|
+
if (existsSync6(UI_DIST)) {
|
|
2759
2883
|
app.use(express.static(UI_DIST, {
|
|
2760
2884
|
setHeaders: (res, filePath) => {
|
|
2761
2885
|
if (filePath.endsWith("index.html")) {
|
|
@@ -2765,7 +2889,7 @@ if (existsSync5(UI_DIST)) {
|
|
|
2765
2889
|
}));
|
|
2766
2890
|
app.get("*", (_req, res) => {
|
|
2767
2891
|
res.setHeader("Cache-Control", "no-store, must-revalidate");
|
|
2768
|
-
res.sendFile(
|
|
2892
|
+
res.sendFile(join6(UI_DIST, "index.html"));
|
|
2769
2893
|
});
|
|
2770
2894
|
} else {
|
|
2771
2895
|
app.get("/", (_req, res) => {
|