@suveren/gateway 0.7.6 → 0.8.0
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/content/integrations/mollie.json +103 -28
- package/dist/mcp-server/http.mjs +228 -118
- package/dist/ui/assets/{index-CsrM6RQr.js → index-BFnSVa9N.js} +22 -22
- package/dist/ui/index.html +1 -1
- package/node_modules/@hap/core/dist/index.d.mts +29 -6
- package/node_modules/@hap/core/dist/index.d.ts +29 -6
- package/node_modules/@hap/core/dist/index.js +54 -8
- package/node_modules/@hap/core/dist/index.mjs +53 -8
- package/node_modules/@hap/core/package.json +2 -1
- package/node_modules/@hap/core/src/frame.ts +115 -14
- package/node_modules/@hap/core/src/gatekeeper.ts +26 -0
- package/node_modules/@hap/core/src/types.ts +7 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/buffer.buffer.d.ts +5 -0
- package/node_modules/@types/node/crypto.d.ts +0 -2
- package/node_modules/@types/node/dgram.d.ts +119 -4
- package/node_modules/@types/node/ffi.d.ts +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +61 -65
- package/node_modules/@types/node/fs.d.ts +86 -76
- package/node_modules/@types/node/http.d.ts +1 -1
- package/node_modules/@types/node/http2.d.ts +2 -2
- package/node_modules/@types/node/index.d.ts +1 -0
- package/node_modules/@types/node/inspector.d.ts +2 -1
- package/node_modules/@types/node/net.d.ts +108 -16
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/quic.d.ts +37 -11
- package/node_modules/@types/node/stream/iter.d.ts +4 -4
- package/node_modules/@types/node/tls.d.ts +24 -0
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +5 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +1 -0
- package/node_modules/@types/node/ts5.7/index.d.ts +1 -0
- package/node_modules/@types/node/tty.d.ts +4 -3
- package/node_modules/@types/node/vfs.d.ts +210 -0
- package/node_modules/@types/node/vm.d.ts +1 -1
- package/node_modules/express-rate-limit/dist/index.cjs +6 -3
- package/node_modules/express-rate-limit/dist/index.d.cts +11 -0
- package/node_modules/express-rate-limit/dist/index.d.mts +11 -0
- package/node_modules/express-rate-limit/dist/index.d.ts +11 -0
- package/node_modules/express-rate-limit/dist/index.mjs +6 -3
- package/node_modules/express-rate-limit/{license.md → license} +7 -6
- package/node_modules/express-rate-limit/package.json +5 -5
- package/node_modules/express-rate-limit/readme.md +1 -0
- package/node_modules/fast-uri/index.js +20 -5
- package/node_modules/fast-uri/lib/utils.js +8 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +58 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +34 -0
- package/node_modules/ip-address/README.md +92 -82
- package/node_modules/ip-address/dist/common.d.ts +20 -0
- package/node_modules/ip-address/dist/common.js +36 -0
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +50 -0
- package/node_modules/ip-address/dist/ipv4.js +75 -0
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +79 -10
- package/node_modules/ip-address/dist/ipv6.js +120 -30
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.d.ts +12 -0
- package/node_modules/ip-address/dist/v4/constants.js +40 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.d.ts +14 -0
- package/node_modules/ip-address/dist/v6/constants.js +47 -1
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +1 -1
- package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +6 -17
- package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +11 -34
- package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +15 -35
- package/node_modules/jose/dist/types/jwk/embedded.d.ts +3 -8
- package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +5 -5
- package/node_modules/jose/dist/types/jwks/local.d.ts +6 -10
- package/node_modules/jose/dist/types/jwks/remote.d.ts +13 -24
- package/node_modules/jose/dist/types/jws/compact/sign.d.ts +5 -10
- package/node_modules/jose/dist/types/jws/compact/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +7 -16
- package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jws/general/sign.d.ts +11 -21
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jwt/decrypt.d.ts +10 -20
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +6 -13
- package/node_modules/jose/dist/types/jwt/sign.d.ts +5 -6
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -14
- package/node_modules/jose/dist/types/jwt/verify.d.ts +9 -19
- package/node_modules/jose/dist/types/key/export.d.ts +4 -4
- package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +6 -8
- package/node_modules/jose/dist/types/key/generate_secret.d.ts +4 -11
- package/node_modules/jose/dist/types/key/import.d.ts +10 -17
- package/node_modules/jose/dist/types/types.d.ts +44 -84
- package/node_modules/jose/dist/types/util/base64url.d.ts +2 -2
- package/node_modules/jose/dist/types/util/decode_jwt.d.ts +3 -10
- package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +4 -4
- package/node_modules/jose/dist/types/util/errors.d.ts +26 -53
- package/node_modules/jose/dist/webapi/index.js +70 -32
- package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +7 -8
- package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +42 -48
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +14 -14
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +53 -64
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +38 -49
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +121 -169
- package/node_modules/jose/dist/webapi/jwk/embedded.js +30 -32
- package/node_modules/jose/dist/webapi/jwk/thumbprint.js +54 -70
- package/node_modules/jose/dist/webapi/jwks/local.js +47 -64
- package/node_modules/jose/dist/webapi/jwks/remote.js +88 -136
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +21 -21
- package/node_modules/jose/dist/webapi/jws/compact/verify.js +7 -8
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +29 -31
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +21 -24
- package/node_modules/jose/dist/webapi/jws/general/sign.js +61 -72
- package/node_modules/jose/dist/webapi/jws/general/verify.js +45 -69
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +13 -20
- package/node_modules/jose/dist/webapi/jwt/encrypt.js +57 -70
- package/node_modules/jose/dist/webapi/jwt/sign.js +17 -16
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +32 -40
- package/node_modules/jose/dist/webapi/jwt/verify.js +12 -14
- package/node_modules/jose/dist/webapi/key/export.js +32 -37
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +40 -48
- package/node_modules/jose/dist/webapi/key/generate_secret.js +35 -40
- package/node_modules/jose/dist/webapi/key/import.js +52 -56
- package/node_modules/jose/dist/webapi/lib/asn1.js +130 -169
- package/node_modules/jose/dist/webapi/lib/base64.js +18 -20
- package/node_modules/jose/dist/webapi/lib/buffer_utils.js +34 -38
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +79 -115
- package/node_modules/jose/dist/webapi/lib/crypto_key.js +24 -25
- package/node_modules/jose/dist/webapi/lib/deflate.js +45 -47
- package/node_modules/jose/dist/webapi/lib/helpers.js +40 -37
- package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +10 -24
- package/node_modules/jose/dist/webapi/lib/is_key_like.js +17 -15
- package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +106 -93
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +207 -230
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +104 -138
- package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +17 -18
- package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +9 -16
- package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +62 -61
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +50 -75
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +80 -125
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +123 -209
- package/node_modules/jose/dist/webapi/lib/key.js +84 -136
- package/node_modules/jose/dist/webapi/lib/key_algorithm.js +13 -8
- package/node_modules/jose/dist/webapi/lib/key_descriptor.js +8 -6
- package/node_modules/jose/dist/webapi/lib/key_management.js +200 -231
- package/node_modules/jose/dist/webapi/lib/key_options.js +7 -5
- package/node_modules/jose/dist/webapi/lib/options.js +55 -68
- package/node_modules/jose/dist/webapi/lib/signing.js +18 -22
- package/node_modules/jose/dist/webapi/lib/type_checks.js +26 -29
- package/node_modules/jose/dist/webapi/util/base64url.js +26 -35
- package/node_modules/jose/dist/webapi/util/decode_jwt.js +32 -31
- package/node_modules/jose/dist/webapi/util/decode_protected_header.js +18 -23
- package/node_modules/jose/dist/webapi/util/errors.js +94 -84
- package/node_modules/jose/package.json +17 -81
- package/package.json +2 -2
- package/profiles/calendar/0.5.profile.json +190 -0
- package/profiles/charge/0.5.profile.json +210 -0
- package/profiles/customers/0.7.profile.json +157 -0
- package/profiles/deploy/0.9.profile.json +176 -0
- package/profiles/email/0.6.profile.json +208 -0
- package/profiles/index.json +9 -1
- package/profiles/publish/0.5.profile.json +186 -0
- package/profiles/purchase/0.5.profile.json +231 -0
- package/profiles/records/0.5.profile.json +117 -0
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -33,6 +33,85 @@ async function notifyControlPlane(type) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// src/lib/client-version.ts
|
|
37
|
+
import { createRequire } from "module";
|
|
38
|
+
import { existsSync, readFileSync } from "fs";
|
|
39
|
+
import { join } from "path";
|
|
40
|
+
var UNKNOWN = "unknown";
|
|
41
|
+
function readJson(path) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function detectGatewayVersion() {
|
|
49
|
+
const override = process.env.SUVEREN_GATEWAY_VERSION;
|
|
50
|
+
if (override) return override;
|
|
51
|
+
const start = import.meta.dirname ?? process.cwd();
|
|
52
|
+
let dir = start;
|
|
53
|
+
for (let up = 0; up < 6; up++) {
|
|
54
|
+
const pkg = readJson(join(dir, "package.json"));
|
|
55
|
+
const name = pkg?.name;
|
|
56
|
+
const version = pkg?.version;
|
|
57
|
+
if (typeof version === "string" && (name === "@suveren/gateway" || name === "suveren-gateway")) {
|
|
58
|
+
return version;
|
|
59
|
+
}
|
|
60
|
+
const parent = join(dir, "..");
|
|
61
|
+
if (parent === dir) break;
|
|
62
|
+
dir = parent;
|
|
63
|
+
}
|
|
64
|
+
return process.env.HAP_BUILD_SHA ?? UNKNOWN;
|
|
65
|
+
}
|
|
66
|
+
function findPackageVersion(entry, wantName) {
|
|
67
|
+
let dir = join(entry, "..");
|
|
68
|
+
for (let up = 0; up < 6; up++) {
|
|
69
|
+
const candidate = join(dir, "package.json");
|
|
70
|
+
if (existsSync(candidate)) {
|
|
71
|
+
const pkg = readJson(candidate);
|
|
72
|
+
if (typeof pkg?.version === "string" && (pkg.name === wantName || pkg.name === "@hap/core")) {
|
|
73
|
+
return pkg.name === wantName ? pkg.version : null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const parent = join(dir, "..");
|
|
77
|
+
if (parent === dir) break;
|
|
78
|
+
dir = parent;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function detectHapCoreVersion() {
|
|
83
|
+
const CORE = "@humanagencyp/hap-core";
|
|
84
|
+
let req;
|
|
85
|
+
try {
|
|
86
|
+
req = createRequire(import.meta.url);
|
|
87
|
+
} catch {
|
|
88
|
+
return UNKNOWN;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const v = findPackageVersion(req.resolve(CORE), CORE);
|
|
92
|
+
if (v) return v;
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const wrapperEntry = req.resolve("@hap/core");
|
|
97
|
+
const v = findPackageVersion(wrapperEntry, CORE);
|
|
98
|
+
if (v) return v;
|
|
99
|
+
const wrapperReq = createRequire(wrapperEntry);
|
|
100
|
+
const v2 = findPackageVersion(wrapperReq.resolve(CORE), CORE);
|
|
101
|
+
if (v2) return v2;
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
return UNKNOWN;
|
|
105
|
+
}
|
|
106
|
+
var GATEWAY_VERSION = detectGatewayVersion();
|
|
107
|
+
var HAP_CORE_VERSION = detectHapCoreVersion();
|
|
108
|
+
function clientVersionHeaders() {
|
|
109
|
+
return {
|
|
110
|
+
"x-suveren-gateway-version": GATEWAY_VERSION,
|
|
111
|
+
"x-hap-core-version": HAP_CORE_VERSION
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
36
115
|
// src/lib/sp-client.ts
|
|
37
116
|
var SPReceiptError = class extends Error {
|
|
38
117
|
constructor(message, statusCode, body) {
|
|
@@ -82,6 +161,11 @@ var SPClient = class {
|
|
|
82
161
|
const url = `${this.baseUrl}${path}`;
|
|
83
162
|
const headers = {
|
|
84
163
|
"Content-Type": "application/json",
|
|
164
|
+
// Identify the caller so the AS can answer "what is deployed against
|
|
165
|
+
// me?" and name a version in an upgrade instruction. Advisory only —
|
|
166
|
+
// never used for authorization. Sent on every call, not just receipts,
|
|
167
|
+
// so the picture is not skewed toward one endpoint.
|
|
168
|
+
...clientVersionHeaders(),
|
|
85
169
|
...init?.headers
|
|
86
170
|
};
|
|
87
171
|
if (this.sessionCookie) {
|
|
@@ -378,11 +462,11 @@ var AttestationCache = class {
|
|
|
378
462
|
};
|
|
379
463
|
|
|
380
464
|
// src/lib/gate-store.ts
|
|
381
|
-
import { mkdirSync, readFileSync, writeFileSync, existsSync, unlinkSync } from "fs";
|
|
465
|
+
import { mkdirSync, readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, unlinkSync } from "fs";
|
|
382
466
|
import { homedir } from "os";
|
|
383
|
-
import { dirname, join } from "path";
|
|
467
|
+
import { dirname, join as join2 } from "path";
|
|
384
468
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
385
|
-
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
469
|
+
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ?? join2(homedir(), ".suveren");
|
|
386
470
|
var GateStore = class {
|
|
387
471
|
entries = /* @__PURE__ */ new Map();
|
|
388
472
|
baseDir;
|
|
@@ -400,11 +484,11 @@ var GateStore = class {
|
|
|
400
484
|
*/
|
|
401
485
|
setVaultKey(key) {
|
|
402
486
|
this.vaultKey = key;
|
|
403
|
-
if (
|
|
487
|
+
if (existsSync2(this.encryptedFilePath)) {
|
|
404
488
|
this.loadEncrypted();
|
|
405
489
|
} else if (this.entries.size > 0) {
|
|
406
490
|
this.persistEncrypted();
|
|
407
|
-
if (
|
|
491
|
+
if (existsSync2(this.plaintextFilePath)) {
|
|
408
492
|
try {
|
|
409
493
|
unlinkSync(this.plaintextFilePath);
|
|
410
494
|
} catch {
|
|
@@ -455,19 +539,19 @@ var GateStore = class {
|
|
|
455
539
|
}
|
|
456
540
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
457
541
|
get plaintextFilePath() {
|
|
458
|
-
return
|
|
542
|
+
return join2(this.baseDir, "gates.json");
|
|
459
543
|
}
|
|
460
544
|
get encryptedFilePath() {
|
|
461
|
-
return
|
|
545
|
+
return join2(this.baseDir, "gates.enc.json");
|
|
462
546
|
}
|
|
463
547
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
464
548
|
loadPlaintext() {
|
|
465
|
-
if (!
|
|
549
|
+
if (!existsSync2(this.plaintextFilePath)) {
|
|
466
550
|
mkdirSync(this.baseDir, { recursive: true });
|
|
467
551
|
return;
|
|
468
552
|
}
|
|
469
553
|
try {
|
|
470
|
-
const raw =
|
|
554
|
+
const raw = readFileSync2(this.plaintextFilePath, "utf-8");
|
|
471
555
|
const data = JSON.parse(raw);
|
|
472
556
|
this.entries = new Map(Object.entries(data.entries));
|
|
473
557
|
} catch {
|
|
@@ -476,9 +560,9 @@ var GateStore = class {
|
|
|
476
560
|
}
|
|
477
561
|
}
|
|
478
562
|
loadEncrypted() {
|
|
479
|
-
if (!
|
|
563
|
+
if (!existsSync2(this.encryptedFilePath)) return;
|
|
480
564
|
try {
|
|
481
|
-
const raw =
|
|
565
|
+
const raw = readFileSync2(this.encryptedFilePath, "utf-8");
|
|
482
566
|
const data = JSON.parse(raw);
|
|
483
567
|
this.entries = /* @__PURE__ */ new Map();
|
|
484
568
|
for (const [key, blob] of Object.entries(data.entries)) {
|
|
@@ -519,11 +603,11 @@ var GateStore = class {
|
|
|
519
603
|
};
|
|
520
604
|
|
|
521
605
|
// src/lib/execution-log.ts
|
|
522
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
606
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
523
607
|
import { homedir as homedir2 } from "os";
|
|
524
|
-
import { dirname as dirname2, join as
|
|
608
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
525
609
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
526
|
-
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
610
|
+
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ?? join3(homedir2(), ".suveren");
|
|
527
611
|
var MAX_AGE_SECONDS = 31 * 24 * 60 * 60;
|
|
528
612
|
var ExecutionLog = class {
|
|
529
613
|
entries = [];
|
|
@@ -542,11 +626,11 @@ var ExecutionLog = class {
|
|
|
542
626
|
*/
|
|
543
627
|
setVaultKey(key) {
|
|
544
628
|
this.vaultKey = key;
|
|
545
|
-
if (
|
|
629
|
+
if (existsSync3(this.encryptedFilePath)) {
|
|
546
630
|
this.loadEncrypted();
|
|
547
631
|
} else if (this.entries.length > 0) {
|
|
548
632
|
this.persistEncrypted();
|
|
549
|
-
if (
|
|
633
|
+
if (existsSync3(this.plaintextFilePath)) {
|
|
550
634
|
try {
|
|
551
635
|
unlinkSync2(this.plaintextFilePath);
|
|
552
636
|
} catch {
|
|
@@ -641,19 +725,19 @@ var ExecutionLog = class {
|
|
|
641
725
|
}
|
|
642
726
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
643
727
|
get plaintextFilePath() {
|
|
644
|
-
return
|
|
728
|
+
return join3(this.baseDir, "execution-log.json");
|
|
645
729
|
}
|
|
646
730
|
get encryptedFilePath() {
|
|
647
|
-
return
|
|
731
|
+
return join3(this.baseDir, "execution-log.enc.json");
|
|
648
732
|
}
|
|
649
733
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
650
734
|
loadPlaintext() {
|
|
651
|
-
if (!
|
|
735
|
+
if (!existsSync3(this.plaintextFilePath)) {
|
|
652
736
|
mkdirSync2(this.baseDir, { recursive: true });
|
|
653
737
|
return;
|
|
654
738
|
}
|
|
655
739
|
try {
|
|
656
|
-
const raw =
|
|
740
|
+
const raw = readFileSync3(this.plaintextFilePath, "utf-8");
|
|
657
741
|
const data = JSON.parse(raw);
|
|
658
742
|
this.entries = data.entries;
|
|
659
743
|
this.prune();
|
|
@@ -663,9 +747,9 @@ var ExecutionLog = class {
|
|
|
663
747
|
}
|
|
664
748
|
}
|
|
665
749
|
loadEncrypted() {
|
|
666
|
-
if (!
|
|
750
|
+
if (!existsSync3(this.encryptedFilePath)) return;
|
|
667
751
|
try {
|
|
668
|
-
const raw =
|
|
752
|
+
const raw = readFileSync3(this.encryptedFilePath, "utf-8");
|
|
669
753
|
const data = JSON.parse(raw);
|
|
670
754
|
const decrypted = this.decrypt(data.blob);
|
|
671
755
|
const logFile = JSON.parse(decrypted);
|
|
@@ -712,11 +796,11 @@ function windowCutoff(window, now) {
|
|
|
712
796
|
}
|
|
713
797
|
|
|
714
798
|
// src/lib/denial-log.ts
|
|
715
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
799
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
716
800
|
import { homedir as homedir3 } from "os";
|
|
717
|
-
import { dirname as dirname3, join as
|
|
801
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
718
802
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes3 } from "crypto";
|
|
719
|
-
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ??
|
|
803
|
+
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ?? join4(homedir3(), ".suveren");
|
|
720
804
|
var MAX_RECORDS = 200;
|
|
721
805
|
var MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
722
806
|
var DenialLog = class {
|
|
@@ -729,11 +813,11 @@ var DenialLog = class {
|
|
|
729
813
|
}
|
|
730
814
|
setVaultKey(key) {
|
|
731
815
|
this.vaultKey = key;
|
|
732
|
-
if (
|
|
816
|
+
if (existsSync4(this.encryptedFilePath)) {
|
|
733
817
|
this.loadEncrypted();
|
|
734
818
|
} else if (this.records.length > 0) {
|
|
735
819
|
this.persistEncrypted();
|
|
736
|
-
if (
|
|
820
|
+
if (existsSync4(this.plaintextFilePath)) {
|
|
737
821
|
try {
|
|
738
822
|
unlinkSync3(this.plaintextFilePath);
|
|
739
823
|
} catch {
|
|
@@ -783,18 +867,18 @@ var DenialLog = class {
|
|
|
783
867
|
return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, "hex")), decipher.final()]).toString("utf8");
|
|
784
868
|
}
|
|
785
869
|
get plaintextFilePath() {
|
|
786
|
-
return
|
|
870
|
+
return join4(this.baseDir, "denials.json");
|
|
787
871
|
}
|
|
788
872
|
get encryptedFilePath() {
|
|
789
|
-
return
|
|
873
|
+
return join4(this.baseDir, "denials.enc.json");
|
|
790
874
|
}
|
|
791
875
|
loadPlaintext() {
|
|
792
|
-
if (!
|
|
876
|
+
if (!existsSync4(this.plaintextFilePath)) {
|
|
793
877
|
mkdirSync3(this.baseDir, { recursive: true });
|
|
794
878
|
return;
|
|
795
879
|
}
|
|
796
880
|
try {
|
|
797
|
-
const data = JSON.parse(
|
|
881
|
+
const data = JSON.parse(readFileSync4(this.plaintextFilePath, "utf-8"));
|
|
798
882
|
this.records = data.records ?? [];
|
|
799
883
|
} catch {
|
|
800
884
|
console.error(`[DenialLog] Could not parse ${this.plaintextFilePath}, starting fresh`);
|
|
@@ -802,9 +886,9 @@ var DenialLog = class {
|
|
|
802
886
|
}
|
|
803
887
|
}
|
|
804
888
|
loadEncrypted() {
|
|
805
|
-
if (!
|
|
889
|
+
if (!existsSync4(this.encryptedFilePath)) return;
|
|
806
890
|
try {
|
|
807
|
-
const data = JSON.parse(
|
|
891
|
+
const data = JSON.parse(readFileSync4(this.encryptedFilePath, "utf-8"));
|
|
808
892
|
const logFile = JSON.parse(this.decrypt(data.blob));
|
|
809
893
|
this.records = logFile.records ?? [];
|
|
810
894
|
} catch (err) {
|
|
@@ -830,11 +914,11 @@ var DenialLog = class {
|
|
|
830
914
|
};
|
|
831
915
|
|
|
832
916
|
// src/lib/receipt-archive.ts
|
|
833
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
917
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
834
918
|
import { homedir as homedir4 } from "os";
|
|
835
|
-
import { dirname as dirname4, join as
|
|
919
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
836
920
|
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes4 } from "crypto";
|
|
837
|
-
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ??
|
|
921
|
+
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ?? join5(homedir4(), ".suveren");
|
|
838
922
|
function stripPreviews(proposal) {
|
|
839
923
|
const args = proposal.toolArgs;
|
|
840
924
|
if (!args || typeof args !== "object") return proposal;
|
|
@@ -859,11 +943,11 @@ var ReceiptArchive = class {
|
|
|
859
943
|
*/
|
|
860
944
|
setVaultKey(key) {
|
|
861
945
|
this.vaultKey = key;
|
|
862
|
-
if (
|
|
946
|
+
if (existsSync5(this.encryptedFilePath)) {
|
|
863
947
|
this.loadEncrypted();
|
|
864
948
|
} else if (this.data.receipts.length > 0 || Object.keys(this.data.authorizations).length > 0) {
|
|
865
949
|
this.persistEncrypted();
|
|
866
|
-
if (
|
|
950
|
+
if (existsSync5(this.plaintextFilePath)) {
|
|
867
951
|
try {
|
|
868
952
|
unlinkSync4(this.plaintextFilePath);
|
|
869
953
|
} catch {
|
|
@@ -877,7 +961,7 @@ var ReceiptArchive = class {
|
|
|
877
961
|
* this state — that would report a hollow success over unreadable evidence.
|
|
878
962
|
*/
|
|
879
963
|
isLocked() {
|
|
880
|
-
return this.vaultKey === null &&
|
|
964
|
+
return this.vaultKey === null && existsSync5(this.encryptedFilePath);
|
|
881
965
|
}
|
|
882
966
|
/**
|
|
883
967
|
* Archive a signed receipt (and the grant it was issued under).
|
|
@@ -978,19 +1062,19 @@ var ReceiptArchive = class {
|
|
|
978
1062
|
}
|
|
979
1063
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
980
1064
|
get plaintextFilePath() {
|
|
981
|
-
return
|
|
1065
|
+
return join5(this.baseDir, "receipt-archive.json");
|
|
982
1066
|
}
|
|
983
1067
|
get encryptedFilePath() {
|
|
984
|
-
return
|
|
1068
|
+
return join5(this.baseDir, "receipt-archive.enc.json");
|
|
985
1069
|
}
|
|
986
1070
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
987
1071
|
loadPlaintext() {
|
|
988
|
-
if (!
|
|
1072
|
+
if (!existsSync5(this.plaintextFilePath)) {
|
|
989
1073
|
mkdirSync4(this.baseDir, { recursive: true });
|
|
990
1074
|
return;
|
|
991
1075
|
}
|
|
992
1076
|
try {
|
|
993
|
-
const raw =
|
|
1077
|
+
const raw = readFileSync5(this.plaintextFilePath, "utf-8");
|
|
994
1078
|
const parsed = JSON.parse(raw);
|
|
995
1079
|
this.data = {
|
|
996
1080
|
version: 1,
|
|
@@ -1002,16 +1086,16 @@ var ReceiptArchive = class {
|
|
|
1002
1086
|
try {
|
|
1003
1087
|
writeFileSync4(
|
|
1004
1088
|
`${this.plaintextFilePath}.corrupt-${Date.now()}`,
|
|
1005
|
-
|
|
1089
|
+
readFileSync5(this.plaintextFilePath)
|
|
1006
1090
|
);
|
|
1007
1091
|
} catch {
|
|
1008
1092
|
}
|
|
1009
1093
|
}
|
|
1010
1094
|
}
|
|
1011
1095
|
loadEncrypted() {
|
|
1012
|
-
if (!
|
|
1096
|
+
if (!existsSync5(this.encryptedFilePath)) return;
|
|
1013
1097
|
try {
|
|
1014
|
-
const raw =
|
|
1098
|
+
const raw = readFileSync5(this.encryptedFilePath, "utf-8");
|
|
1015
1099
|
const data = JSON.parse(raw);
|
|
1016
1100
|
const decrypted = this.decrypt(data.blob);
|
|
1017
1101
|
const parsed = JSON.parse(decrypted);
|
|
@@ -1025,7 +1109,7 @@ var ReceiptArchive = class {
|
|
|
1025
1109
|
try {
|
|
1026
1110
|
writeFileSync4(
|
|
1027
1111
|
`${this.encryptedFilePath}.corrupt-${Date.now()}`,
|
|
1028
|
-
|
|
1112
|
+
readFileSync5(this.encryptedFilePath)
|
|
1029
1113
|
);
|
|
1030
1114
|
} catch {
|
|
1031
1115
|
}
|
|
@@ -1055,9 +1139,16 @@ var ReceiptArchive = class {
|
|
|
1055
1139
|
// src/lib/gatekeeper.ts
|
|
1056
1140
|
import { verify } from "@hap/core";
|
|
1057
1141
|
var MCPGatekeeper = class {
|
|
1058
|
-
|
|
1142
|
+
/**
|
|
1143
|
+
* No ExecutionLog dependency by construction. The local record is
|
|
1144
|
+
* display-only (protocol.md → "Executor Gating, Context vs Bounds,
|
|
1145
|
+
* Display-Only Logs"), so the Gatekeeper must not be able to read it: with
|
|
1146
|
+
* no log in scope, a local cumulative check cannot be reintroduced by
|
|
1147
|
+
* accident. `SharedState.executionLog` stays — it feeds the UI's consumption
|
|
1148
|
+
* display and nothing else.
|
|
1149
|
+
*/
|
|
1150
|
+
constructor(cache) {
|
|
1059
1151
|
this.cache = cache;
|
|
1060
|
-
this.executionLog = executionLog;
|
|
1061
1152
|
}
|
|
1062
1153
|
/**
|
|
1063
1154
|
* Verify an execution request against a cached authorization.
|
|
@@ -1104,16 +1195,15 @@ var MCPGatekeeper = class {
|
|
|
1104
1195
|
attestations: auth.attestations.map((a) => a.blob),
|
|
1105
1196
|
execution,
|
|
1106
1197
|
context: resolvedContext,
|
|
1107
|
-
//
|
|
1108
|
-
//
|
|
1109
|
-
//
|
|
1110
|
-
//
|
|
1111
|
-
//
|
|
1112
|
-
//
|
|
1113
|
-
// the local gate never fired and the AS was doing all the enforcing.
|
|
1198
|
+
// Identifies the grant whose bounds are being checked. hap-core reads it
|
|
1199
|
+
// only to scope a cumulative lookup, which no longer happens here (see
|
|
1200
|
+
// below); it is kept because it belongs to the request, not to the
|
|
1201
|
+
// dropped check. It cannot go inside `frame`: that is validated against
|
|
1202
|
+
// the profile's boundsSchema, which declares no `path` field in any
|
|
1203
|
+
// shipped profile, so an extra key there fails with "Unknown field".
|
|
1114
1204
|
path: auth.path
|
|
1115
1205
|
};
|
|
1116
|
-
const result = await verify(request, publicKeyHex
|
|
1206
|
+
const result = await verify(request, publicKeyHex);
|
|
1117
1207
|
return { result, authorization: auth };
|
|
1118
1208
|
}
|
|
1119
1209
|
};
|
|
@@ -1134,7 +1224,7 @@ var SharedState = class {
|
|
|
1134
1224
|
this.executionLog = new ExecutionLog(gateStorePath);
|
|
1135
1225
|
this.denialLog = new DenialLog(gateStorePath);
|
|
1136
1226
|
this.receiptArchive = new ReceiptArchive(gateStorePath);
|
|
1137
|
-
this.gatekeeper = new MCPGatekeeper(this.cache
|
|
1227
|
+
this.gatekeeper = new MCPGatekeeper(this.cache);
|
|
1138
1228
|
}
|
|
1139
1229
|
/**
|
|
1140
1230
|
* Archive a signed receipt into the local receipt archive — the subject's
|
|
@@ -1282,17 +1372,17 @@ function formatConsumptionFull(entries) {
|
|
|
1282
1372
|
}
|
|
1283
1373
|
|
|
1284
1374
|
// src/lib/context-loader.ts
|
|
1285
|
-
import { readFileSync as
|
|
1375
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
1286
1376
|
import { homedir as homedir5 } from "os";
|
|
1287
|
-
import { join as
|
|
1288
|
-
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ??
|
|
1377
|
+
import { join as join6 } from "path";
|
|
1378
|
+
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ?? join6(homedir5(), ".suveren");
|
|
1289
1379
|
var BRIEF_MAX_CHARS = 16 * 1024;
|
|
1290
1380
|
function readContextFile(dataDir) {
|
|
1291
1381
|
const dir = dataDir ?? DEFAULT_DIR5;
|
|
1292
|
-
const filePath =
|
|
1293
|
-
if (!
|
|
1382
|
+
const filePath = join6(dir, "context.md");
|
|
1383
|
+
if (!existsSync6(filePath)) return null;
|
|
1294
1384
|
try {
|
|
1295
|
-
const content =
|
|
1385
|
+
const content = readFileSync6(filePath, "utf-8").trim();
|
|
1296
1386
|
return content || null;
|
|
1297
1387
|
} catch {
|
|
1298
1388
|
return null;
|
|
@@ -1933,10 +2023,11 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
1933
2023
|
return inner(args);
|
|
1934
2024
|
};
|
|
1935
2025
|
if (category === "disabled") {
|
|
2026
|
+
const reason = tool.gating.disabledReason;
|
|
1936
2027
|
return async () => ({
|
|
1937
2028
|
content: [{
|
|
1938
2029
|
type: "text",
|
|
1939
|
-
text: `Tool "${tool.namespacedName}" is disabled by the integration manifest and cannot be used.`
|
|
2030
|
+
text: reason ? `Tool "${tool.namespacedName}" is refused: ${reason}. A tool that no manifest entry describes cannot be gated \u2014 there is nothing declaring which action type it performs or how its arguments map to the bounds. Add an entry for "${tool.originalName}" under this integration's toolGating.overrides (with "category": "read" for a read-only tool) before it can be used.` : `Tool "${tool.namespacedName}" is disabled by the integration manifest and cannot be used.`
|
|
1940
2031
|
}],
|
|
1941
2032
|
isError: true
|
|
1942
2033
|
});
|
|
@@ -2257,7 +2348,12 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2257
2348
|
executionContext: { ...execution },
|
|
2258
2349
|
amount: typeof execution.amount === "number" ? execution.amount : void 0,
|
|
2259
2350
|
idempotencyKey: randomUUID(),
|
|
2260
|
-
|
|
2351
|
+
// Privacy: send the hash and how to reproduce it — never the
|
|
2352
|
+
// preimage. `binding` also carries `boundContent`, the plaintext
|
|
2353
|
+
// that was hashed (an email's to/cc/subject/body); it stays on
|
|
2354
|
+
// this machine for the local archive, so it must be picked out
|
|
2355
|
+
// field by field rather than spread.
|
|
2356
|
+
...binding ? { contentHash: binding.contentHash, contentBinding: binding.contentBinding } : {}
|
|
2261
2357
|
});
|
|
2262
2358
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
2263
2359
|
await state2.archiveReceipt(receipt, {
|
|
@@ -2407,7 +2503,7 @@ function buildCapabilityMap(profileId, toolGating, integrationManager2) {
|
|
|
2407
2503
|
const shortName = shortProfileName2(profileId);
|
|
2408
2504
|
const gated = [];
|
|
2409
2505
|
const readOnly = [];
|
|
2410
|
-
const
|
|
2506
|
+
const undescribed = [];
|
|
2411
2507
|
for (const tool of allTools) {
|
|
2412
2508
|
if (!tool.gating || !tool.gating.profile) {
|
|
2413
2509
|
continue;
|
|
@@ -2429,12 +2525,7 @@ function buildCapabilityMap(profileId, toolGating, integrationManager2) {
|
|
|
2429
2525
|
const actionType = override.staticExecution?.action_type ?? "unknown";
|
|
2430
2526
|
gated.push(` - ${tool.originalName}: ${actionType}${mappingDesc ? `, ${mappingDesc}` : ""}`);
|
|
2431
2527
|
} else {
|
|
2432
|
-
|
|
2433
|
-
if (defaultAction === "read" && Object.keys(toolGating.default.executionMapping ?? {}).length === 0) {
|
|
2434
|
-
defaultGated.push(tool.originalName);
|
|
2435
|
-
} else {
|
|
2436
|
-
gated.push(` - ${tool.originalName}: ${defaultAction ?? "default"} (default gating)`);
|
|
2437
|
-
}
|
|
2528
|
+
undescribed.push(tool.originalName);
|
|
2438
2529
|
}
|
|
2439
2530
|
}
|
|
2440
2531
|
const lines = [];
|
|
@@ -2446,10 +2537,12 @@ function buildCapabilityMap(profileId, toolGating, integrationManager2) {
|
|
|
2446
2537
|
if (readOnly.length > 0) {
|
|
2447
2538
|
lines.push(` Read-only (no authorization needed): ${readOnly.join(", ")}`);
|
|
2448
2539
|
}
|
|
2449
|
-
if (
|
|
2450
|
-
lines.push(
|
|
2540
|
+
if (undescribed.length > 0) {
|
|
2541
|
+
lines.push(
|
|
2542
|
+
` Refused (no manifest entry \u2014 do not call): ${undescribed.join(", ")}`
|
|
2543
|
+
);
|
|
2451
2544
|
}
|
|
2452
|
-
if (gated.length === 0 && readOnly.length === 0 &&
|
|
2545
|
+
if (gated.length === 0 && readOnly.length === 0 && undescribed.length === 0) {
|
|
2453
2546
|
lines.push(" No tools discovered for this profile.");
|
|
2454
2547
|
}
|
|
2455
2548
|
return lines.join("\n");
|
|
@@ -2738,7 +2831,10 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2738
2831
|
// SPClient therefore treats proposalId as retry-safe on its own; a
|
|
2739
2832
|
// PROPOSAL_ALREADY_EXECUTED answer is still a definitive rejection
|
|
2740
2833
|
// (never retried) and means a *different* caller consumed the proposal.
|
|
2741
|
-
|
|
2834
|
+
// Privacy: hash + how to reproduce it only. `binding.boundContent` is
|
|
2835
|
+
// the plaintext preimage (what the human approved) and never leaves
|
|
2836
|
+
// this machine — see the archive call below.
|
|
2837
|
+
...binding ? { contentHash: binding.contentHash, contentBinding: binding.contentBinding } : {}
|
|
2742
2838
|
});
|
|
2743
2839
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
2744
2840
|
await state2.archiveReceipt(receipt, {
|
|
@@ -3076,16 +3172,16 @@ function verifyGateContentHashes(content, auth) {
|
|
|
3076
3172
|
}
|
|
3077
3173
|
|
|
3078
3174
|
// src/lib/integration-registry.ts
|
|
3079
|
-
import { mkdirSync as mkdirSync5, readFileSync as
|
|
3175
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
|
|
3080
3176
|
import { homedir as homedir6 } from "os";
|
|
3081
|
-
import { dirname as dirname5, join as
|
|
3082
|
-
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
3177
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
3178
|
+
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join7(homedir6(), ".suveren");
|
|
3083
3179
|
var IntegrationRegistry = class {
|
|
3084
3180
|
integrations = /* @__PURE__ */ new Map();
|
|
3085
3181
|
filePath;
|
|
3086
3182
|
constructor(dataDir) {
|
|
3087
3183
|
const dir = dataDir ?? DEFAULT_DATA_DIR;
|
|
3088
|
-
this.filePath =
|
|
3184
|
+
this.filePath = join7(dir, "integrations.json");
|
|
3089
3185
|
this.load();
|
|
3090
3186
|
}
|
|
3091
3187
|
// ─── CRUD ───────────────────────────────────────────────────────────────
|
|
@@ -3116,12 +3212,12 @@ var IntegrationRegistry = class {
|
|
|
3116
3212
|
}
|
|
3117
3213
|
// ─── Load / Save ────────────────────────────────────────────────────────
|
|
3118
3214
|
load() {
|
|
3119
|
-
if (!
|
|
3215
|
+
if (!existsSync7(this.filePath)) {
|
|
3120
3216
|
mkdirSync5(dirname5(this.filePath), { recursive: true });
|
|
3121
3217
|
return;
|
|
3122
3218
|
}
|
|
3123
3219
|
try {
|
|
3124
|
-
const raw =
|
|
3220
|
+
const raw = readFileSync7(this.filePath, "utf-8");
|
|
3125
3221
|
const data = JSON.parse(raw);
|
|
3126
3222
|
const migrated = data.integrations.map((i) => {
|
|
3127
3223
|
if ("toolGating" in i && !("profile" in i)) {
|
|
@@ -3157,25 +3253,31 @@ var IntegrationRegistry = class {
|
|
|
3157
3253
|
|
|
3158
3254
|
// src/lib/integration-manager.ts
|
|
3159
3255
|
import { homedir as homedir7 } from "os";
|
|
3160
|
-
import { join as
|
|
3161
|
-
import { existsSync as
|
|
3256
|
+
import { join as join8, delimiter } from "path";
|
|
3257
|
+
import { existsSync as existsSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync8, rmSync } from "fs";
|
|
3162
3258
|
import { execFile } from "child_process";
|
|
3163
3259
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3164
3260
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3165
3261
|
import { getProfile as getProfile5 } from "@hap/core";
|
|
3166
|
-
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
3167
|
-
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ??
|
|
3168
|
-
var
|
|
3262
|
+
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join8(homedir7(), ".suveren");
|
|
3263
|
+
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ?? join8(DEFAULT_DATA_DIR2, "integrations");
|
|
3264
|
+
var installLock = Promise.resolve();
|
|
3265
|
+
function withInstallLock(task) {
|
|
3266
|
+
const run = installLock.then(task, task);
|
|
3267
|
+
installLock = run.then(() => void 0, () => void 0);
|
|
3268
|
+
return run;
|
|
3269
|
+
}
|
|
3270
|
+
var INTEGRATIONS_BIN = join8(INTEGRATIONS_DIR, "node_modules", ".bin");
|
|
3169
3271
|
function buildPath() {
|
|
3170
3272
|
const base = process.env.PATH ?? "";
|
|
3171
3273
|
return [INTEGRATIONS_BIN, base].join(delimiter);
|
|
3172
3274
|
}
|
|
3173
3275
|
function ensureIntegrationsDir() {
|
|
3174
|
-
if (!
|
|
3276
|
+
if (!existsSync8(INTEGRATIONS_DIR)) {
|
|
3175
3277
|
mkdirSync6(INTEGRATIONS_DIR, { recursive: true });
|
|
3176
3278
|
}
|
|
3177
|
-
const pkgPath =
|
|
3178
|
-
if (!
|
|
3279
|
+
const pkgPath = join8(INTEGRATIONS_DIR, "package.json");
|
|
3280
|
+
if (!existsSync8(pkgPath)) {
|
|
3179
3281
|
writeFileSync6(pkgPath, JSON.stringify({ name: "suveren-integrations", version: "1.0.0", private: true }, null, 2));
|
|
3180
3282
|
}
|
|
3181
3283
|
}
|
|
@@ -3242,19 +3344,19 @@ var IntegrationManager = class {
|
|
|
3242
3344
|
* exist, and treat anything else as not-installed (and reinstallable).
|
|
3243
3345
|
*/
|
|
3244
3346
|
isUsableInstall(npmPackage) {
|
|
3245
|
-
const pkgDir =
|
|
3246
|
-
const pkgJson =
|
|
3247
|
-
if (!
|
|
3347
|
+
const pkgDir = join8(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
3348
|
+
const pkgJson = join8(pkgDir, "package.json");
|
|
3349
|
+
if (!existsSync8(pkgDir) || !existsSync8(pkgJson)) return false;
|
|
3248
3350
|
try {
|
|
3249
|
-
const pkg = JSON.parse(
|
|
3351
|
+
const pkg = JSON.parse(readFileSync8(pkgJson, "utf8"));
|
|
3250
3352
|
const defaultBinName = (pkg.name ?? npmPackage).split("/").pop() ?? "";
|
|
3251
3353
|
const binMap = typeof pkg.bin === "string" ? { [defaultBinName]: pkg.bin } : pkg.bin ?? {};
|
|
3252
3354
|
const binEntries = Object.entries(binMap);
|
|
3253
3355
|
for (const [binName, target] of binEntries) {
|
|
3254
|
-
if (!
|
|
3356
|
+
if (!existsSync8(join8(pkgDir, target))) return false;
|
|
3255
3357
|
if (!this.binShimExists(binName)) return false;
|
|
3256
3358
|
}
|
|
3257
|
-
if (binEntries.length === 0 && pkg.main && !
|
|
3359
|
+
if (binEntries.length === 0 && pkg.main && !existsSync8(join8(pkgDir, pkg.main))) return false;
|
|
3258
3360
|
return true;
|
|
3259
3361
|
} catch {
|
|
3260
3362
|
return false;
|
|
@@ -3268,7 +3370,7 @@ var IntegrationManager = class {
|
|
|
3268
3370
|
binShimExists(binName) {
|
|
3269
3371
|
if (!binName) return false;
|
|
3270
3372
|
const candidates = process.platform === "win32" ? [binName, `${binName}.cmd`, `${binName}.CMD`, `${binName}.ps1`] : [binName];
|
|
3271
|
-
return candidates.some((c) =>
|
|
3373
|
+
return candidates.some((c) => existsSync8(join8(INTEGRATIONS_BIN, c)));
|
|
3272
3374
|
}
|
|
3273
3375
|
/**
|
|
3274
3376
|
* Install an npm package into the managed integrations directory if not
|
|
@@ -3285,8 +3387,15 @@ var IntegrationManager = class {
|
|
|
3285
3387
|
async ensureInstalled(npmPackage) {
|
|
3286
3388
|
ensureIntegrationsDir();
|
|
3287
3389
|
if (this.isUsableInstall(npmPackage)) return;
|
|
3288
|
-
|
|
3289
|
-
|
|
3390
|
+
return withInstallLock(async () => {
|
|
3391
|
+
if (this.isUsableInstall(npmPackage)) return;
|
|
3392
|
+
await this.installNow(npmPackage);
|
|
3393
|
+
});
|
|
3394
|
+
}
|
|
3395
|
+
/** The actual install. Callers MUST hold the install lock. */
|
|
3396
|
+
async installNow(npmPackage) {
|
|
3397
|
+
const pkgDir = join8(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
3398
|
+
if (existsSync8(pkgDir)) {
|
|
3290
3399
|
console.error(`[IntegrationManager] Removing unusable install of ${npmPackage}`);
|
|
3291
3400
|
try {
|
|
3292
3401
|
rmSync(pkgDir, { recursive: true, force: true });
|
|
@@ -3658,8 +3767,9 @@ var IntegrationManager = class {
|
|
|
3658
3767
|
}
|
|
3659
3768
|
return {
|
|
3660
3769
|
profile: profileId,
|
|
3661
|
-
executionMapping:
|
|
3662
|
-
|
|
3770
|
+
executionMapping: {},
|
|
3771
|
+
category: "disabled",
|
|
3772
|
+
disabledReason: "not described in manifest"
|
|
3663
3773
|
};
|
|
3664
3774
|
}
|
|
3665
3775
|
/**
|
|
@@ -3701,28 +3811,28 @@ var IntegrationManager = class {
|
|
|
3701
3811
|
};
|
|
3702
3812
|
|
|
3703
3813
|
// src/lib/profile-loader.ts
|
|
3704
|
-
import { readFileSync as
|
|
3705
|
-
import { join as
|
|
3814
|
+
import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
|
|
3815
|
+
import { join as join9, resolve } from "path";
|
|
3706
3816
|
import { registerProfile } from "@hap/core";
|
|
3707
3817
|
function loadProfiles(profilesDir) {
|
|
3708
|
-
const dir = resolve(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ??
|
|
3709
|
-
const indexPath =
|
|
3710
|
-
if (!
|
|
3818
|
+
const dir = resolve(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ?? join9(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "..", "hap-profiles"));
|
|
3819
|
+
const indexPath = join9(dir, "index.json");
|
|
3820
|
+
if (!existsSync9(indexPath)) {
|
|
3711
3821
|
warnNoProfiles(`No index.json at ${indexPath}`);
|
|
3712
3822
|
return 0;
|
|
3713
3823
|
}
|
|
3714
3824
|
let index;
|
|
3715
3825
|
try {
|
|
3716
|
-
index = JSON.parse(
|
|
3826
|
+
index = JSON.parse(readFileSync9(indexPath, "utf-8"));
|
|
3717
3827
|
} catch (err) {
|
|
3718
3828
|
console.error(`[ProfileLoader] Failed to parse ${indexPath}:`, err);
|
|
3719
3829
|
return 0;
|
|
3720
3830
|
}
|
|
3721
3831
|
let loaded = 0;
|
|
3722
3832
|
for (const [profileId, relativePath] of Object.entries(index.profiles)) {
|
|
3723
|
-
const profilePath =
|
|
3833
|
+
const profilePath = join9(dir, relativePath);
|
|
3724
3834
|
try {
|
|
3725
|
-
const profile = JSON.parse(
|
|
3835
|
+
const profile = JSON.parse(readFileSync9(profilePath, "utf-8"));
|
|
3726
3836
|
registerProfile(profileId, profile);
|
|
3727
3837
|
const shortName = profileId.split("/").pop()?.replace(/@.*$/, "");
|
|
3728
3838
|
if (shortName && shortName !== profileId) {
|
|
@@ -3755,30 +3865,30 @@ function warnNoProfiles(reason) {
|
|
|
3755
3865
|
}
|
|
3756
3866
|
|
|
3757
3867
|
// src/lib/manifest-loader.ts
|
|
3758
|
-
import { readFileSync as
|
|
3759
|
-
import { join as
|
|
3868
|
+
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
|
|
3869
|
+
import { join as join10, resolve as resolve2 } from "path";
|
|
3760
3870
|
var manifests = /* @__PURE__ */ new Map();
|
|
3761
3871
|
function loadManifests(integrationsDir) {
|
|
3762
3872
|
const dir = resolve2(
|
|
3763
|
-
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ??
|
|
3873
|
+
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ?? join10(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "content", "integrations")
|
|
3764
3874
|
);
|
|
3765
|
-
const indexPath =
|
|
3766
|
-
if (!
|
|
3875
|
+
const indexPath = join10(dir, "index.json");
|
|
3876
|
+
if (!existsSync10(indexPath)) {
|
|
3767
3877
|
console.error(`[ManifestLoader] No index.json found at ${indexPath}, skipping manifest loading`);
|
|
3768
3878
|
return 0;
|
|
3769
3879
|
}
|
|
3770
3880
|
let index;
|
|
3771
3881
|
try {
|
|
3772
|
-
index = JSON.parse(
|
|
3882
|
+
index = JSON.parse(readFileSync10(indexPath, "utf-8"));
|
|
3773
3883
|
} catch (err) {
|
|
3774
3884
|
console.error(`[ManifestLoader] Failed to parse ${indexPath}:`, err);
|
|
3775
3885
|
return 0;
|
|
3776
3886
|
}
|
|
3777
3887
|
let loaded = 0;
|
|
3778
3888
|
for (const [id, relativePath] of Object.entries(index.integrations)) {
|
|
3779
|
-
const manifestPath =
|
|
3889
|
+
const manifestPath = join10(dir, relativePath);
|
|
3780
3890
|
try {
|
|
3781
|
-
const manifest = JSON.parse(
|
|
3891
|
+
const manifest = JSON.parse(readFileSync10(manifestPath, "utf-8"));
|
|
3782
3892
|
manifests.set(id, manifest);
|
|
3783
3893
|
loaded++;
|
|
3784
3894
|
} catch (err) {
|