@suveren/gateway 0.7.2 → 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/dist/control-plane/index.mjs +65 -6
- package/dist/ui/assets/index-DdJeSfV9.js +110 -0
- package/dist/ui/index.html +1 -1
- 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
|
|
|
@@ -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);
|
|
@@ -2327,7 +2386,7 @@ function resolveOrigin(req) {
|
|
|
2327
2386
|
return `${req.protocol}://${req.get("host")}`;
|
|
2328
2387
|
}
|
|
2329
2388
|
var oauthRedirectUris = /* @__PURE__ */ new Map();
|
|
2330
|
-
var
|
|
2389
|
+
var manifestCache2 = null;
|
|
2331
2390
|
function resolvePath(obj, path) {
|
|
2332
2391
|
const v = path.split(".").reduce((acc, key) => {
|
|
2333
2392
|
return acc && typeof acc === "object" ? acc[key] : void 0;
|
|
@@ -2347,15 +2406,15 @@ function decodeJwtEmail(idToken) {
|
|
|
2347
2406
|
}
|
|
2348
2407
|
}
|
|
2349
2408
|
async function getOAuthManifest(integrationId) {
|
|
2350
|
-
if (!
|
|
2409
|
+
if (!manifestCache2) {
|
|
2351
2410
|
try {
|
|
2352
2411
|
const data = await getManifests();
|
|
2353
|
-
|
|
2412
|
+
manifestCache2 = data.manifests;
|
|
2354
2413
|
} catch {
|
|
2355
2414
|
return null;
|
|
2356
2415
|
}
|
|
2357
2416
|
}
|
|
2358
|
-
return
|
|
2417
|
+
return manifestCache2?.find((m) => m.id === integrationId && m.oauth) ?? null;
|
|
2359
2418
|
}
|
|
2360
2419
|
app.get("/auth/oauth/:integrationId/start", async (req, res) => {
|
|
2361
2420
|
const { integrationId } = req.params;
|