@suveren/gateway 0.8.7 → 0.10.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/README.md +33 -1
- package/bin/suveren-gateway.js +363 -9
- package/content/integrations/erp.json +184 -0
- package/content/integrations/index.json +2 -1
- package/dist/control-plane/index.mjs +835 -118
- package/dist/mcp-server/http.mjs +876 -193
- package/dist/ui/assets/{index-tzStUGuj.js → index-B1qNl7zo.js} +21 -21
- package/dist/ui/index.html +1 -1
- package/lib/as-pairing.mjs +77 -0
- package/lib/config.d.mts +37 -0
- package/lib/config.mjs +198 -0
- package/node_modules/@hap/core/dist/index.d.mts +33 -2
- package/node_modules/@hap/core/dist/index.d.ts +33 -2
- package/node_modules/@hap/core/dist/index.js +26 -2
- package/node_modules/@hap/core/dist/index.mjs +25 -2
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/gatekeeper.ts +36 -2
- package/node_modules/@hap/core/src/types.ts +21 -1
- package/node_modules/@hono/node-server/README.md +21 -10
- package/node_modules/@hono/node-server/dist/early-hints.cjs +1 -1
- package/node_modules/@hono/node-server/dist/early-hints.mjs +1 -1
- package/node_modules/@hono/node-server/dist/index.cjs +41 -19
- package/node_modules/@hono/node-server/dist/index.mjs +42 -20
- package/node_modules/@hono/node-server/dist/serve-static.cjs +1 -0
- package/node_modules/@hono/node-server/dist/serve-static.d.cts +2 -1
- package/node_modules/@hono/node-server/dist/serve-static.d.mts +2 -1
- package/node_modules/@hono/node-server/dist/serve-static.mjs +1 -0
- package/node_modules/@hono/node-server/package.json +3 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts +43 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js +26 -5
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts +11 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js +96 -14
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/client/simpleClientCredentials.d.ts +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/client/simpleClientCredentials.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/client/simpleClientCredentials.js +11 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/client/simpleClientCredentials.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts +2 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/auth/providers/proxyProvider.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/auth/providers/proxyProvider.js +6 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/auth/providers/proxyProvider.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/auth.d.ts +3 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/auth.js +12 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/auth.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth-extensions.d.ts +43 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth-extensions.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth-extensions.js +26 -5
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth-extensions.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.d.ts +11 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js +96 -14
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/client/simpleClientCredentials.d.ts +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/client/simpleClientCredentials.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/client/simpleClientCredentials.js +11 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/client/simpleClientCredentials.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts +2 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/providers/proxyProvider.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/providers/proxyProvider.js +6 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/providers/proxyProvider.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.d.ts +3 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js +12 -2
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/package.json +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/crypto.d.ts +2 -2
- package/node_modules/@types/node/dgram.d.ts +1 -1
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/hono/dist/_virtual/_rolldown/runtime.js +13 -0
- package/node_modules/hono/dist/adapter/aws-lambda/conninfo.js +42 -23
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +318 -344
- package/node_modules/hono/dist/adapter/aws-lambda/index.js +2 -8
- package/node_modules/hono/dist/adapter/aws-lambda/types.js +1 -0
- package/node_modules/hono/dist/adapter/bun/conninfo.js +20 -25
- package/node_modules/hono/dist/adapter/bun/index.js +3 -13
- package/node_modules/hono/dist/adapter/bun/serve-static.js +27 -27
- package/node_modules/hono/dist/adapter/bun/server.js +11 -5
- package/node_modules/hono/dist/adapter/bun/ssg.js +25 -15
- package/node_modules/hono/dist/adapter/bun/websocket.js +61 -68
- package/node_modules/hono/dist/adapter/cloudflare-pages/conninfo.js +24 -9
- package/node_modules/hono/dist/adapter/cloudflare-pages/handler.js +59 -62
- package/node_modules/hono/dist/adapter/cloudflare-pages/index.js +2 -8
- package/node_modules/hono/dist/adapter/cloudflare-workers/conninfo.js +7 -9
- package/node_modules/hono/dist/adapter/cloudflare-workers/index.js +3 -8
- package/node_modules/hono/dist/adapter/cloudflare-workers/serve-static-module.js +5 -6
- package/node_modules/hono/dist/adapter/cloudflare-workers/serve-static.js +26 -20
- package/node_modules/hono/dist/adapter/cloudflare-workers/utils.js +21 -34
- package/node_modules/hono/dist/adapter/cloudflare-workers/websocket.js +31 -39
- package/node_modules/hono/dist/adapter/deno/conninfo.js +16 -13
- package/node_modules/hono/dist/adapter/deno/deno.d.js +1 -0
- package/node_modules/hono/dist/adapter/deno/index.js +3 -10
- package/node_modules/hono/dist/adapter/deno/serve-static.js +33 -38
- package/node_modules/hono/dist/adapter/deno/ssg.js +27 -16
- package/node_modules/hono/dist/adapter/deno/websocket.js +30 -30
- package/node_modules/hono/dist/adapter/lambda-edge/conninfo.js +7 -9
- package/node_modules/hono/dist/adapter/lambda-edge/handler.js +102 -101
- package/node_modules/hono/dist/adapter/lambda-edge/index.js +2 -6
- package/node_modules/hono/dist/adapter/netlify/conninfo.js +24 -9
- package/node_modules/hono/dist/adapter/netlify/handler.js +10 -8
- package/node_modules/hono/dist/adapter/netlify/index.js +3 -2
- package/node_modules/hono/dist/adapter/netlify/mod.js +2 -6
- package/node_modules/hono/dist/adapter/service-worker/handler.js +15 -19
- package/node_modules/hono/dist/adapter/service-worker/index.js +23 -7
- package/node_modules/hono/dist/adapter/service-worker/types.js +1 -0
- package/node_modules/hono/dist/adapter/vercel/conninfo.js +7 -10
- package/node_modules/hono/dist/adapter/vercel/handler.js +8 -6
- package/node_modules/hono/dist/adapter/vercel/index.js +2 -6
- package/node_modules/hono/dist/cjs/_virtual/_rolldown/runtime.js +33 -0
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/conninfo.js +42 -44
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +326 -373
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/index.js +7 -34
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/types.js +0 -15
- package/node_modules/hono/dist/cjs/adapter/bun/conninfo.js +21 -47
- package/node_modules/hono/dist/cjs/adapter/bun/index.js +14 -45
- package/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +29 -50
- package/node_modules/hono/dist/cjs/adapter/bun/server.js +11 -26
- package/node_modules/hono/dist/cjs/adapter/bun/ssg.js +24 -35
- package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +63 -91
- package/node_modules/hono/dist/cjs/adapter/cloudflare-pages/conninfo.js +25 -31
- package/node_modules/hono/dist/cjs/adapter/cloudflare-pages/handler.js +61 -85
- package/node_modules/hono/dist/cjs/adapter/cloudflare-pages/index.js +7 -34
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/conninfo.js +8 -31
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/index.js +7 -33
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/serve-static-module.js +7 -29
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/serve-static.js +27 -42
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/utils.js +21 -55
- package/node_modules/hono/dist/cjs/adapter/cloudflare-workers/websocket.js +33 -62
- package/node_modules/hono/dist/cjs/adapter/deno/conninfo.js +16 -34
- package/node_modules/hono/dist/cjs/adapter/deno/index.js +10 -38
- package/node_modules/hono/dist/cjs/adapter/deno/serve-static.js +33 -59
- package/node_modules/hono/dist/cjs/adapter/deno/ssg.js +27 -37
- package/node_modules/hono/dist/cjs/adapter/deno/websocket.js +32 -53
- package/node_modules/hono/dist/cjs/adapter/lambda-edge/conninfo.js +8 -31
- package/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +102 -130
- package/node_modules/hono/dist/cjs/adapter/lambda-edge/index.js +5 -30
- package/node_modules/hono/dist/cjs/adapter/netlify/conninfo.js +25 -31
- package/node_modules/hono/dist/cjs/adapter/netlify/handler.js +10 -29
- package/node_modules/hono/dist/cjs/adapter/netlify/index.js +5 -21
- package/node_modules/hono/dist/cjs/adapter/netlify/mod.js +5 -30
- package/node_modules/hono/dist/cjs/adapter/service-worker/handler.js +16 -41
- package/node_modules/hono/dist/cjs/adapter/service-worker/index.js +25 -30
- package/node_modules/hono/dist/cjs/adapter/service-worker/types.js +0 -15
- package/node_modules/hono/dist/cjs/adapter/vercel/conninfo.js +8 -32
- package/node_modules/hono/dist/cjs/adapter/vercel/handler.js +8 -27
- package/node_modules/hono/dist/cjs/adapter/vercel/index.js +5 -30
- package/node_modules/hono/dist/cjs/client/client.js +139 -212
- package/node_modules/hono/dist/cjs/client/fetch-result-please.js +62 -80
- package/node_modules/hono/dist/cjs/client/index.js +7 -32
- package/node_modules/hono/dist/cjs/client/types.js +0 -15
- package/node_modules/hono/dist/cjs/client/utils.js +54 -92
- package/node_modules/hono/dist/cjs/compose.js +49 -66
- package/node_modules/hono/dist/cjs/context.js +379 -450
- package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +47 -72
- package/node_modules/hono/dist/cjs/helper/accepts/index.js +3 -27
- package/node_modules/hono/dist/cjs/helper/adapter/index.js +33 -73
- package/node_modules/hono/dist/cjs/helper/conninfo/index.js +0 -15
- package/node_modules/hono/dist/cjs/helper/conninfo/types.js +0 -15
- package/node_modules/hono/dist/cjs/helper/cookie/index.js +75 -116
- package/node_modules/hono/dist/cjs/helper/css/common.js +165 -244
- package/node_modules/hono/dist/cjs/helper/css/index.js +136 -151
- package/node_modules/hono/dist/cjs/helper/dev/index.js +45 -71
- package/node_modules/hono/dist/cjs/helper/factory/index.js +30 -51
- package/node_modules/hono/dist/cjs/helper/html/index.js +32 -62
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +113 -106
- package/node_modules/hono/dist/cjs/helper/route/index.js +123 -66
- package/node_modules/hono/dist/cjs/helper/ssg/index.js +19 -43
- package/node_modules/hono/dist/cjs/helper/ssg/middleware.js +56 -64
- package/node_modules/hono/dist/cjs/helper/ssg/plugins.js +55 -57
- package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +196 -296
- package/node_modules/hono/dist/cjs/helper/ssg/utils.js +47 -90
- package/node_modules/hono/dist/cjs/helper/streaming/index.js +8 -35
- package/node_modules/hono/dist/cjs/helper/streaming/sse.js +53 -85
- package/node_modules/hono/dist/cjs/helper/streaming/stream.js +23 -53
- package/node_modules/hono/dist/cjs/helper/streaming/text.js +10 -32
- package/node_modules/hono/dist/cjs/helper/streaming/utils.js +13 -32
- package/node_modules/hono/dist/cjs/helper/testing/index.js +16 -31
- package/node_modules/hono/dist/cjs/helper/websocket/index.js +51 -76
- package/node_modules/hono/dist/cjs/hono-base.js +345 -403
- package/node_modules/hono/dist/cjs/hono.js +28 -42
- package/node_modules/hono/dist/cjs/http-exception.js +55 -56
- package/node_modules/hono/dist/cjs/index.js +22 -30
- package/node_modules/hono/dist/cjs/jsx/base.js +237 -366
- package/node_modules/hono/dist/cjs/jsx/children.js +16 -41
- package/node_modules/hono/dist/cjs/jsx/components.js +119 -192
- package/node_modules/hono/dist/cjs/jsx/constants.js +15 -42
- package/node_modules/hono/dist/cjs/jsx/context.js +144 -162
- package/node_modules/hono/dist/cjs/jsx/dom/client.js +49 -69
- package/node_modules/hono/dist/cjs/jsx/dom/components.js +23 -52
- package/node_modules/hono/dist/cjs/jsx/dom/context.js +39 -67
- package/node_modules/hono/dist/cjs/jsx/dom/css.js +143 -158
- package/node_modules/hono/dist/cjs/jsx/dom/hooks/index.js +55 -64
- package/node_modules/hono/dist/cjs/jsx/dom/index.js +114 -173
- package/node_modules/hono/dist/cjs/jsx/dom/intrinsic-element/components.js +282 -375
- package/node_modules/hono/dist/cjs/jsx/dom/jsx-dev-runtime.js +14 -49
- package/node_modules/hono/dist/cjs/jsx/dom/jsx-runtime.js +5 -32
- package/node_modules/hono/dist/cjs/jsx/dom/render.js +469 -623
- package/node_modules/hono/dist/cjs/jsx/dom/server.js +37 -64
- package/node_modules/hono/dist/cjs/jsx/dom/utils.js +7 -30
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +225 -318
- package/node_modules/hono/dist/cjs/jsx/index.js +86 -135
- package/node_modules/hono/dist/cjs/jsx/intrinsic-element/common.js +20 -43
- package/node_modules/hono/dist/cjs/jsx/intrinsic-element/components.js +117 -168
- package/node_modules/hono/dist/cjs/jsx/intrinsic-elements.js +0 -15
- package/node_modules/hono/dist/cjs/jsx/jsx-dev-runtime.js +14 -39
- package/node_modules/hono/dist/cjs/jsx/jsx-runtime.js +34 -68
- package/node_modules/hono/dist/cjs/jsx/streaming.js +123 -166
- package/node_modules/hono/dist/cjs/jsx/types.js +0 -15
- package/node_modules/hono/dist/cjs/jsx/utils.js +91 -175
- package/node_modules/hono/dist/cjs/middleware/basic-auth/index.js +98 -86
- package/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +92 -109
- package/node_modules/hono/dist/cjs/middleware/body-limit/index.js +66 -72
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +153 -199
- package/node_modules/hono/dist/cjs/middleware/combine/index.js +135 -95
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +73 -88
- package/node_modules/hono/dist/cjs/middleware/context-storage/index.js +49 -41
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +107 -107
- package/node_modules/hono/dist/cjs/middleware/csrf/index.js +101 -72
- package/node_modules/hono/dist/cjs/middleware/etag/digest.js +58 -97
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +71 -91
- package/node_modules/hono/dist/cjs/middleware/ip-restriction/index.js +161 -169
- package/node_modules/hono/dist/cjs/middleware/jsx-renderer/index.js +99 -77
- package/node_modules/hono/dist/cjs/middleware/jwk/index.js +3 -27
- package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +118 -135
- package/node_modules/hono/dist/cjs/middleware/jwt/index.js +9 -38
- package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +120 -141
- package/node_modules/hono/dist/cjs/middleware/language/index.js +7 -35
- package/node_modules/hono/dist/cjs/middleware/language/language.js +184 -182
- package/node_modules/hono/dist/cjs/middleware/logger/index.js +41 -62
- package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +82 -88
- package/node_modules/hono/dist/cjs/middleware/method-override/index.js +101 -102
- package/node_modules/hono/dist/cjs/middleware/powered-by/index.js +23 -30
- package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +38 -42
- package/node_modules/hono/dist/cjs/middleware/request-id/index.js +3 -27
- package/node_modules/hono/dist/cjs/middleware/request-id/request-id.js +34 -42
- package/node_modules/hono/dist/cjs/middleware/secure-headers/index.js +4 -29
- package/node_modules/hono/dist/cjs/middleware/secure-headers/permissions-policy.js +0 -15
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +142 -174
- package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +56 -93
- package/node_modules/hono/dist/cjs/middleware/serve-static/path.js +15 -38
- package/node_modules/hono/dist/cjs/middleware/timeout/index.js +40 -45
- package/node_modules/hono/dist/cjs/middleware/timing/index.js +7 -35
- package/node_modules/hono/dist/cjs/middleware/timing/timing.js +177 -118
- package/node_modules/hono/dist/cjs/middleware/trailing-slash/index.js +85 -58
- package/node_modules/hono/dist/cjs/preset/quick.js +18 -37
- package/node_modules/hono/dist/cjs/preset/tiny.js +15 -33
- package/node_modules/hono/dist/cjs/request/constants.js +5 -27
- package/node_modules/hono/dist/cjs/request.js +334 -346
- package/node_modules/hono/dist/cjs/router/linear-router/index.js +3 -27
- package/node_modules/hono/dist/cjs/router/linear-router/router.js +95 -143
- package/node_modules/hono/dist/cjs/router/pattern-router/index.js +3 -27
- package/node_modules/hono/dist/cjs/router/pattern-router/router.js +41 -63
- package/node_modules/hono/dist/cjs/router/reg-exp-router/index.js +7 -34
- package/node_modules/hono/dist/cjs/router/reg-exp-router/matcher.js +18 -45
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +91 -135
- package/node_modules/hono/dist/cjs/router/reg-exp-router/prepared-router.js +92 -161
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +98 -147
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +73 -89
- package/node_modules/hono/dist/cjs/router/smart-router/index.js +3 -27
- package/node_modules/hono/dist/cjs/router/smart-router/router.js +49 -79
- package/node_modules/hono/dist/cjs/router/trie-router/index.js +3 -27
- package/node_modules/hono/dist/cjs/router/trie-router/node.js +134 -186
- package/node_modules/hono/dist/cjs/router/trie-router/router.js +15 -39
- package/node_modules/hono/dist/cjs/router/utils.js +5 -27
- package/node_modules/hono/dist/cjs/router.js +37 -37
- package/node_modules/hono/dist/cjs/types.js +5 -28
- package/node_modules/hono/dist/cjs/utils/accept.js +177 -225
- package/node_modules/hono/dist/cjs/utils/basic-auth.js +16 -40
- package/node_modules/hono/dist/cjs/utils/body.js +84 -110
- package/node_modules/hono/dist/cjs/utils/buffer.js +43 -91
- package/node_modules/hono/dist/cjs/utils/color.js +35 -44
- package/node_modules/hono/dist/cjs/utils/compress.js +11 -26
- package/node_modules/hono/dist/cjs/utils/concurrent.js +29 -59
- package/node_modules/hono/dist/cjs/utils/constants.js +7 -26
- package/node_modules/hono/dist/cjs/utils/cookie.js +107 -177
- package/node_modules/hono/dist/cjs/utils/crypto.js +30 -61
- package/node_modules/hono/dist/cjs/utils/encode.js +31 -48
- package/node_modules/hono/dist/cjs/utils/filepath.js +23 -54
- package/node_modules/hono/dist/cjs/utils/handler.js +11 -33
- package/node_modules/hono/dist/cjs/utils/headers.js +0 -15
- package/node_modules/hono/dist/cjs/utils/html.js +96 -137
- package/node_modules/hono/dist/cjs/utils/http-status.js +0 -15
- package/node_modules/hono/dist/cjs/utils/ipaddr.js +213 -286
- package/node_modules/hono/dist/cjs/utils/jwt/index.js +14 -27
- package/node_modules/hono/dist/cjs/utils/jwt/jwa.js +25 -42
- package/node_modules/hono/dist/cjs/utils/jwt/jws.js +119 -199
- package/node_modules/hono/dist/cjs/utils/jwt/jwt.js +122 -206
- package/node_modules/hono/dist/cjs/utils/jwt/types.js +122 -159
- package/node_modules/hono/dist/cjs/utils/jwt/utf8.js +9 -28
- package/node_modules/hono/dist/cjs/utils/mime.js +75 -101
- package/node_modules/hono/dist/cjs/utils/stream.js +88 -111
- package/node_modules/hono/dist/cjs/utils/types.js +0 -15
- package/node_modules/hono/dist/cjs/utils/url.js +185 -234
- package/node_modules/hono/dist/cjs/validator/index.js +3 -27
- package/node_modules/hono/dist/cjs/validator/utils.js +0 -15
- package/node_modules/hono/dist/cjs/validator/validator.js +60 -103
- package/node_modules/hono/dist/client/client.js +138 -197
- package/node_modules/hono/dist/client/fetch-result-please.js +59 -56
- package/node_modules/hono/dist/client/index.js +3 -7
- package/node_modules/hono/dist/client/types.js +1 -0
- package/node_modules/hono/dist/client/utils.js +51 -68
- package/node_modules/hono/dist/compose.js +49 -45
- package/node_modules/hono/dist/context.js +376 -426
- package/node_modules/hono/dist/helper/accepts/accepts.js +47 -51
- package/node_modules/hono/dist/helper/accepts/index.js +1 -4
- package/node_modules/hono/dist/helper/adapter/index.js +33 -52
- package/node_modules/hono/dist/helper/conninfo/index.js +1 -0
- package/node_modules/hono/dist/helper/conninfo/types.js +1 -0
- package/node_modules/hono/dist/helper/cookie/index.js +74 -94
- package/node_modules/hono/dist/helper/css/common.js +167 -225
- package/node_modules/hono/dist/helper/css/index.js +132 -137
- package/node_modules/hono/dist/helper/dev/index.js +44 -49
- package/node_modules/hono/dist/helper/factory/index.js +27 -27
- package/node_modules/hono/dist/helper/html/index.js +30 -39
- package/node_modules/hono/dist/helper/proxy/index.js +116 -88
- package/node_modules/hono/dist/helper/route/index.js +121 -43
- package/node_modules/hono/dist/helper/ssg/index.js +3 -18
- package/node_modules/hono/dist/helper/ssg/middleware.js +53 -40
- package/node_modules/hono/dist/helper/ssg/plugins.js +55 -36
- package/node_modules/hono/dist/helper/ssg/ssg.js +198 -283
- package/node_modules/hono/dist/helper/ssg/utils.js +53 -75
- package/node_modules/hono/dist/helper/streaming/index.js +2 -8
- package/node_modules/hono/dist/helper/streaming/sse.js +50 -61
- package/node_modules/hono/dist/helper/streaming/stream.js +22 -31
- package/node_modules/hono/dist/helper/streaming/text.js +9 -10
- package/node_modules/hono/dist/helper/streaming/utils.js +9 -12
- package/node_modules/hono/dist/helper/testing/index.js +16 -10
- package/node_modules/hono/dist/helper/websocket/index.js +49 -53
- package/node_modules/hono/dist/hono-base.js +342 -379
- package/node_modules/hono/dist/hono.js +27 -20
- package/node_modules/hono/dist/http-exception.js +53 -33
- package/node_modules/hono/dist/index.js +19 -6
- package/node_modules/hono/dist/jsx/base.js +231 -340
- package/node_modules/hono/dist/jsx/children.js +16 -20
- package/node_modules/hono/dist/jsx/components.js +118 -170
- package/node_modules/hono/dist/jsx/constants.js +9 -15
- package/node_modules/hono/dist/jsx/context.js +153 -150
- package/node_modules/hono/dist/jsx/dom/client.js +45 -48
- package/node_modules/hono/dist/jsx/dom/components.js +21 -29
- package/node_modules/hono/dist/jsx/dom/context.js +37 -44
- package/node_modules/hono/dist/jsx/dom/css.js +142 -147
- package/node_modules/hono/dist/jsx/dom/hooks/index.js +52 -40
- package/node_modules/hono/dist/jsx/dom/index.js +71 -134
- package/node_modules/hono/dist/jsx/dom/intrinsic-element/components.js +275 -359
- package/node_modules/hono/dist/jsx/dom/jsx-dev-runtime.js +14 -18
- package/node_modules/hono/dist/jsx/dom/jsx-runtime.js +2 -8
- package/node_modules/hono/dist/jsx/dom/render.js +492 -631
- package/node_modules/hono/dist/jsx/dom/server.js +32 -32
- package/node_modules/hono/dist/jsx/dom/utils.js +6 -8
- package/node_modules/hono/dist/jsx/hooks/index.js +236 -308
- package/node_modules/hono/dist/jsx/index.js +45 -98
- package/node_modules/hono/dist/jsx/intrinsic-element/common.js +20 -22
- package/node_modules/hono/dist/jsx/intrinsic-element/components.js +113 -154
- package/node_modules/hono/dist/jsx/intrinsic-elements.js +1 -0
- package/node_modules/hono/dist/jsx/jsx-dev-runtime.js +12 -16
- package/node_modules/hono/dist/jsx/jsx-runtime.js +29 -42
- package/node_modules/hono/dist/jsx/streaming.js +120 -142
- package/node_modules/hono/dist/jsx/types.js +1 -0
- package/node_modules/hono/dist/jsx/utils.js +105 -168
- package/node_modules/hono/dist/middleware/basic-auth/index.js +96 -63
- package/node_modules/hono/dist/middleware/bearer-auth/index.js +93 -89
- package/node_modules/hono/dist/middleware/body-limit/index.js +66 -51
- package/node_modules/hono/dist/middleware/cache/index.js +165 -190
- package/node_modules/hono/dist/middleware/combine/index.js +134 -73
- package/node_modules/hono/dist/middleware/compress/index.js +75 -69
- package/node_modules/hono/dist/middleware/context-storage/index.js +49 -19
- package/node_modules/hono/dist/middleware/cors/index.js +107 -86
- package/node_modules/hono/dist/middleware/csrf/index.js +103 -53
- package/node_modules/hono/dist/middleware/etag/digest.js +59 -77
- package/node_modules/hono/dist/middleware/etag/index.js +71 -70
- package/node_modules/hono/dist/middleware/ip-restriction/index.js +163 -158
- package/node_modules/hono/dist/middleware/jsx-renderer/index.js +97 -54
- package/node_modules/hono/dist/middleware/jwk/index.js +1 -4
- package/node_modules/hono/dist/middleware/jwk/jwk.js +116 -112
- package/node_modules/hono/dist/middleware/jwt/index.js +2 -10
- package/node_modules/hono/dist/middleware/jwt/jwt.js +114 -114
- package/node_modules/hono/dist/middleware/language/index.js +2 -15
- package/node_modules/hono/dist/middleware/language/language.js +180 -157
- package/node_modules/hono/dist/middleware/logger/index.js +43 -37
- package/node_modules/hono/dist/middleware/method-not-allowed/index.js +81 -66
- package/node_modules/hono/dist/middleware/method-override/index.js +101 -81
- package/node_modules/hono/dist/middleware/powered-by/index.js +23 -9
- package/node_modules/hono/dist/middleware/pretty-json/index.js +39 -22
- package/node_modules/hono/dist/middleware/request-id/index.js +1 -4
- package/node_modules/hono/dist/middleware/request-id/request-id.js +33 -20
- package/node_modules/hono/dist/middleware/secure-headers/index.js +1 -5
- package/node_modules/hono/dist/middleware/secure-headers/permissions-policy.js +1 -0
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +144 -155
- package/node_modules/hono/dist/middleware/serve-static/index.js +56 -72
- package/node_modules/hono/dist/middleware/serve-static/path.js +15 -17
- package/node_modules/hono/dist/middleware/timeout/index.js +40 -23
- package/node_modules/hono/dist/middleware/timing/index.js +2 -9
- package/node_modules/hono/dist/middleware/timing/timing.js +177 -97
- package/node_modules/hono/dist/middleware/trailing-slash/index.js +85 -37
- package/node_modules/hono/dist/preset/quick.js +17 -15
- package/node_modules/hono/dist/preset/tiny.js +14 -11
- package/node_modules/hono/dist/request/constants.js +4 -5
- package/node_modules/hono/dist/request.js +328 -319
- package/node_modules/hono/dist/router/linear-router/index.js +1 -4
- package/node_modules/hono/dist/router/linear-router/router.js +93 -120
- package/node_modules/hono/dist/router/pattern-router/index.js +1 -4
- package/node_modules/hono/dist/router/pattern-router/router.js +39 -40
- package/node_modules/hono/dist/router/reg-exp-router/index.js +1 -7
- package/node_modules/hono/dist/router/reg-exp-router/matcher.js +17 -23
- package/node_modules/hono/dist/router/reg-exp-router/node.js +87 -110
- package/node_modules/hono/dist/router/reg-exp-router/prepared-router.js +89 -137
- package/node_modules/hono/dist/router/reg-exp-router/router.js +92 -129
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +69 -64
- package/node_modules/hono/dist/router/smart-router/index.js +1 -4
- package/node_modules/hono/dist/router/smart-router/router.js +46 -55
- package/node_modules/hono/dist/router/trie-router/index.js +1 -4
- package/node_modules/hono/dist/router/trie-router/node.js +131 -162
- package/node_modules/hono/dist/router/trie-router/router.js +11 -14
- package/node_modules/hono/dist/router/utils.js +4 -5
- package/node_modules/hono/dist/router.js +35 -14
- package/node_modules/hono/dist/types/adapter/aws-lambda/conninfo.d.ts +4 -1
- package/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +150 -104
- package/node_modules/hono/dist/types/adapter/aws-lambda/index.d.ts +4 -8
- package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +152 -122
- package/node_modules/hono/dist/types/adapter/bun/conninfo.d.ts +4 -1
- package/node_modules/hono/dist/types/adapter/bun/index.d.ts +6 -10
- package/node_modules/hono/dist/types/adapter/bun/serve-static.d.ts +7 -2
- package/node_modules/hono/dist/types/adapter/bun/server.d.ts +4 -5
- package/node_modules/hono/dist/types/adapter/bun/ssg.d.ts +5 -1
- package/node_modules/hono/dist/types/adapter/bun/websocket.d.ts +31 -16
- package/node_modules/hono/dist/types/adapter/cloudflare-pages/conninfo.d.ts +4 -1
- package/node_modules/hono/dist/types/adapter/cloudflare-pages/handler.d.ts +29 -17
- package/node_modules/hono/dist/types/adapter/cloudflare-pages/index.d.ts +3 -7
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/conninfo.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/index.d.ts +4 -7
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/serve-static-module.d.ts +5 -2
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/serve-static.d.ts +10 -5
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/utils.d.ts +10 -2
- package/node_modules/hono/dist/types/adapter/cloudflare-workers/websocket.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/deno/conninfo.d.ts +4 -1
- package/node_modules/hono/dist/types/adapter/deno/deno.d.ts +1 -0
- package/node_modules/hono/dist/types/adapter/deno/index.d.ts +5 -8
- package/node_modules/hono/dist/types/adapter/deno/serve-static.d.ts +7 -2
- package/node_modules/hono/dist/types/adapter/deno/ssg.d.ts +5 -1
- package/node_modules/hono/dist/types/adapter/deno/websocket.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/lambda-edge/conninfo.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/lambda-edge/handler.d.ts +83 -57
- package/node_modules/hono/dist/types/adapter/lambda-edge/index.d.ts +3 -7
- package/node_modules/hono/dist/types/adapter/netlify/conninfo.d.ts +4 -1
- package/node_modules/hono/dist/types/adapter/netlify/handler.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/netlify/index.d.ts +3 -5
- package/node_modules/hono/dist/types/adapter/netlify/mod.d.ts +3 -2
- package/node_modules/hono/dist/types/adapter/service-worker/handler.d.ts +9 -7
- package/node_modules/hono/dist/types/adapter/service-worker/index.d.ts +7 -9
- package/node_modules/hono/dist/types/adapter/service-worker/types.d.ts +12 -7
- package/node_modules/hono/dist/types/adapter/vercel/conninfo.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/vercel/handler.d.ts +6 -1
- package/node_modules/hono/dist/types/adapter/vercel/index.d.ts +3 -6
- package/node_modules/hono/dist/types/client/client.d.ts +5 -3
- package/node_modules/hono/dist/types/client/fetch-result-please.d.ts +21 -19
- package/node_modules/hono/dist/types/client/index.d.ts +5 -7
- package/node_modules/hono/dist/types/client/types.d.ts +134 -159
- package/node_modules/hono/dist/types/client/utils.d.ts +6 -4
- package/node_modules/hono/dist/types/compose.d.ts +4 -2
- package/node_modules/hono/dist/types/context.d.ts +335 -335
- package/node_modules/hono/dist/types/helper/accepts/accepts.d.ts +11 -9
- package/node_modules/hono/dist/types/helper/accepts/index.d.ts +2 -5
- package/node_modules/hono/dist/types/helper/adapter/index.d.ts +4 -6
- package/node_modules/hono/dist/types/helper/conninfo/index.d.ts +2 -5
- package/node_modules/hono/dist/types/helper/conninfo/types.d.ts +25 -23
- package/node_modules/hono/dist/types/helper/cookie/index.d.ts +10 -12
- package/node_modules/hono/dist/types/helper/css/common.d.ts +11 -9
- package/node_modules/hono/dist/types/helper/css/index.d.ts +26 -28
- package/node_modules/hono/dist/types/helper/dev/index.d.ts +10 -12
- package/node_modules/hono/dist/types/helper/factory/index.d.ts +26 -73
- package/node_modules/hono/dist/types/helper/html/index.d.ts +4 -7
- package/node_modules/hono/dist/types/helper/proxy/index.d.ts +19 -21
- package/node_modules/hono/dist/types/helper/route/index.d.ts +4 -2
- package/node_modules/hono/dist/types/helper/ssg/index.d.ts +4 -7
- package/node_modules/hono/dist/types/helper/ssg/middleware.d.ts +8 -6
- package/node_modules/hono/dist/types/helper/ssg/plugins.d.ts +3 -1
- package/node_modules/hono/dist/types/helper/ssg/ssg.d.ts +38 -36
- package/node_modules/hono/dist/types/helper/ssg/utils.d.ts +5 -3
- package/node_modules/hono/dist/types/helper/streaming/index.d.ts +4 -8
- package/node_modules/hono/dist/types/helper/streaming/sse.d.ts +10 -8
- package/node_modules/hono/dist/types/helper/streaming/stream.d.ts +4 -2
- package/node_modules/hono/dist/types/helper/streaming/text.d.ts +4 -2
- package/node_modules/hono/dist/types/helper/streaming/utils.d.ts +2 -0
- package/node_modules/hono/dist/types/helper/testing/index.d.ts +7 -9
- package/node_modules/hono/dist/types/helper/websocket/index.d.ts +30 -33
- package/node_modules/hono/dist/types/hono-base.d.ts +208 -210
- package/node_modules/hono/dist/types/hono.d.ts +11 -10
- package/node_modules/hono/dist/types/http-exception.d.ts +20 -22
- package/node_modules/hono/dist/types/index.d.ts +6 -37
- package/node_modules/hono/dist/types/jsx/base.d.ts +36 -34
- package/node_modules/hono/dist/types/jsx/children.d.ts +8 -6
- package/node_modules/hono/dist/types/jsx/components.d.ts +8 -5
- package/node_modules/hono/dist/types/jsx/constants.d.ts +2 -0
- package/node_modules/hono/dist/types/jsx/context.d.ts +9 -6
- package/node_modules/hono/dist/types/jsx/dom/client.d.ts +9 -10
- package/node_modules/hono/dist/types/jsx/dom/components.d.ts +9 -6
- package/node_modules/hono/dist/types/jsx/dom/context.d.ts +3 -1
- package/node_modules/hono/dist/types/jsx/dom/css.d.ts +27 -30
- package/node_modules/hono/dist/types/jsx/dom/hooks/index.d.ts +11 -12
- package/node_modules/hono/dist/types/jsx/dom/index.d.ts +79 -83
- package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +9 -5
- package/node_modules/hono/dist/types/jsx/dom/jsx-dev-runtime.d.ts +4 -6
- package/node_modules/hono/dist/types/jsx/dom/jsx-runtime.d.ts +3 -7
- package/node_modules/hono/dist/types/jsx/dom/render.d.ts +32 -50
- package/node_modules/hono/dist/types/jsx/dom/server.d.ts +87 -85
- package/node_modules/hono/dist/types/jsx/dom/utils.d.ts +2 -0
- package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +16 -16
- package/node_modules/hono/dist/types/jsx/index.d.ts +71 -73
- package/node_modules/hono/dist/types/jsx/intrinsic-element/common.d.ts +3 -1
- package/node_modules/hono/dist/types/jsx/intrinsic-element/components.d.ts +7 -4
- package/node_modules/hono/dist/types/jsx/intrinsic-elements.d.ts +708 -708
- package/node_modules/hono/dist/types/jsx/jsx-dev-runtime.d.ts +4 -7
- package/node_modules/hono/dist/types/jsx/jsx-runtime.d.ts +7 -10
- package/node_modules/hono/dist/types/jsx/streaming.d.ts +9 -10
- package/node_modules/hono/dist/types/jsx/types.d.ts +12 -13
- package/node_modules/hono/dist/types/jsx/utils.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/basic-auth/index.d.ts +17 -19
- package/node_modules/hono/dist/types/middleware/bearer-auth/index.d.ts +46 -48
- package/node_modules/hono/dist/types/middleware/body-limit/index.d.ts +6 -8
- package/node_modules/hono/dist/types/middleware/cache/index.d.ts +13 -15
- package/node_modules/hono/dist/types/middleware/combine/index.d.ts +4 -6
- package/node_modules/hono/dist/types/middleware/compress/index.d.ts +9 -10
- package/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +4 -6
- package/node_modules/hono/dist/types/middleware/cors/index.d.ts +10 -12
- package/node_modules/hono/dist/types/middleware/csrf/index.d.ts +6 -8
- package/node_modules/hono/dist/types/middleware/etag/digest.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/etag/index.d.ts +6 -8
- package/node_modules/hono/dist/types/middleware/ip-restriction/index.d.ts +11 -12
- package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +11 -11
- package/node_modules/hono/dist/types/middleware/jwk/index.d.ts +2 -1
- package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +20 -23
- package/node_modules/hono/dist/types/middleware/jwt/index.d.ts +7 -6
- package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +28 -30
- package/node_modules/hono/dist/types/middleware/language/index.d.ts +6 -5
- package/node_modules/hono/dist/types/middleware/language/language.d.ts +42 -44
- package/node_modules/hono/dist/types/middleware/logger/index.d.ts +3 -5
- package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +7 -9
- package/node_modules/hono/dist/types/middleware/method-override/index.d.ts +14 -16
- package/node_modules/hono/dist/types/middleware/powered-by/index.d.ts +8 -10
- package/node_modules/hono/dist/types/middleware/pretty-json/index.d.ts +18 -20
- package/node_modules/hono/dist/types/middleware/request-id/index.d.ts +6 -5
- package/node_modules/hono/dist/types/middleware/request-id/request-id.d.ts +9 -11
- package/node_modules/hono/dist/types/middleware/secure-headers/index.d.ts +6 -6
- package/node_modules/hono/dist/types/middleware/secure-headers/permissions-policy.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/secure-headers/secure-headers.d.ts +55 -57
- package/node_modules/hono/dist/types/middleware/serve-static/index.d.ts +24 -24
- package/node_modules/hono/dist/types/middleware/serve-static/path.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/timeout/index.d.ts +5 -7
- package/node_modules/hono/dist/types/middleware/timing/index.d.ts +6 -5
- package/node_modules/hono/dist/types/middleware/timing/timing.d.ts +17 -20
- package/node_modules/hono/dist/types/middleware/trailing-slash/index.d.ts +35 -37
- package/node_modules/hono/dist/types/preset/quick.d.ts +6 -9
- package/node_modules/hono/dist/types/preset/tiny.d.ts +6 -9
- package/node_modules/hono/dist/types/request/constants.d.ts +2 -0
- package/node_modules/hono/dist/types/request.d.ts +288 -286
- package/node_modules/hono/dist/types/router/linear-router/index.d.ts +2 -5
- package/node_modules/hono/dist/types/router/linear-router/router.d.ts +7 -5
- package/node_modules/hono/dist/types/router/pattern-router/index.d.ts +2 -5
- package/node_modules/hono/dist/types/router/pattern-router/router.d.ts +7 -5
- package/node_modules/hono/dist/types/router/reg-exp-router/index.d.ts +3 -6
- package/node_modules/hono/dist/types/router/reg-exp-router/matcher.d.ts +3 -1
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +6 -4
- package/node_modules/hono/dist/types/router/reg-exp-router/prepared-router.d.ts +11 -10
- package/node_modules/hono/dist/types/router/reg-exp-router/router.d.ts +10 -9
- package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +7 -5
- package/node_modules/hono/dist/types/router/smart-router/index.d.ts +2 -5
- package/node_modules/hono/dist/types/router/smart-router/router.d.ts +11 -9
- package/node_modules/hono/dist/types/router/trie-router/index.d.ts +2 -5
- package/node_modules/hono/dist/types/router/trie-router/node.d.ts +6 -4
- package/node_modules/hono/dist/types/router/trie-router/router.d.ts +7 -5
- package/node_modules/hono/dist/types/router/utils.d.ts +2 -0
- package/node_modules/hono/dist/types/router.d.ts +23 -22
- package/node_modules/hono/dist/types/types.d.ts +146 -505
- package/node_modules/hono/dist/types/utils/accept.d.ts +5 -3
- package/node_modules/hono/dist/types/utils/basic-auth.d.ts +4 -2
- package/node_modules/hono/dist/types/utils/body.d.ts +46 -50
- package/node_modules/hono/dist/types/utils/buffer.d.ts +7 -5
- package/node_modules/hono/dist/types/utils/color.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/compress.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/concurrent.d.ts +6 -4
- package/node_modules/hono/dist/types/utils/constants.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/cookie.d.ts +20 -18
- package/node_modules/hono/dist/types/utils/crypto.d.ts +5 -7
- package/node_modules/hono/dist/types/utils/encode.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/filepath.d.ts +5 -3
- package/node_modules/hono/dist/types/utils/handler.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/headers.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/html.d.ts +11 -9
- package/node_modules/hono/dist/types/utils/http-status.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/ipaddr.d.ts +4 -6
- package/node_modules/hono/dist/types/utils/jwt/index.d.ts +18 -12
- package/node_modules/hono/dist/types/utils/jwt/jwa.d.ts +15 -13
- package/node_modules/hono/dist/types/utils/jwt/jws.d.ts +4 -7
- package/node_modules/hono/dist/types/utils/jwt/jwt.d.ts +26 -29
- package/node_modules/hono/dist/types/utils/jwt/types.d.ts +48 -45
- package/node_modules/hono/dist/types/utils/jwt/utf8.d.ts +2 -0
- package/node_modules/hono/dist/types/utils/mime.d.ts +60 -57
- package/node_modules/hono/dist/types/utils/stream.d.ts +27 -25
- package/node_modules/hono/dist/types/utils/types.d.ts +14 -26
- package/node_modules/hono/dist/types/utils/url.d.ts +2 -0
- package/node_modules/hono/dist/types/validator/index.d.ts +3 -7
- package/node_modules/hono/dist/types/validator/utils.d.ts +6 -8
- package/node_modules/hono/dist/types/validator/validator.d.ts +11 -9
- package/node_modules/hono/dist/types.js +4 -6
- package/node_modules/hono/dist/utils/accept.js +185 -212
- package/node_modules/hono/dist/utils/basic-auth.js +18 -21
- package/node_modules/hono/dist/utils/body.js +87 -92
- package/node_modules/hono/dist/utils/buffer.js +44 -71
- package/node_modules/hono/dist/utils/color.js +33 -21
- package/node_modules/hono/dist/utils/compress.js +11 -5
- package/node_modules/hono/dist/utils/concurrent.js +29 -38
- package/node_modules/hono/dist/utils/constants.js +7 -5
- package/node_modules/hono/dist/utils/cookie.js +114 -163
- package/node_modules/hono/dist/utils/crypto.js +30 -40
- package/node_modules/hono/dist/utils/encode.js +30 -26
- package/node_modules/hono/dist/utils/filepath.js +23 -33
- package/node_modules/hono/dist/utils/handler.js +10 -11
- package/node_modules/hono/dist/utils/headers.js +1 -0
- package/node_modules/hono/dist/utils/html.js +97 -117
- package/node_modules/hono/dist/utils/http-status.js +1 -0
- package/node_modules/hono/dist/utils/ipaddr.js +227 -279
- package/node_modules/hono/dist/utils/jwt/index.js +12 -4
- package/node_modules/hono/dist/utils/jwt/jwa.js +24 -20
- package/node_modules/hono/dist/utils/jwt/jws.js +115 -174
- package/node_modules/hono/dist/utils/jwt/jwt.js +120 -198
- package/node_modules/hono/dist/utils/jwt/types.js +79 -95
- package/node_modules/hono/dist/utils/jwt/utf8.js +9 -7
- package/node_modules/hono/dist/utils/mime.js +74 -79
- package/node_modules/hono/dist/utils/stream.js +86 -88
- package/node_modules/hono/dist/utils/types.js +1 -0
- package/node_modules/hono/dist/utils/url.js +187 -215
- package/node_modules/hono/dist/validator/index.js +1 -4
- package/node_modules/hono/dist/validator/utils.js +1 -0
- package/node_modules/hono/dist/validator/validator.js +61 -83
- package/node_modules/hono/package.json +27 -27
- package/node_modules/undici/LICENSE +21 -0
- package/node_modules/undici/README.md +741 -0
- package/node_modules/undici/docs/docs/api/Agent.md +84 -0
- package/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
- package/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
- package/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
- package/node_modules/undici/docs/docs/api/Client.md +288 -0
- package/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
- package/node_modules/undici/docs/docs/api/Connector.md +115 -0
- package/node_modules/undici/docs/docs/api/ContentType.md +57 -0
- package/node_modules/undici/docs/docs/api/Cookies.md +128 -0
- package/node_modules/undici/docs/docs/api/Debug.md +62 -0
- package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +317 -0
- package/node_modules/undici/docs/docs/api/Dispatcher.md +1393 -0
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
- package/node_modules/undici/docs/docs/api/Errors.md +49 -0
- package/node_modules/undici/docs/docs/api/EventSource.md +45 -0
- package/node_modules/undici/docs/docs/api/Fetch.md +60 -0
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
- package/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
- package/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
- package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
- package/node_modules/undici/docs/docs/api/MockClient.md +81 -0
- package/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
- package/node_modules/undici/docs/docs/api/MockPool.md +555 -0
- package/node_modules/undici/docs/docs/api/Pool.md +84 -0
- package/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
- package/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
- package/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
- package/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +275 -0
- package/node_modules/undici/docs/docs/api/Util.md +25 -0
- package/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
- package/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
- package/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
- package/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
- package/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
- package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
- package/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
- package/node_modules/undici/index-fetch.js +65 -0
- package/node_modules/undici/index.d.ts +3 -0
- package/node_modules/undici/index.js +234 -0
- package/node_modules/undici/lib/api/abort-signal.js +59 -0
- package/node_modules/undici/lib/api/api-connect.js +110 -0
- package/node_modules/undici/lib/api/api-pipeline.js +252 -0
- package/node_modules/undici/lib/api/api-request.js +214 -0
- package/node_modules/undici/lib/api/api-stream.js +209 -0
- package/node_modules/undici/lib/api/api-upgrade.js +111 -0
- package/node_modules/undici/lib/api/index.js +7 -0
- package/node_modules/undici/lib/api/readable.js +580 -0
- package/node_modules/undici/lib/cache/memory-cache-store.js +279 -0
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +467 -0
- package/node_modules/undici/lib/core/connect.js +153 -0
- package/node_modules/undici/lib/core/constants.js +143 -0
- package/node_modules/undici/lib/core/diagnostics.js +227 -0
- package/node_modules/undici/lib/core/errors.js +477 -0
- package/node_modules/undici/lib/core/request.js +485 -0
- package/node_modules/undici/lib/core/socks5-client.js +422 -0
- package/node_modules/undici/lib/core/socks5-utils.js +212 -0
- package/node_modules/undici/lib/core/symbols.js +75 -0
- package/node_modules/undici/lib/core/tree.js +160 -0
- package/node_modules/undici/lib/core/util.js +992 -0
- package/node_modules/undici/lib/dispatcher/agent.js +158 -0
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +221 -0
- package/node_modules/undici/lib/dispatcher/client-h1.js +1746 -0
- package/node_modules/undici/lib/dispatcher/client-h2.js +1060 -0
- package/node_modules/undici/lib/dispatcher/client.js +668 -0
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +184 -0
- package/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
- package/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
- package/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
- package/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
- package/node_modules/undici/lib/dispatcher/pool.js +118 -0
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +319 -0
- package/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +260 -0
- package/node_modules/undici/lib/encoding/index.js +33 -0
- package/node_modules/undici/lib/global.js +59 -0
- package/node_modules/undici/lib/handler/cache-handler.js +776 -0
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
- package/node_modules/undici/lib/handler/decorator-handler.js +67 -0
- package/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
- package/node_modules/undici/lib/handler/redirect-handler.js +238 -0
- package/node_modules/undici/lib/handler/retry-handler.js +504 -0
- package/node_modules/undici/lib/handler/unwrap-handler.js +106 -0
- package/node_modules/undici/lib/handler/wrap-handler.js +105 -0
- package/node_modules/undici/lib/interceptor/cache.js +621 -0
- package/node_modules/undici/lib/interceptor/decompress.js +551 -0
- package/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
- package/node_modules/undici/lib/interceptor/dns.js +571 -0
- package/node_modules/undici/lib/interceptor/dump.js +99 -0
- package/node_modules/undici/lib/interceptor/redirect.js +21 -0
- package/node_modules/undici/lib/interceptor/response-error.js +95 -0
- package/node_modules/undici/lib/interceptor/retry.js +19 -0
- package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
- package/node_modules/undici/lib/llhttp/constants.js +531 -0
- package/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
- package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
- package/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
- package/node_modules/undici/lib/llhttp/utils.js +12 -0
- package/node_modules/undici/lib/mock/mock-agent.js +232 -0
- package/node_modules/undici/lib/mock/mock-call-history.js +248 -0
- package/node_modules/undici/lib/mock/mock-client.js +68 -0
- package/node_modules/undici/lib/mock/mock-errors.js +29 -0
- package/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
- package/node_modules/undici/lib/mock/mock-pool.js +68 -0
- package/node_modules/undici/lib/mock/mock-symbols.js +32 -0
- package/node_modules/undici/lib/mock/mock-utils.js +486 -0
- package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
- package/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
- package/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
- package/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
- package/node_modules/undici/lib/util/cache.js +676 -0
- package/node_modules/undici/lib/util/date.js +670 -0
- package/node_modules/undici/lib/util/promise.js +28 -0
- package/node_modules/undici/lib/util/runtime-features.js +124 -0
- package/node_modules/undici/lib/util/stats.js +32 -0
- package/node_modules/undici/lib/util/timers.js +425 -0
- package/node_modules/undici/lib/web/cache/cache.js +864 -0
- package/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
- package/node_modules/undici/lib/web/cache/util.js +45 -0
- package/node_modules/undici/lib/web/cookies/constants.js +12 -0
- package/node_modules/undici/lib/web/cookies/index.js +199 -0
- package/node_modules/undici/lib/web/cookies/parse.js +314 -0
- package/node_modules/undici/lib/web/cookies/util.js +352 -0
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +494 -0
- package/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
- package/node_modules/undici/lib/web/eventsource/util.js +29 -0
- package/node_modules/undici/lib/web/fetch/LICENSE +21 -0
- package/node_modules/undici/lib/web/fetch/body.js +509 -0
- package/node_modules/undici/lib/web/fetch/constants.js +131 -0
- package/node_modules/undici/lib/web/fetch/data-url.js +596 -0
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +586 -0
- package/node_modules/undici/lib/web/fetch/formdata.js +259 -0
- package/node_modules/undici/lib/web/fetch/global.js +40 -0
- package/node_modules/undici/lib/web/fetch/headers.js +719 -0
- package/node_modules/undici/lib/web/fetch/index.js +2413 -0
- package/node_modules/undici/lib/web/fetch/request.js +1115 -0
- package/node_modules/undici/lib/web/fetch/response.js +641 -0
- package/node_modules/undici/lib/web/fetch/util.js +1522 -0
- package/node_modules/undici/lib/web/infra/index.js +229 -0
- package/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
- package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
- package/node_modules/undici/lib/web/webidl/index.js +1006 -0
- package/node_modules/undici/lib/web/websocket/connection.js +339 -0
- package/node_modules/undici/lib/web/websocket/constants.js +126 -0
- package/node_modules/undici/lib/web/websocket/events.js +331 -0
- package/node_modules/undici/lib/web/websocket/frame.js +133 -0
- package/node_modules/undici/lib/web/websocket/permessage-deflate.js +105 -0
- package/node_modules/undici/lib/web/websocket/receiver.js +507 -0
- package/node_modules/undici/lib/web/websocket/sender.js +109 -0
- package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +496 -0
- package/node_modules/undici/lib/web/websocket/util.js +347 -0
- package/node_modules/undici/lib/web/websocket/websocket.js +758 -0
- package/node_modules/undici/package.json +152 -0
- package/node_modules/undici/scripts/strip-comments.js +10 -0
- package/node_modules/undici/types/README.md +6 -0
- package/node_modules/undici/types/agent.d.ts +32 -0
- package/node_modules/undici/types/api.d.ts +43 -0
- package/node_modules/undici/types/balanced-pool.d.ts +30 -0
- package/node_modules/undici/types/cache-interceptor.d.ts +179 -0
- package/node_modules/undici/types/cache.d.ts +36 -0
- package/node_modules/undici/types/client-stats.d.ts +15 -0
- package/node_modules/undici/types/client.d.ts +139 -0
- package/node_modules/undici/types/connector.d.ts +36 -0
- package/node_modules/undici/types/content-type.d.ts +21 -0
- package/node_modules/undici/types/cookies.d.ts +30 -0
- package/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
- package/node_modules/undici/types/dispatcher.d.ts +275 -0
- package/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
- package/node_modules/undici/types/errors.d.ts +177 -0
- package/node_modules/undici/types/eventsource.d.ts +66 -0
- package/node_modules/undici/types/fetch.d.ts +231 -0
- package/node_modules/undici/types/formdata.d.ts +114 -0
- package/node_modules/undici/types/global-dispatcher.d.ts +9 -0
- package/node_modules/undici/types/global-origin.d.ts +7 -0
- package/node_modules/undici/types/h2c-client.d.ts +73 -0
- package/node_modules/undici/types/handlers.d.ts +14 -0
- package/node_modules/undici/types/header.d.ts +160 -0
- package/node_modules/undici/types/index.d.ts +91 -0
- package/node_modules/undici/types/interceptors.d.ts +82 -0
- package/node_modules/undici/types/mock-agent.d.ts +68 -0
- package/node_modules/undici/types/mock-call-history.d.ts +111 -0
- package/node_modules/undici/types/mock-client.d.ts +27 -0
- package/node_modules/undici/types/mock-errors.d.ts +12 -0
- package/node_modules/undici/types/mock-interceptor.d.ts +94 -0
- package/node_modules/undici/types/mock-pool.d.ts +27 -0
- package/node_modules/undici/types/patch.d.ts +29 -0
- package/node_modules/undici/types/pool-stats.d.ts +19 -0
- package/node_modules/undici/types/pool.d.ts +41 -0
- package/node_modules/undici/types/proxy-agent.d.ts +29 -0
- package/node_modules/undici/types/readable.d.ts +68 -0
- package/node_modules/undici/types/retry-agent.d.ts +8 -0
- package/node_modules/undici/types/retry-handler.d.ts +125 -0
- package/node_modules/undici/types/round-robin-pool.d.ts +41 -0
- package/node_modules/undici/types/snapshot-agent.d.ts +109 -0
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
- package/node_modules/undici/types/util.d.ts +18 -0
- package/node_modules/undici/types/utility.d.ts +7 -0
- package/node_modules/undici/types/webidl.d.ts +347 -0
- package/node_modules/undici/types/websocket.d.ts +188 -0
- package/package.json +5 -3
- package/profiles/README.md +20 -0
- package/profiles/index.json +2 -1
- package/profiles/sales/0.1.profile.json +252 -0
- package/server.js +99 -0
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -112,6 +112,262 @@ function clientVersionHeaders() {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// src/lib/as-pairing.ts
|
|
116
|
+
import { createHash } from "crypto";
|
|
117
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
|
|
118
|
+
import { dirname, join as join2 } from "path";
|
|
119
|
+
function pairingPath(dataDir2) {
|
|
120
|
+
return join2(dataDir2, "as-pairing.json");
|
|
121
|
+
}
|
|
122
|
+
function readPairing(dataDir2) {
|
|
123
|
+
const path = pairingPath(dataDir2);
|
|
124
|
+
if (!existsSync2(path)) return null;
|
|
125
|
+
try {
|
|
126
|
+
const data = JSON.parse(readFileSync2(path, "utf-8"));
|
|
127
|
+
if (typeof data.asUrl !== "string" || typeof data.publicKeyHex !== "string") return null;
|
|
128
|
+
return {
|
|
129
|
+
asUrl: data.asUrl,
|
|
130
|
+
publicKeyHex: data.publicKeyHex,
|
|
131
|
+
pairedAt: data.pairedAt ?? "",
|
|
132
|
+
...typeof data.tlsSpkiPinHex === "string" ? { tlsSpkiPinHex: data.tlsSpkiPinHex } : {}
|
|
133
|
+
};
|
|
134
|
+
} catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function fingerprintOf(publicKeyHex) {
|
|
139
|
+
const raw = Buffer.from(publicKeyHex, "hex");
|
|
140
|
+
const digest = createHash("sha256").update(raw).digest("hex").toUpperCase();
|
|
141
|
+
return digest.match(/.{1,4}/g)?.join(":") ?? digest;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/lib/as-config.ts
|
|
145
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
146
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
147
|
+
var DEFAULT_AS_URL = "https://www.suveren.ai";
|
|
148
|
+
function configPath(dataDir2) {
|
|
149
|
+
return join3(dataDir2, "config.json");
|
|
150
|
+
}
|
|
151
|
+
function readAsConfigStrict(dataDir2) {
|
|
152
|
+
const path = configPath(dataDir2);
|
|
153
|
+
if (!existsSync3(path)) return {};
|
|
154
|
+
let data;
|
|
155
|
+
try {
|
|
156
|
+
data = JSON.parse(readFileSync3(path, "utf-8"));
|
|
157
|
+
} catch (err) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const out = {};
|
|
163
|
+
if (typeof data.asUrl === "string") out.asUrl = data.asUrl;
|
|
164
|
+
if (typeof data.caFile === "string") out.caFile = data.caFile;
|
|
165
|
+
if (typeof data.pinTls === "boolean") out.pinTls = data.pinTls;
|
|
166
|
+
if (typeof data.pinTlsExpectedFingerprint === "string") out.pinTlsExpectedFingerprint = data.pinTlsExpectedFingerprint;
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
function readAsConfig(dataDir2) {
|
|
170
|
+
const path = configPath(dataDir2);
|
|
171
|
+
if (!existsSync3(path)) return {};
|
|
172
|
+
try {
|
|
173
|
+
const data = JSON.parse(readFileSync3(path, "utf-8"));
|
|
174
|
+
const out = {};
|
|
175
|
+
if (typeof data.asUrl === "string") out.asUrl = data.asUrl;
|
|
176
|
+
if (typeof data.caFile === "string") out.caFile = data.caFile;
|
|
177
|
+
if (typeof data.pinTls === "boolean") out.pinTls = data.pinTls;
|
|
178
|
+
if (typeof data.pinTlsExpectedFingerprint === "string") out.pinTlsExpectedFingerprint = data.pinTlsExpectedFingerprint;
|
|
179
|
+
return out;
|
|
180
|
+
} catch {
|
|
181
|
+
return {};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function validateAsUrl(candidate) {
|
|
185
|
+
const trimmed = candidate.trim();
|
|
186
|
+
if (!trimmed) return { ok: false, error: "The Authority Server URL is empty." };
|
|
187
|
+
let parsed;
|
|
188
|
+
try {
|
|
189
|
+
parsed = new URL(trimmed);
|
|
190
|
+
} catch {
|
|
191
|
+
return { ok: false, error: `"${trimmed}" is not a valid URL.` };
|
|
192
|
+
}
|
|
193
|
+
const isLocalHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
194
|
+
if (parsed.protocol !== "https:" && !isLocalHttp) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
error: `"${trimmed}" must use https:// (http:// is only allowed for http://localhost or http://127.0.0.1).`
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
let normalized = `${parsed.origin}${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
201
|
+
if (normalized.endsWith("/") && normalized !== `${parsed.origin}/`) {
|
|
202
|
+
normalized = normalized.slice(0, -1);
|
|
203
|
+
} else if (normalized === `${parsed.origin}/`) {
|
|
204
|
+
normalized = parsed.origin;
|
|
205
|
+
}
|
|
206
|
+
return { ok: true, url: normalized };
|
|
207
|
+
}
|
|
208
|
+
function resolveAsUrl(dataDir2, flag) {
|
|
209
|
+
if (flag) {
|
|
210
|
+
const v = validateAsUrl(flag);
|
|
211
|
+
if (!v.ok) throw new Error(`Invalid --as-url: ${v.error}`);
|
|
212
|
+
return v.url;
|
|
213
|
+
}
|
|
214
|
+
const envUrl = process.env.SUVEREN_AS_URL;
|
|
215
|
+
if (envUrl) {
|
|
216
|
+
const v = validateAsUrl(envUrl);
|
|
217
|
+
if (!v.ok) throw new Error(`Invalid SUVEREN_AS_URL: ${v.error}`);
|
|
218
|
+
return v.url;
|
|
219
|
+
}
|
|
220
|
+
const saved = readAsConfigStrict(dataDir2).asUrl;
|
|
221
|
+
if (saved) {
|
|
222
|
+
const v = validateAsUrl(saved);
|
|
223
|
+
if (!v.ok) throw new Error(`Invalid saved as-url "${saved}" in ${dataDir2}/config.json: ${v.error}`);
|
|
224
|
+
return v.url;
|
|
225
|
+
}
|
|
226
|
+
return DEFAULT_AS_URL;
|
|
227
|
+
}
|
|
228
|
+
function resolvePinTls(dataDir2) {
|
|
229
|
+
return readAsConfig(dataDir2).pinTls === true;
|
|
230
|
+
}
|
|
231
|
+
function validatePinTlsForUrl(pinTls, asUrl) {
|
|
232
|
+
if (!pinTls) return;
|
|
233
|
+
if (!asUrl.startsWith("https:")) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`config.json sets "pinTls": true, but the Authority Server URL (${asUrl}) is not https:// \u2014 there is no TLS certificate to pin. Fix the saved as-url, or turn pin-tls off: \`suveren-gateway config set pin-tls off\`.`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/lib/as-tls-pin.ts
|
|
241
|
+
import { createHash as createHash2 } from "crypto";
|
|
242
|
+
import { checkServerIdentity as defaultCheckServerIdentity, rootCertificates } from "tls";
|
|
243
|
+
import { Agent as HttpsAgent } from "https";
|
|
244
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
245
|
+
import { Agent, fetch as undiciFetch } from "undici";
|
|
246
|
+
function effectiveCa() {
|
|
247
|
+
const path = process.env.NODE_EXTRA_CA_CERTS;
|
|
248
|
+
if (!path) return void 0;
|
|
249
|
+
try {
|
|
250
|
+
return [...rootCertificates, readFileSync4(path, "utf-8")];
|
|
251
|
+
} catch {
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
var PIN_CHECK_ERROR_CODE = "EAS_TLS_PIN_CHECK";
|
|
256
|
+
function taggedCheckError(err) {
|
|
257
|
+
err.code = PIN_CHECK_ERROR_CODE;
|
|
258
|
+
return err;
|
|
259
|
+
}
|
|
260
|
+
function isPinCheckError(err) {
|
|
261
|
+
let cur = err;
|
|
262
|
+
for (let i = 0; i < 5 && cur; i++) {
|
|
263
|
+
if (cur instanceof Error && cur.code === PIN_CHECK_ERROR_CODE) return true;
|
|
264
|
+
cur = cur instanceof Error ? cur.cause : void 0;
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
var AsTlsMismatchError = class extends Error {
|
|
269
|
+
constructor(message) {
|
|
270
|
+
super(message);
|
|
271
|
+
this.name = "AsTlsMismatchError";
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
function spkiSha256Hex(cert) {
|
|
275
|
+
if (!cert.pubkey) {
|
|
276
|
+
throw new Error("peer certificate carries no pubkey (expected the detailed certificate object)");
|
|
277
|
+
}
|
|
278
|
+
return createHash2("sha256").update(cert.pubkey).digest("hex");
|
|
279
|
+
}
|
|
280
|
+
function formatPinFingerprint(hex) {
|
|
281
|
+
const upper = hex.toUpperCase();
|
|
282
|
+
return upper.match(/.{1,4}/g)?.join(":") ?? upper;
|
|
283
|
+
}
|
|
284
|
+
function pinnedCheckServerIdentity(pinnedSpkiHex) {
|
|
285
|
+
const wantHex = pinnedSpkiHex.toLowerCase();
|
|
286
|
+
return (hostname, cert) => {
|
|
287
|
+
const defaultErr = defaultCheckServerIdentity(hostname, cert);
|
|
288
|
+
if (defaultErr) return taggedCheckError(defaultErr);
|
|
289
|
+
let actualHex;
|
|
290
|
+
try {
|
|
291
|
+
actualHex = spkiSha256Hex(cert);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
return taggedCheckError(new Error(
|
|
294
|
+
`could not read the server certificate's public key to check the TLS pin \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
295
|
+
));
|
|
296
|
+
}
|
|
297
|
+
if (actualHex !== wantHex) {
|
|
298
|
+
return taggedCheckError(new Error(
|
|
299
|
+
`TLS certificate pin mismatch for ${hostname}: expected SPKI sha256 ${formatPinFingerprint(wantHex)}, got ${formatPinFingerprint(actualHex)}.`
|
|
300
|
+
));
|
|
301
|
+
}
|
|
302
|
+
return void 0;
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function buildPinnedDispatcher(pinnedSpkiHex) {
|
|
306
|
+
return new Agent({
|
|
307
|
+
connect: {
|
|
308
|
+
ca: effectiveCa(),
|
|
309
|
+
checkServerIdentity: pinnedCheckServerIdentity(pinnedSpkiHex)
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function buildCapturingDispatcher() {
|
|
314
|
+
let captured;
|
|
315
|
+
const dispatcher = new Agent({
|
|
316
|
+
connect: {
|
|
317
|
+
ca: effectiveCa(),
|
|
318
|
+
checkServerIdentity: (hostname, cert) => {
|
|
319
|
+
captured = cert;
|
|
320
|
+
const defaultErr = defaultCheckServerIdentity(hostname, cert);
|
|
321
|
+
return defaultErr ? taggedCheckError(defaultErr) : void 0;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
return { dispatcher, getCapturedCert: () => captured };
|
|
326
|
+
}
|
|
327
|
+
async function fetchAs(url, init, pinning) {
|
|
328
|
+
if (!pinning.enforce && !pinning.capture) {
|
|
329
|
+
const res2 = await fetch(url, init);
|
|
330
|
+
return { res: res2 };
|
|
331
|
+
}
|
|
332
|
+
if (pinning.enforce && !pinning.capture && !pinning.pinnedSpkiHex) {
|
|
333
|
+
throw new AsTlsMismatchError(
|
|
334
|
+
`pin-tls is on but no certificate is pinned yet for ${url} \u2014 sign in again to establish it (re-pairing required).`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
if (pinning.pinnedSpkiHex && (pinning.enforce || !pinning.capture)) {
|
|
338
|
+
const dispatcher2 = buildPinnedDispatcher(pinning.pinnedSpkiHex);
|
|
339
|
+
try {
|
|
340
|
+
const res2 = await undiciFetch(url, { ...init, dispatcher: dispatcher2 });
|
|
341
|
+
return { res: res2 };
|
|
342
|
+
} catch (err) {
|
|
343
|
+
if (!isPinCheckError(err)) throw err;
|
|
344
|
+
throw new AsTlsMismatchError(
|
|
345
|
+
`TLS pin check failed for ${url} \u2014 ${describeFetchError(err)}. Refusing the connection; the API key / session cookie were never sent. If the Authority Server's certificate changed intentionally (a new key, not just renewal), an operator must clear the pairing and sign in again to re-pin it.`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const { dispatcher, getCapturedCert } = buildCapturingDispatcher();
|
|
350
|
+
let res;
|
|
351
|
+
try {
|
|
352
|
+
res = await undiciFetch(url, { ...init, dispatcher });
|
|
353
|
+
} catch (err) {
|
|
354
|
+
if (!isPinCheckError(err)) throw err;
|
|
355
|
+
throw new AsTlsMismatchError(
|
|
356
|
+
`could not verify the Authority Server at ${url} while establishing its TLS pin \u2014 ${describeFetchError(err)}.`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
const cert = getCapturedCert();
|
|
360
|
+
return { res, capturedSpkiHex: cert ? spkiSha256Hex(cert) : void 0 };
|
|
361
|
+
}
|
|
362
|
+
function describeFetchError(err) {
|
|
363
|
+
if (err instanceof Error) {
|
|
364
|
+
const cause = err.cause;
|
|
365
|
+
if (cause instanceof Error) return cause.message;
|
|
366
|
+
return err.message;
|
|
367
|
+
}
|
|
368
|
+
return String(err);
|
|
369
|
+
}
|
|
370
|
+
|
|
115
371
|
// src/lib/sp-client.ts
|
|
116
372
|
var SPReceiptError = class extends Error {
|
|
117
373
|
constructor(message, statusCode, body) {
|
|
@@ -127,8 +383,9 @@ var DEFAULT_RECEIPT_RETRY = {
|
|
|
127
383
|
};
|
|
128
384
|
var sleep = (ms) => ms > 0 ? new Promise((resolve3) => setTimeout(resolve3, ms)) : Promise.resolve();
|
|
129
385
|
var SPClient = class {
|
|
130
|
-
constructor(baseUrl, receiptRetry = {}) {
|
|
386
|
+
constructor(baseUrl, receiptRetry = {}, dataDir2) {
|
|
131
387
|
this.baseUrl = baseUrl;
|
|
388
|
+
this.dataDir = dataDir2;
|
|
132
389
|
this.receiptRetry = { ...DEFAULT_RECEIPT_RETRY, ...receiptRetry };
|
|
133
390
|
}
|
|
134
391
|
sessionCookie = "";
|
|
@@ -141,6 +398,22 @@ var SPClient = class {
|
|
|
141
398
|
* was active tells the control plane. Concurrent in-flight calls that were
|
|
142
399
|
* all sent under the same now-dead cookie would otherwise all report it. */
|
|
143
400
|
sessionExpiredNotified = false;
|
|
401
|
+
/** Same single-flight shape, for a TLS pin mismatch (as-tls-pin.ts). */
|
|
402
|
+
tlsMismatchNotified = false;
|
|
403
|
+
/** Opt-in TLS pinning (as-tls-pin.ts) for every call THIS client makes.
|
|
404
|
+
* Re-read live on each call rather than cached — same reasoning as
|
|
405
|
+
* AttestationCache.getPublicKey's pin check: a pin or setting change
|
|
406
|
+
* must take effect on the very next call, not the next restart. Never
|
|
407
|
+
* allowed to CAPTURE a new pin here — only the control plane's sign-in
|
|
408
|
+
* exchange (as-challenge.ts) does that; this client only enforces. */
|
|
409
|
+
tlsPinning() {
|
|
410
|
+
if (!this.dataDir) return { enforce: false };
|
|
411
|
+
const pin = readPairing(this.dataDir);
|
|
412
|
+
return {
|
|
413
|
+
enforce: resolvePinTls(this.dataDir),
|
|
414
|
+
pinnedSpkiHex: pin && pin.asUrl === this.baseUrl ? pin.tlsSpkiPinHex : void 0
|
|
415
|
+
};
|
|
416
|
+
}
|
|
144
417
|
/** The AS base URL this client talks to (for provenance records). */
|
|
145
418
|
get url() {
|
|
146
419
|
return this.baseUrl;
|
|
@@ -152,15 +425,23 @@ var SPClient = class {
|
|
|
152
425
|
this.sessionCookie = cookie;
|
|
153
426
|
this.lockReason = null;
|
|
154
427
|
this.sessionExpiredNotified = false;
|
|
428
|
+
this.tlsMismatchNotified = false;
|
|
155
429
|
}
|
|
156
430
|
/**
|
|
157
431
|
* Drop the session because the control plane learned (by whatever path —
|
|
158
|
-
* one of OUR calls 401ing,
|
|
159
|
-
* Idempotent: safe to call redundantly from the
|
|
432
|
+
* one of OUR calls 401ing, its own AS proxy 401ing, or an AS key mismatch)
|
|
433
|
+
* that it ended. Idempotent: safe to call redundantly from the
|
|
434
|
+
* control-plane's push.
|
|
435
|
+
*
|
|
436
|
+
* @param reason Defaults to 'expired' for the original caller (a 401 really
|
|
437
|
+
* does mean the session ended) — but the control plane's own lock
|
|
438
|
+
* procedures (session-lock.ts) know the REAL reason and must pass it, or
|
|
439
|
+
* an agent told "your sign-in ended, sign in again" for an AS key
|
|
440
|
+
* mismatch would be sent to a sign-in that is itself refused.
|
|
160
441
|
*/
|
|
161
|
-
clearSession() {
|
|
442
|
+
clearSession(reason = "expired") {
|
|
162
443
|
this.sessionCookie = "";
|
|
163
|
-
this.lockReason =
|
|
444
|
+
this.lockReason = reason;
|
|
164
445
|
}
|
|
165
446
|
/** Why we are currently locked, if known. `null` means the default
|
|
166
447
|
* boot-locked case (nobody has signed in yet this run). */
|
|
@@ -198,10 +479,21 @@ var SPClient = class {
|
|
|
198
479
|
headers["X-API-Key"] = this.apiKey;
|
|
199
480
|
}
|
|
200
481
|
const hadSession = this.sessionCookie !== "";
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
headers
|
|
204
|
-
|
|
482
|
+
let res;
|
|
483
|
+
try {
|
|
484
|
+
const result = await fetchAs(url, { ...init, headers }, this.tlsPinning());
|
|
485
|
+
res = result.res;
|
|
486
|
+
} catch (err) {
|
|
487
|
+
if (err instanceof AsTlsMismatchError) {
|
|
488
|
+
this.sessionCookie = "";
|
|
489
|
+
this.lockReason = "as-tls-mismatch";
|
|
490
|
+
if (!this.tlsMismatchNotified) {
|
|
491
|
+
this.tlsMismatchNotified = true;
|
|
492
|
+
void notifyControlPlane("as-tls-mismatch");
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
throw err;
|
|
496
|
+
}
|
|
205
497
|
if (res.status === 401 && hadSession) {
|
|
206
498
|
this.sessionCookie = "";
|
|
207
499
|
this.lockReason = "expired";
|
|
@@ -364,13 +656,26 @@ var SPClient = class {
|
|
|
364
656
|
|
|
365
657
|
// src/lib/attestation-cache.ts
|
|
366
658
|
import { decodeAttestationBlob } from "@hap/core";
|
|
659
|
+
var AsKeyMismatchError = class extends Error {
|
|
660
|
+
constructor(message) {
|
|
661
|
+
super(message);
|
|
662
|
+
this.name = "AsKeyMismatchError";
|
|
663
|
+
}
|
|
664
|
+
};
|
|
367
665
|
function isCommitmentDowngrade(auth) {
|
|
368
666
|
const requiresReview = auth.signedCommitmentMode === "review" || auth.signedCommitmentMode === "review_above_cap";
|
|
369
667
|
return requiresReview && (auth.deferredCommitmentDomains ?? []).length === 0;
|
|
370
668
|
}
|
|
371
669
|
var AttestationCache = class {
|
|
372
|
-
|
|
670
|
+
/**
|
|
671
|
+
* @param dataDir Where to look for a pinned key (as-pairing.json). Optional
|
|
672
|
+
* and defaults to "no pin enforced" — kept optional so existing
|
|
673
|
+
* constructions (and this class's own unit tests) that pass only an
|
|
674
|
+
* SPClient keep working unpinned, exactly as before pinning existed.
|
|
675
|
+
*/
|
|
676
|
+
constructor(spClient, dataDir2) {
|
|
373
677
|
this.spClient = spClient;
|
|
678
|
+
this.dataDir = dataDir2;
|
|
374
679
|
}
|
|
375
680
|
spPublicKey = null;
|
|
376
681
|
spPublicKeyFetchedAt = 0;
|
|
@@ -380,15 +685,29 @@ var AttestationCache = class {
|
|
|
380
685
|
authorizations = /* @__PURE__ */ new Map();
|
|
381
686
|
lastSync = 0;
|
|
382
687
|
/**
|
|
383
|
-
* Get the SP public key, fetching from SP if not cached or expired
|
|
688
|
+
* Get the SP public key, fetching from SP if not cached or expired, then —
|
|
689
|
+
* when a pin exists for this exact AS URL — verifying the live key still
|
|
690
|
+
* matches it.
|
|
691
|
+
*
|
|
692
|
+
* Trust-on-first-use before any pairing exists (or when no `dataDir` was
|
|
693
|
+
* given): the fetched key is cached and returned, same as before pinning.
|
|
694
|
+
* Once paired, a live key that differs from the pin throws
|
|
695
|
+
* {@link AsKeyMismatchError} — fail closed, never silently re-pin.
|
|
384
696
|
*/
|
|
385
697
|
async getPublicKey() {
|
|
386
698
|
const now = Math.floor(Date.now() / 1e3);
|
|
387
|
-
if (this.spPublicKey && now - this.spPublicKeyFetchedAt < this.SP_PUBKEY_TTL) {
|
|
388
|
-
|
|
699
|
+
if (!(this.spPublicKey && now - this.spPublicKeyFetchedAt < this.SP_PUBKEY_TTL)) {
|
|
700
|
+
this.spPublicKey = await this.spClient.getPublicKey();
|
|
701
|
+
this.spPublicKeyFetchedAt = now;
|
|
702
|
+
}
|
|
703
|
+
if (this.dataDir) {
|
|
704
|
+
const pin = readPairing(this.dataDir);
|
|
705
|
+
if (pin && pin.asUrl === this.spClient.url && pin.publicKeyHex !== this.spPublicKey) {
|
|
706
|
+
throw new AsKeyMismatchError(
|
|
707
|
+
`The Authority Server at ${this.spClient.url} presented a signing key that does not match the one pinned at pairing (pinned fingerprint ${fingerprintOf(pin.publicKeyHex)}). Refusing to trust it. Re-pair (sign in again) only if you expect this key to have changed.`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
389
710
|
}
|
|
390
|
-
this.spPublicKey = await this.spClient.getPublicKey();
|
|
391
|
-
this.spPublicKeyFetchedAt = now;
|
|
392
711
|
return this.spPublicKey;
|
|
393
712
|
}
|
|
394
713
|
/**
|
|
@@ -498,18 +817,18 @@ var AttestationCache = class {
|
|
|
498
817
|
};
|
|
499
818
|
|
|
500
819
|
// src/lib/gate-store.ts
|
|
501
|
-
import { mkdirSync, readFileSync as
|
|
820
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
502
821
|
import { homedir } from "os";
|
|
503
|
-
import { dirname, join as
|
|
822
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
504
823
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
505
|
-
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
824
|
+
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ?? join4(homedir(), ".suveren");
|
|
506
825
|
var GateStore = class {
|
|
507
826
|
entries = /* @__PURE__ */ new Map();
|
|
508
827
|
baseDir;
|
|
509
828
|
vaultKey = null;
|
|
510
829
|
constructor(filePath) {
|
|
511
830
|
if (filePath && filePath.endsWith(".json")) {
|
|
512
|
-
this.baseDir =
|
|
831
|
+
this.baseDir = dirname3(filePath);
|
|
513
832
|
} else {
|
|
514
833
|
this.baseDir = filePath ?? DEFAULT_DIR;
|
|
515
834
|
}
|
|
@@ -520,13 +839,13 @@ var GateStore = class {
|
|
|
520
839
|
*/
|
|
521
840
|
setVaultKey(key) {
|
|
522
841
|
this.vaultKey = key;
|
|
523
|
-
if (
|
|
842
|
+
if (existsSync4(this.encryptedFilePath)) {
|
|
524
843
|
this.loadEncrypted();
|
|
525
844
|
} else if (this.entries.size > 0) {
|
|
526
845
|
this.persistEncrypted();
|
|
527
|
-
if (
|
|
846
|
+
if (existsSync4(this.plaintextFilePath)) {
|
|
528
847
|
try {
|
|
529
|
-
|
|
848
|
+
unlinkSync2(this.plaintextFilePath);
|
|
530
849
|
} catch {
|
|
531
850
|
}
|
|
532
851
|
}
|
|
@@ -546,6 +865,30 @@ var GateStore = class {
|
|
|
546
865
|
this.entries.delete(path);
|
|
547
866
|
this.persist();
|
|
548
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* Wipe every locally cached gate. Used when the Authority Server this
|
|
870
|
+
* gateway points at changes (re-pairing, see as-pairing.ts): a stored
|
|
871
|
+
* authorization id and its intent/context are meaningless against a
|
|
872
|
+
* different AS's grants, and keeping them around risks a `getAll()` caller
|
|
873
|
+
* (e.g. list-authorizations) advertising authority that no longer exists.
|
|
874
|
+
*
|
|
875
|
+
* Removes BOTH the plaintext and encrypted files, not just the one
|
|
876
|
+
* currently active — this runs at boot, before any vault key is set, so
|
|
877
|
+
* `persist()` would otherwise only touch `gates.json` and leave a stale
|
|
878
|
+
* `gates.enc.json` in place for `setVaultKey()` to resurrect on the next
|
|
879
|
+
* unlock.
|
|
880
|
+
*/
|
|
881
|
+
clearAll() {
|
|
882
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
883
|
+
try {
|
|
884
|
+
if (existsSync4(this.plaintextFilePath)) unlinkSync2(this.plaintextFilePath);
|
|
885
|
+
} catch {
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
if (existsSync4(this.encryptedFilePath)) unlinkSync2(this.encryptedFilePath);
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
}
|
|
549
892
|
// ─── Encryption helpers ─────────────────────────────────────────────────
|
|
550
893
|
encrypt(plaintext) {
|
|
551
894
|
if (!this.vaultKey) throw new Error("No vault key");
|
|
@@ -575,19 +918,19 @@ var GateStore = class {
|
|
|
575
918
|
}
|
|
576
919
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
577
920
|
get plaintextFilePath() {
|
|
578
|
-
return
|
|
921
|
+
return join4(this.baseDir, "gates.json");
|
|
579
922
|
}
|
|
580
923
|
get encryptedFilePath() {
|
|
581
|
-
return
|
|
924
|
+
return join4(this.baseDir, "gates.enc.json");
|
|
582
925
|
}
|
|
583
926
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
584
927
|
loadPlaintext() {
|
|
585
|
-
if (!
|
|
586
|
-
|
|
928
|
+
if (!existsSync4(this.plaintextFilePath)) {
|
|
929
|
+
mkdirSync3(this.baseDir, { recursive: true });
|
|
587
930
|
return;
|
|
588
931
|
}
|
|
589
932
|
try {
|
|
590
|
-
const raw =
|
|
933
|
+
const raw = readFileSync5(this.plaintextFilePath, "utf-8");
|
|
591
934
|
const data = JSON.parse(raw);
|
|
592
935
|
this.entries = new Map(Object.entries(data.entries));
|
|
593
936
|
} catch {
|
|
@@ -596,9 +939,9 @@ var GateStore = class {
|
|
|
596
939
|
}
|
|
597
940
|
}
|
|
598
941
|
loadEncrypted() {
|
|
599
|
-
if (!
|
|
942
|
+
if (!existsSync4(this.encryptedFilePath)) return;
|
|
600
943
|
try {
|
|
601
|
-
const raw =
|
|
944
|
+
const raw = readFileSync5(this.encryptedFilePath, "utf-8");
|
|
602
945
|
const data = JSON.parse(raw);
|
|
603
946
|
this.entries = /* @__PURE__ */ new Map();
|
|
604
947
|
for (const [key, blob] of Object.entries(data.entries)) {
|
|
@@ -622,8 +965,8 @@ var GateStore = class {
|
|
|
622
965
|
version: 1,
|
|
623
966
|
entries: Object.fromEntries(this.entries)
|
|
624
967
|
};
|
|
625
|
-
|
|
626
|
-
|
|
968
|
+
mkdirSync3(this.baseDir, { recursive: true, mode: 448 });
|
|
969
|
+
writeFileSync3(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
627
970
|
}
|
|
628
971
|
persistEncrypted() {
|
|
629
972
|
const data = {
|
|
@@ -633,17 +976,17 @@ var GateStore = class {
|
|
|
633
976
|
for (const [key, entry] of this.entries) {
|
|
634
977
|
data.entries[key] = this.encrypt(JSON.stringify(entry));
|
|
635
978
|
}
|
|
636
|
-
|
|
637
|
-
|
|
979
|
+
mkdirSync3(this.baseDir, { recursive: true, mode: 448 });
|
|
980
|
+
writeFileSync3(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
638
981
|
}
|
|
639
982
|
};
|
|
640
983
|
|
|
641
984
|
// src/lib/execution-log.ts
|
|
642
|
-
import { mkdirSync as
|
|
985
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
643
986
|
import { homedir as homedir2 } from "os";
|
|
644
|
-
import { dirname as
|
|
987
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
645
988
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
646
|
-
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
989
|
+
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ?? join5(homedir2(), ".suveren");
|
|
647
990
|
var MAX_AGE_SECONDS = 31 * 24 * 60 * 60;
|
|
648
991
|
var ExecutionLog = class {
|
|
649
992
|
entries = [];
|
|
@@ -651,7 +994,7 @@ var ExecutionLog = class {
|
|
|
651
994
|
vaultKey = null;
|
|
652
995
|
constructor(filePath) {
|
|
653
996
|
if (filePath && filePath.endsWith(".json")) {
|
|
654
|
-
this.baseDir =
|
|
997
|
+
this.baseDir = dirname4(filePath);
|
|
655
998
|
} else {
|
|
656
999
|
this.baseDir = filePath ?? DEFAULT_DIR2;
|
|
657
1000
|
}
|
|
@@ -662,13 +1005,13 @@ var ExecutionLog = class {
|
|
|
662
1005
|
*/
|
|
663
1006
|
setVaultKey(key) {
|
|
664
1007
|
this.vaultKey = key;
|
|
665
|
-
if (
|
|
1008
|
+
if (existsSync5(this.encryptedFilePath)) {
|
|
666
1009
|
this.loadEncrypted();
|
|
667
1010
|
} else if (this.entries.length > 0) {
|
|
668
1011
|
this.persistEncrypted();
|
|
669
|
-
if (
|
|
1012
|
+
if (existsSync5(this.plaintextFilePath)) {
|
|
670
1013
|
try {
|
|
671
|
-
|
|
1014
|
+
unlinkSync3(this.plaintextFilePath);
|
|
672
1015
|
} catch {
|
|
673
1016
|
}
|
|
674
1017
|
}
|
|
@@ -690,14 +1033,23 @@ var ExecutionLog = class {
|
|
|
690
1033
|
* @param field - The execution field to sum ("_count" for plain counting)
|
|
691
1034
|
* @param window - Time window (daily, weekly, monthly)
|
|
692
1035
|
* @param now - Current timestamp in seconds (for testing)
|
|
1036
|
+
* @param actionTypes - Only count entries whose `execution.action_type` is one
|
|
1037
|
+
* of these (omitted → all). Consumption is partitioned by action type, as at
|
|
1038
|
+
* the Authority Server: without it, the usage shown for sales' "orders per
|
|
1039
|
+
* day" counted every quote and send. An entry with no action_type counts against every filter —
|
|
1040
|
+
* an unknown action is not evidence of headroom.
|
|
693
1041
|
*/
|
|
694
|
-
sumByWindow(profileId, path, field, window, now = Math.floor(Date.now() / 1e3)) {
|
|
1042
|
+
sumByWindow(profileId, path, field, window, now = Math.floor(Date.now() / 1e3), actionTypes) {
|
|
695
1043
|
const cutoff = windowCutoff(window, now);
|
|
696
1044
|
let total = 0;
|
|
697
1045
|
for (const entry of this.entries) {
|
|
698
1046
|
if (entry.profileId !== profileId) continue;
|
|
699
1047
|
if (entry.path !== path) continue;
|
|
700
1048
|
if (entry.timestamp < cutoff) continue;
|
|
1049
|
+
if (actionTypes) {
|
|
1050
|
+
const at = entry.execution.action_type;
|
|
1051
|
+
if (typeof at === "string" && !actionTypes.includes(at)) continue;
|
|
1052
|
+
}
|
|
701
1053
|
if (field === "_count") {
|
|
702
1054
|
total += 1;
|
|
703
1055
|
} else {
|
|
@@ -761,19 +1113,19 @@ var ExecutionLog = class {
|
|
|
761
1113
|
}
|
|
762
1114
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
763
1115
|
get plaintextFilePath() {
|
|
764
|
-
return
|
|
1116
|
+
return join5(this.baseDir, "execution-log.json");
|
|
765
1117
|
}
|
|
766
1118
|
get encryptedFilePath() {
|
|
767
|
-
return
|
|
1119
|
+
return join5(this.baseDir, "execution-log.enc.json");
|
|
768
1120
|
}
|
|
769
1121
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
770
1122
|
loadPlaintext() {
|
|
771
|
-
if (!
|
|
772
|
-
|
|
1123
|
+
if (!existsSync5(this.plaintextFilePath)) {
|
|
1124
|
+
mkdirSync4(this.baseDir, { recursive: true });
|
|
773
1125
|
return;
|
|
774
1126
|
}
|
|
775
1127
|
try {
|
|
776
|
-
const raw =
|
|
1128
|
+
const raw = readFileSync6(this.plaintextFilePath, "utf-8");
|
|
777
1129
|
const data = JSON.parse(raw);
|
|
778
1130
|
this.entries = data.entries;
|
|
779
1131
|
this.prune();
|
|
@@ -783,9 +1135,9 @@ var ExecutionLog = class {
|
|
|
783
1135
|
}
|
|
784
1136
|
}
|
|
785
1137
|
loadEncrypted() {
|
|
786
|
-
if (!
|
|
1138
|
+
if (!existsSync5(this.encryptedFilePath)) return;
|
|
787
1139
|
try {
|
|
788
|
-
const raw =
|
|
1140
|
+
const raw = readFileSync6(this.encryptedFilePath, "utf-8");
|
|
789
1141
|
const data = JSON.parse(raw);
|
|
790
1142
|
const decrypted = this.decrypt(data.blob);
|
|
791
1143
|
const logFile = JSON.parse(decrypted);
|
|
@@ -805,8 +1157,8 @@ var ExecutionLog = class {
|
|
|
805
1157
|
}
|
|
806
1158
|
persistPlaintext() {
|
|
807
1159
|
const data = { version: 1, entries: this.entries };
|
|
808
|
-
|
|
809
|
-
|
|
1160
|
+
mkdirSync4(this.baseDir, { recursive: true, mode: 448 });
|
|
1161
|
+
writeFileSync4(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
810
1162
|
}
|
|
811
1163
|
persistEncrypted() {
|
|
812
1164
|
const logFile = { version: 1, entries: this.entries };
|
|
@@ -814,8 +1166,8 @@ var ExecutionLog = class {
|
|
|
814
1166
|
version: 1,
|
|
815
1167
|
blob: this.encrypt(JSON.stringify(logFile))
|
|
816
1168
|
};
|
|
817
|
-
|
|
818
|
-
|
|
1169
|
+
mkdirSync4(this.baseDir, { recursive: true, mode: 448 });
|
|
1170
|
+
writeFileSync4(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
819
1171
|
}
|
|
820
1172
|
};
|
|
821
1173
|
function windowCutoff(window, now) {
|
|
@@ -832,11 +1184,11 @@ function windowCutoff(window, now) {
|
|
|
832
1184
|
}
|
|
833
1185
|
|
|
834
1186
|
// src/lib/denial-log.ts
|
|
835
|
-
import { mkdirSync as
|
|
1187
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync6, unlinkSync as unlinkSync4 } from "fs";
|
|
836
1188
|
import { homedir as homedir3 } from "os";
|
|
837
|
-
import { dirname as
|
|
1189
|
+
import { dirname as dirname5, join as join6 } from "path";
|
|
838
1190
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes3 } from "crypto";
|
|
839
|
-
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ??
|
|
1191
|
+
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ?? join6(homedir3(), ".suveren");
|
|
840
1192
|
var MAX_RECORDS = 200;
|
|
841
1193
|
var MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
842
1194
|
var DenialLog = class {
|
|
@@ -844,18 +1196,18 @@ var DenialLog = class {
|
|
|
844
1196
|
baseDir;
|
|
845
1197
|
vaultKey = null;
|
|
846
1198
|
constructor(filePath) {
|
|
847
|
-
this.baseDir = filePath && filePath.endsWith(".json") ?
|
|
1199
|
+
this.baseDir = filePath && filePath.endsWith(".json") ? dirname5(filePath) : filePath ?? DEFAULT_DIR3;
|
|
848
1200
|
this.loadPlaintext();
|
|
849
1201
|
}
|
|
850
1202
|
setVaultKey(key) {
|
|
851
1203
|
this.vaultKey = key;
|
|
852
|
-
if (
|
|
1204
|
+
if (existsSync6(this.encryptedFilePath)) {
|
|
853
1205
|
this.loadEncrypted();
|
|
854
1206
|
} else if (this.records.length > 0) {
|
|
855
1207
|
this.persistEncrypted();
|
|
856
|
-
if (
|
|
1208
|
+
if (existsSync6(this.plaintextFilePath)) {
|
|
857
1209
|
try {
|
|
858
|
-
|
|
1210
|
+
unlinkSync4(this.plaintextFilePath);
|
|
859
1211
|
} catch {
|
|
860
1212
|
}
|
|
861
1213
|
}
|
|
@@ -903,18 +1255,18 @@ var DenialLog = class {
|
|
|
903
1255
|
return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, "hex")), decipher.final()]).toString("utf8");
|
|
904
1256
|
}
|
|
905
1257
|
get plaintextFilePath() {
|
|
906
|
-
return
|
|
1258
|
+
return join6(this.baseDir, "denials.json");
|
|
907
1259
|
}
|
|
908
1260
|
get encryptedFilePath() {
|
|
909
|
-
return
|
|
1261
|
+
return join6(this.baseDir, "denials.enc.json");
|
|
910
1262
|
}
|
|
911
1263
|
loadPlaintext() {
|
|
912
|
-
if (!
|
|
913
|
-
|
|
1264
|
+
if (!existsSync6(this.plaintextFilePath)) {
|
|
1265
|
+
mkdirSync5(this.baseDir, { recursive: true });
|
|
914
1266
|
return;
|
|
915
1267
|
}
|
|
916
1268
|
try {
|
|
917
|
-
const data = JSON.parse(
|
|
1269
|
+
const data = JSON.parse(readFileSync7(this.plaintextFilePath, "utf-8"));
|
|
918
1270
|
this.records = data.records ?? [];
|
|
919
1271
|
} catch {
|
|
920
1272
|
console.error(`[DenialLog] Could not parse ${this.plaintextFilePath}, starting fresh`);
|
|
@@ -922,9 +1274,9 @@ var DenialLog = class {
|
|
|
922
1274
|
}
|
|
923
1275
|
}
|
|
924
1276
|
loadEncrypted() {
|
|
925
|
-
if (!
|
|
1277
|
+
if (!existsSync6(this.encryptedFilePath)) return;
|
|
926
1278
|
try {
|
|
927
|
-
const data = JSON.parse(
|
|
1279
|
+
const data = JSON.parse(readFileSync7(this.encryptedFilePath, "utf-8"));
|
|
928
1280
|
const logFile = JSON.parse(this.decrypt(data.blob));
|
|
929
1281
|
this.records = logFile.records ?? [];
|
|
930
1282
|
} catch (err) {
|
|
@@ -938,23 +1290,23 @@ var DenialLog = class {
|
|
|
938
1290
|
}
|
|
939
1291
|
persistPlaintext() {
|
|
940
1292
|
const data = { version: 1, records: this.records };
|
|
941
|
-
|
|
942
|
-
|
|
1293
|
+
mkdirSync5(this.baseDir, { recursive: true, mode: 448 });
|
|
1294
|
+
writeFileSync5(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
943
1295
|
}
|
|
944
1296
|
persistEncrypted() {
|
|
945
1297
|
const logFile = { version: 1, records: this.records };
|
|
946
1298
|
const data = { version: 1, blob: this.encrypt(JSON.stringify(logFile)) };
|
|
947
|
-
|
|
948
|
-
|
|
1299
|
+
mkdirSync5(this.baseDir, { recursive: true, mode: 448 });
|
|
1300
|
+
writeFileSync5(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
949
1301
|
}
|
|
950
1302
|
};
|
|
951
1303
|
|
|
952
1304
|
// src/lib/receipt-archive.ts
|
|
953
|
-
import { mkdirSync as
|
|
1305
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
954
1306
|
import { homedir as homedir4 } from "os";
|
|
955
|
-
import { dirname as
|
|
1307
|
+
import { dirname as dirname6, join as join7 } from "path";
|
|
956
1308
|
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes4 } from "crypto";
|
|
957
|
-
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ??
|
|
1309
|
+
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ?? join7(homedir4(), ".suveren");
|
|
958
1310
|
function stripPreviews(proposal) {
|
|
959
1311
|
const args = proposal.toolArgs;
|
|
960
1312
|
if (!args || typeof args !== "object") return proposal;
|
|
@@ -968,7 +1320,7 @@ var ReceiptArchive = class {
|
|
|
968
1320
|
vaultKey = null;
|
|
969
1321
|
constructor(filePath) {
|
|
970
1322
|
if (filePath && filePath.endsWith(".json")) {
|
|
971
|
-
this.baseDir =
|
|
1323
|
+
this.baseDir = dirname6(filePath);
|
|
972
1324
|
} else {
|
|
973
1325
|
this.baseDir = filePath ?? DEFAULT_DIR4;
|
|
974
1326
|
}
|
|
@@ -979,13 +1331,13 @@ var ReceiptArchive = class {
|
|
|
979
1331
|
*/
|
|
980
1332
|
setVaultKey(key) {
|
|
981
1333
|
this.vaultKey = key;
|
|
982
|
-
if (
|
|
1334
|
+
if (existsSync7(this.encryptedFilePath)) {
|
|
983
1335
|
this.loadEncrypted();
|
|
984
1336
|
} else if (this.data.receipts.length > 0 || Object.keys(this.data.authorizations).length > 0) {
|
|
985
1337
|
this.persistEncrypted();
|
|
986
|
-
if (
|
|
1338
|
+
if (existsSync7(this.plaintextFilePath)) {
|
|
987
1339
|
try {
|
|
988
|
-
|
|
1340
|
+
unlinkSync5(this.plaintextFilePath);
|
|
989
1341
|
} catch {
|
|
990
1342
|
}
|
|
991
1343
|
}
|
|
@@ -997,7 +1349,7 @@ var ReceiptArchive = class {
|
|
|
997
1349
|
* this state — that would report a hollow success over unreadable evidence.
|
|
998
1350
|
*/
|
|
999
1351
|
isLocked() {
|
|
1000
|
-
return this.vaultKey === null &&
|
|
1352
|
+
return this.vaultKey === null && existsSync7(this.encryptedFilePath);
|
|
1001
1353
|
}
|
|
1002
1354
|
/**
|
|
1003
1355
|
* Archive a signed receipt (and the grant it was issued under).
|
|
@@ -1098,19 +1450,19 @@ var ReceiptArchive = class {
|
|
|
1098
1450
|
}
|
|
1099
1451
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
1100
1452
|
get plaintextFilePath() {
|
|
1101
|
-
return
|
|
1453
|
+
return join7(this.baseDir, "receipt-archive.json");
|
|
1102
1454
|
}
|
|
1103
1455
|
get encryptedFilePath() {
|
|
1104
|
-
return
|
|
1456
|
+
return join7(this.baseDir, "receipt-archive.enc.json");
|
|
1105
1457
|
}
|
|
1106
1458
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
1107
1459
|
loadPlaintext() {
|
|
1108
|
-
if (!
|
|
1109
|
-
|
|
1460
|
+
if (!existsSync7(this.plaintextFilePath)) {
|
|
1461
|
+
mkdirSync6(this.baseDir, { recursive: true });
|
|
1110
1462
|
return;
|
|
1111
1463
|
}
|
|
1112
1464
|
try {
|
|
1113
|
-
const raw =
|
|
1465
|
+
const raw = readFileSync8(this.plaintextFilePath, "utf-8");
|
|
1114
1466
|
const parsed = JSON.parse(raw);
|
|
1115
1467
|
this.data = {
|
|
1116
1468
|
version: 1,
|
|
@@ -1120,18 +1472,18 @@ var ReceiptArchive = class {
|
|
|
1120
1472
|
} catch {
|
|
1121
1473
|
console.error(`[ReceiptArchive] Could not parse ${this.plaintextFilePath} \u2014 preserving as .corrupt`);
|
|
1122
1474
|
try {
|
|
1123
|
-
|
|
1475
|
+
writeFileSync6(
|
|
1124
1476
|
`${this.plaintextFilePath}.corrupt-${Date.now()}`,
|
|
1125
|
-
|
|
1477
|
+
readFileSync8(this.plaintextFilePath)
|
|
1126
1478
|
);
|
|
1127
1479
|
} catch {
|
|
1128
1480
|
}
|
|
1129
1481
|
}
|
|
1130
1482
|
}
|
|
1131
1483
|
loadEncrypted() {
|
|
1132
|
-
if (!
|
|
1484
|
+
if (!existsSync7(this.encryptedFilePath)) return;
|
|
1133
1485
|
try {
|
|
1134
|
-
const raw =
|
|
1486
|
+
const raw = readFileSync8(this.encryptedFilePath, "utf-8");
|
|
1135
1487
|
const data = JSON.parse(raw);
|
|
1136
1488
|
const decrypted = this.decrypt(data.blob);
|
|
1137
1489
|
const parsed = JSON.parse(decrypted);
|
|
@@ -1143,9 +1495,9 @@ var ReceiptArchive = class {
|
|
|
1143
1495
|
} catch (err) {
|
|
1144
1496
|
console.error(`[ReceiptArchive] Could not decrypt ${this.encryptedFilePath} \u2014 preserving as .corrupt:`, err);
|
|
1145
1497
|
try {
|
|
1146
|
-
|
|
1498
|
+
writeFileSync6(
|
|
1147
1499
|
`${this.encryptedFilePath}.corrupt-${Date.now()}`,
|
|
1148
|
-
|
|
1500
|
+
readFileSync8(this.encryptedFilePath)
|
|
1149
1501
|
);
|
|
1150
1502
|
} catch {
|
|
1151
1503
|
}
|
|
@@ -1159,29 +1511,29 @@ var ReceiptArchive = class {
|
|
|
1159
1511
|
}
|
|
1160
1512
|
}
|
|
1161
1513
|
persistPlaintext() {
|
|
1162
|
-
|
|
1163
|
-
|
|
1514
|
+
mkdirSync6(this.baseDir, { recursive: true, mode: 448 });
|
|
1515
|
+
writeFileSync6(this.plaintextFilePath, JSON.stringify(this.data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1164
1516
|
}
|
|
1165
1517
|
persistEncrypted() {
|
|
1166
1518
|
const data = {
|
|
1167
1519
|
version: 1,
|
|
1168
1520
|
blob: this.encrypt(JSON.stringify(this.data))
|
|
1169
1521
|
};
|
|
1170
|
-
|
|
1171
|
-
|
|
1522
|
+
mkdirSync6(this.baseDir, { recursive: true, mode: 448 });
|
|
1523
|
+
writeFileSync6(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1172
1524
|
}
|
|
1173
1525
|
};
|
|
1174
1526
|
|
|
1175
1527
|
// src/lib/execution-journal.ts
|
|
1176
|
-
import { mkdirSync as
|
|
1528
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync8, renameSync } from "fs";
|
|
1177
1529
|
import { homedir as homedir5 } from "os";
|
|
1178
|
-
import { dirname as
|
|
1179
|
-
import { createHash } from "crypto";
|
|
1180
|
-
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ??
|
|
1530
|
+
import { dirname as dirname7, join as join8 } from "path";
|
|
1531
|
+
import { createHash as createHash3 } from "crypto";
|
|
1532
|
+
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ?? join8(homedir5(), ".suveren");
|
|
1181
1533
|
var FILE_NAME = "execution-journal.json";
|
|
1182
1534
|
var MAX_AGE_SECONDS2 = 90 * 24 * 60 * 60;
|
|
1183
1535
|
function hashToolArgs(args) {
|
|
1184
|
-
return "sha256:" +
|
|
1536
|
+
return "sha256:" + createHash3("sha256").update(stableStringify(args)).digest("hex");
|
|
1185
1537
|
}
|
|
1186
1538
|
function stableStringify(value) {
|
|
1187
1539
|
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
|
|
@@ -1193,8 +1545,8 @@ function stableStringify(value) {
|
|
|
1193
1545
|
var ExecutionJournal = class {
|
|
1194
1546
|
filePath;
|
|
1195
1547
|
constructor(filePath) {
|
|
1196
|
-
const baseDir = filePath && filePath.endsWith(".json") ?
|
|
1197
|
-
this.filePath =
|
|
1548
|
+
const baseDir = filePath && filePath.endsWith(".json") ? dirname7(filePath) : filePath ?? DEFAULT_DIR5;
|
|
1549
|
+
this.filePath = join8(baseDir, FILE_NAME);
|
|
1198
1550
|
}
|
|
1199
1551
|
/** Look a ticket up. Always reads from disk — another process may have written. */
|
|
1200
1552
|
get(ticketId) {
|
|
@@ -1233,9 +1585,9 @@ var ExecutionJournal = class {
|
|
|
1233
1585
|
}
|
|
1234
1586
|
// ─── Persistence ────────────────────────────────────────────────────────
|
|
1235
1587
|
load() {
|
|
1236
|
-
if (!
|
|
1588
|
+
if (!existsSync8(this.filePath)) return { version: 1, entries: [] };
|
|
1237
1589
|
try {
|
|
1238
|
-
const parsed = JSON.parse(
|
|
1590
|
+
const parsed = JSON.parse(readFileSync9(this.filePath, "utf8"));
|
|
1239
1591
|
if (parsed?.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
1240
1592
|
throw new Error("unexpected shape");
|
|
1241
1593
|
}
|
|
@@ -1249,9 +1601,9 @@ var ExecutionJournal = class {
|
|
|
1249
1601
|
persist(file) {
|
|
1250
1602
|
const cutoff = nowSec() - MAX_AGE_SECONDS2;
|
|
1251
1603
|
file.entries = file.entries.filter((e) => e.startedAt >= cutoff);
|
|
1252
|
-
|
|
1604
|
+
mkdirSync7(dirname7(this.filePath), { recursive: true, mode: 448 });
|
|
1253
1605
|
const tmp = this.filePath + ".tmp";
|
|
1254
|
-
|
|
1606
|
+
writeFileSync7(tmp, JSON.stringify(file, null, 2), { mode: 384 });
|
|
1255
1607
|
renameSync(tmp, this.filePath);
|
|
1256
1608
|
}
|
|
1257
1609
|
};
|
|
@@ -1259,6 +1611,61 @@ function nowSec() {
|
|
|
1259
1611
|
return Math.floor(Date.now() / 1e3);
|
|
1260
1612
|
}
|
|
1261
1613
|
|
|
1614
|
+
// src/lib/proposal-submission-store.ts
|
|
1615
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync9, renameSync as renameSync2 } from "fs";
|
|
1616
|
+
import { homedir as homedir6 } from "os";
|
|
1617
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
1618
|
+
var DEFAULT_DIR6 = process.env.SUVEREN_DATA_DIR ?? join9(homedir6(), ".suveren");
|
|
1619
|
+
var FILE_NAME2 = "proposal-submissions.json";
|
|
1620
|
+
var MAX_AGE_SECONDS3 = 90 * 24 * 60 * 60;
|
|
1621
|
+
function nowSec2() {
|
|
1622
|
+
return Math.floor(Date.now() / 1e3);
|
|
1623
|
+
}
|
|
1624
|
+
var ProposalSubmissionStore = class {
|
|
1625
|
+
filePath;
|
|
1626
|
+
constructor(filePath) {
|
|
1627
|
+
const baseDir = filePath && filePath.endsWith(".json") ? dirname8(filePath) : filePath ?? DEFAULT_DIR6;
|
|
1628
|
+
this.filePath = join9(baseDir, FILE_NAME2);
|
|
1629
|
+
}
|
|
1630
|
+
/** Record what was submitted, right after a successful submitProposal(). */
|
|
1631
|
+
record(entry) {
|
|
1632
|
+
const file = this.load();
|
|
1633
|
+
file.entries = file.entries.filter((e) => e.proposalId !== entry.proposalId);
|
|
1634
|
+
file.entries.push({
|
|
1635
|
+
proposalId: entry.proposalId,
|
|
1636
|
+
tool: entry.tool,
|
|
1637
|
+
toolArgsHash: hashToolArgs(entry.toolArgs),
|
|
1638
|
+
executionContextHash: hashToolArgs(entry.executionContext),
|
|
1639
|
+
authorizationId: entry.authorizationId,
|
|
1640
|
+
profileId: entry.profileId,
|
|
1641
|
+
submittedAt: nowSec2()
|
|
1642
|
+
});
|
|
1643
|
+
this.persist(file);
|
|
1644
|
+
}
|
|
1645
|
+
/** Always reads from disk — another process (the poll loop lives in the
|
|
1646
|
+
* same process, but this stays consistent with execution-journal.ts). */
|
|
1647
|
+
get(proposalId) {
|
|
1648
|
+
return this.load().entries.find((e) => e.proposalId === proposalId);
|
|
1649
|
+
}
|
|
1650
|
+
load() {
|
|
1651
|
+
if (!existsSync9(this.filePath)) return { version: 1, entries: [] };
|
|
1652
|
+
try {
|
|
1653
|
+
const parsed = JSON.parse(readFileSync10(this.filePath, "utf-8"));
|
|
1654
|
+
const cutoff = nowSec2() - MAX_AGE_SECONDS3;
|
|
1655
|
+
parsed.entries = (parsed.entries ?? []).filter((e) => e.submittedAt >= cutoff);
|
|
1656
|
+
return parsed;
|
|
1657
|
+
} catch {
|
|
1658
|
+
return { version: 1, entries: [] };
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
persist(file) {
|
|
1662
|
+
mkdirSync8(dirname8(this.filePath), { recursive: true, mode: 448 });
|
|
1663
|
+
const tmpPath = `${this.filePath}.tmp`;
|
|
1664
|
+
writeFileSync8(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1665
|
+
renameSync2(tmpPath, this.filePath);
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1262
1669
|
// src/lib/gatekeeper.ts
|
|
1263
1670
|
import { verify } from "@hap/core";
|
|
1264
1671
|
var MCPGatekeeper = class {
|
|
@@ -1309,7 +1716,26 @@ var MCPGatekeeper = class {
|
|
|
1309
1716
|
authorization: auth
|
|
1310
1717
|
};
|
|
1311
1718
|
}
|
|
1312
|
-
|
|
1719
|
+
let publicKeyHex;
|
|
1720
|
+
try {
|
|
1721
|
+
publicKeyHex = await this.cache.getPublicKey();
|
|
1722
|
+
} catch (err) {
|
|
1723
|
+
if (err instanceof AsKeyMismatchError) {
|
|
1724
|
+
void notifyControlPlane("as-key-mismatch");
|
|
1725
|
+
return {
|
|
1726
|
+
result: {
|
|
1727
|
+
approved: false,
|
|
1728
|
+
// No dedicated GatekeeperError code exists for this (hap-core's
|
|
1729
|
+
// union predates gateway-side key pinning) — INVALID_SIGNATURE is
|
|
1730
|
+
// the closest fit: it's exactly the claim being made here ("we
|
|
1731
|
+
// will not trust a signature made under this key").
|
|
1732
|
+
errors: [{ code: "INVALID_SIGNATURE", message: err.message }]
|
|
1733
|
+
},
|
|
1734
|
+
authorization: auth
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
throw err;
|
|
1738
|
+
}
|
|
1313
1739
|
const resolvedBounds = override?.bounds ?? auth.bounds ?? auth.frame;
|
|
1314
1740
|
const resolvedContext = override?.context ?? auth.context;
|
|
1315
1741
|
const frame = { ...resolvedBounds, profile: auth.profileId };
|
|
@@ -1341,15 +1767,26 @@ var SharedState = class {
|
|
|
1341
1767
|
receiptArchive;
|
|
1342
1768
|
/** Which tickets this Gatekeeper has executed — the "one execution per ticket" half of exactly-once. */
|
|
1343
1769
|
executionJournal;
|
|
1770
|
+
/** What THIS gateway submitted for each review-mode proposal it created —
|
|
1771
|
+
* see ticket-verify.ts / commitments.ts. */
|
|
1772
|
+
proposalSubmissions;
|
|
1344
1773
|
gatekeeper;
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1774
|
+
/**
|
|
1775
|
+
* @param dataDir Passed to the AttestationCache so it can enforce AS key
|
|
1776
|
+
* pinning (as-pairing.ts), and to the SPClient so it can enforce opt-in
|
|
1777
|
+
* TLS pinning (as-tls-pin.ts). Optional for backward compat with
|
|
1778
|
+
* existing constructions/tests that pass only a URL — those get
|
|
1779
|
+
* unpinned trust-on-first-use behavior, same as before pinning existed.
|
|
1780
|
+
*/
|
|
1781
|
+
constructor(spUrl2, gateStorePath, dataDir2) {
|
|
1782
|
+
this.spClient = new SPClient(spUrl2, void 0, dataDir2);
|
|
1783
|
+
this.cache = new AttestationCache(this.spClient, dataDir2);
|
|
1348
1784
|
this.gateStore = new GateStore(gateStorePath);
|
|
1349
1785
|
this.executionLog = new ExecutionLog(gateStorePath);
|
|
1350
1786
|
this.denialLog = new DenialLog(gateStorePath);
|
|
1351
1787
|
this.receiptArchive = new ReceiptArchive(gateStorePath);
|
|
1352
1788
|
this.executionJournal = new ExecutionJournal(gateStorePath);
|
|
1789
|
+
this.proposalSubmissions = new ProposalSubmissionStore(gateStorePath);
|
|
1353
1790
|
this.gatekeeper = new MCPGatekeeper(this.cache);
|
|
1354
1791
|
}
|
|
1355
1792
|
/**
|
|
@@ -1365,7 +1802,8 @@ var SharedState = class {
|
|
|
1365
1802
|
let asPublicKey;
|
|
1366
1803
|
try {
|
|
1367
1804
|
asPublicKey = await this.cache.getPublicKey();
|
|
1368
|
-
} catch {
|
|
1805
|
+
} catch (err) {
|
|
1806
|
+
if (err instanceof AsKeyMismatchError) throw err;
|
|
1369
1807
|
}
|
|
1370
1808
|
this.receiptArchive.record({
|
|
1371
1809
|
receipt,
|
|
@@ -1387,6 +1825,7 @@ var SharedState = class {
|
|
|
1387
1825
|
} : void 0
|
|
1388
1826
|
});
|
|
1389
1827
|
} catch (err) {
|
|
1828
|
+
if (err instanceof AsKeyMismatchError) throw err;
|
|
1390
1829
|
console.error(
|
|
1391
1830
|
"[Suveren MCP] Receipt archive write failed (execution proceeds \u2014 AS retains authoritative copy):",
|
|
1392
1831
|
err
|
|
@@ -1435,6 +1874,7 @@ import { z } from "zod";
|
|
|
1435
1874
|
import { getProfile } from "@hap/core";
|
|
1436
1875
|
|
|
1437
1876
|
// src/lib/consumption.ts
|
|
1877
|
+
import { boundActionTypes } from "@hap/core";
|
|
1438
1878
|
function getConsumptionState(auth, executionLog, profile) {
|
|
1439
1879
|
if (!profile?.boundsSchema?.fields) return [];
|
|
1440
1880
|
const entries = [];
|
|
@@ -1454,7 +1894,8 @@ function getConsumptionState(auth, executionLog, profile) {
|
|
|
1454
1894
|
auth.path,
|
|
1455
1895
|
cumulativeField,
|
|
1456
1896
|
bt.window,
|
|
1457
|
-
now
|
|
1897
|
+
now,
|
|
1898
|
+
boundActionTypes(fieldName, fieldDef)
|
|
1458
1899
|
);
|
|
1459
1900
|
entries.push({
|
|
1460
1901
|
// displayName FIRST: description is prose meant for a human reading the
|
|
@@ -1498,24 +1939,24 @@ function formatConsumptionFull(entries) {
|
|
|
1498
1939
|
}
|
|
1499
1940
|
|
|
1500
1941
|
// src/lib/context-loader.ts
|
|
1501
|
-
import { readFileSync as
|
|
1502
|
-
import { homedir as
|
|
1503
|
-
import { join as
|
|
1504
|
-
var
|
|
1942
|
+
import { readFileSync as readFileSync11, existsSync as existsSync10 } from "fs";
|
|
1943
|
+
import { homedir as homedir7 } from "os";
|
|
1944
|
+
import { join as join10 } from "path";
|
|
1945
|
+
var DEFAULT_DIR7 = process.env.SUVEREN_DATA_DIR ?? join10(homedir7(), ".suveren");
|
|
1505
1946
|
var BRIEF_MAX_CHARS = 16 * 1024;
|
|
1506
|
-
function readContextFile(
|
|
1507
|
-
const dir =
|
|
1508
|
-
const filePath =
|
|
1509
|
-
if (!
|
|
1947
|
+
function readContextFile(dataDir2) {
|
|
1948
|
+
const dir = dataDir2 ?? DEFAULT_DIR7;
|
|
1949
|
+
const filePath = join10(dir, "context.md");
|
|
1950
|
+
if (!existsSync10(filePath)) return null;
|
|
1510
1951
|
try {
|
|
1511
|
-
const content =
|
|
1952
|
+
const content = readFileSync11(filePath, "utf-8").trim();
|
|
1512
1953
|
return content || null;
|
|
1513
1954
|
} catch {
|
|
1514
1955
|
return null;
|
|
1515
1956
|
}
|
|
1516
1957
|
}
|
|
1517
|
-
function getContextForBrief(
|
|
1518
|
-
const full = readContextFile(
|
|
1958
|
+
function getContextForBrief(dataDir2) {
|
|
1959
|
+
const full = readContextFile(dataDir2);
|
|
1519
1960
|
if (!full) return { brief: null, truncated: false };
|
|
1520
1961
|
if (full.length <= BRIEF_MAX_CHARS) {
|
|
1521
1962
|
return { brief: full, truncated: false };
|
|
@@ -1623,9 +2064,35 @@ function expiredSessionNotice(what) {
|
|
|
1623
2064
|
|
|
1624
2065
|
TELL THE USER: open ${uiUrl()} and enter your Suveren API key to sign in again. Your mandates are safe; nothing ran.`;
|
|
1625
2066
|
}
|
|
2067
|
+
function asKeyMismatchNotice(what) {
|
|
2068
|
+
return `${what} Suveren gateway is LOCKED because the Authority Server it is configured to use presented a signing key that does not match the one pinned when this gateway last signed in. This is NOT an ended sign-in \u2014 signing in again will be refused until the mismatch is resolved.
|
|
2069
|
+
|
|
2070
|
+
TELL THE USER: this needs an operator to check whether the Authority Server's key changed intentionally (e.g. a reinstall) or something else is answering at that address, at ${uiUrl()}. Nothing ran under the unrecognized key.`;
|
|
2071
|
+
}
|
|
2072
|
+
function asTlsMismatchNotice(what) {
|
|
2073
|
+
return `${what} Suveren gateway is LOCKED because a connection to the Authority Server presented a TLS certificate that does not match the one pinned when this gateway last signed in (opt-in pin-tls). This is NOT an ended sign-in \u2014 signing in again will be refused until the mismatch is resolved.
|
|
2074
|
+
|
|
2075
|
+
TELL THE USER: this needs an operator to check whether the Authority Server's certificate changed intentionally (e.g. a new TLS key, not just a renewal) or something else is answering at that address, at ${uiUrl()}. Nothing was sent under the unrecognized certificate.`;
|
|
2076
|
+
}
|
|
2077
|
+
function asUrlChangedNotice(what) {
|
|
2078
|
+
return `${what} Suveren gateway is LOCKED because the Authority Server it points at has changed since it last signed in. Cached mandates from the old server were cleared.
|
|
2079
|
+
|
|
2080
|
+
TELL THE USER: open ${uiUrl()} and sign in again to pair with the new Authority Server.`;
|
|
2081
|
+
}
|
|
1626
2082
|
function lockedNotice(action, reason = "restart") {
|
|
1627
2083
|
const what = action ? `Cannot ${action}: the` : "The";
|
|
1628
|
-
|
|
2084
|
+
switch (reason) {
|
|
2085
|
+
case "expired":
|
|
2086
|
+
return expiredSessionNotice(what);
|
|
2087
|
+
case "as-key-mismatch":
|
|
2088
|
+
return asKeyMismatchNotice(what);
|
|
2089
|
+
case "as-tls-mismatch":
|
|
2090
|
+
return asTlsMismatchNotice(what);
|
|
2091
|
+
case "as-url-changed":
|
|
2092
|
+
return asUrlChangedNotice(what);
|
|
2093
|
+
default:
|
|
2094
|
+
return bootLockedNotice(what);
|
|
2095
|
+
}
|
|
1629
2096
|
}
|
|
1630
2097
|
|
|
1631
2098
|
// src/tools/authorizations.ts
|
|
@@ -1634,6 +2101,9 @@ import { getProfile as getProfile4 } from "@hap/core";
|
|
|
1634
2101
|
// src/lib/receipt-footer.ts
|
|
1635
2102
|
import { deriveIdentityLine } from "@hap/core";
|
|
1636
2103
|
var AS_BASE = (process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai").replace(/\/$/, "");
|
|
2104
|
+
function setAsBaseUrl(url) {
|
|
2105
|
+
AS_BASE = url.replace(/\/$/, "");
|
|
2106
|
+
}
|
|
1637
2107
|
var OPERATOR_NAME = process.env.SUVEREN_OPERATOR_NAME ?? "Suveren";
|
|
1638
2108
|
var HAP_URL = "https://www.humanagencyprotocol.org/";
|
|
1639
2109
|
var FOOTER_PROFILES = /* @__PURE__ */ new Set(["email", "calendar", "publish"]);
|
|
@@ -1739,6 +2209,88 @@ function attachReceiptId(tool, args, receiptId) {
|
|
|
1739
2209
|
return { ...args, receipt_id: receiptId };
|
|
1740
2210
|
}
|
|
1741
2211
|
|
|
2212
|
+
// src/lib/ticket-verify.ts
|
|
2213
|
+
import { verifyReceiptSignature } from "@hap/core";
|
|
2214
|
+
var TicketBindingMismatchError = class extends Error {
|
|
2215
|
+
constructor(message) {
|
|
2216
|
+
super(message);
|
|
2217
|
+
this.name = "TicketBindingMismatchError";
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
var TICKET_MAX_AGE_SECONDS = 5 * 60;
|
|
2221
|
+
var TICKET_MAX_CLOCK_SKEW_SECONDS = 30;
|
|
2222
|
+
async function verifyTicket(cache, receipt, expected) {
|
|
2223
|
+
const publicKeyHex = await cache.getPublicKey();
|
|
2224
|
+
if (typeof receipt.signature !== "string" || !receipt.signature) {
|
|
2225
|
+
throw new AsKeyMismatchError("Ticket carries no signature \u2014 refusing to trust it.");
|
|
2226
|
+
}
|
|
2227
|
+
try {
|
|
2228
|
+
await verifyReceiptSignature(receipt, publicKeyHex);
|
|
2229
|
+
} catch (err) {
|
|
2230
|
+
throw new AsKeyMismatchError(
|
|
2231
|
+
`Ticket signature does not verify against the pinned Authority Server key \u2014 ${err instanceof Error ? err.message : String(err)}. Refusing to execute.`
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
if (receipt.action !== expected.action) {
|
|
2235
|
+
throw new TicketBindingMismatchError(
|
|
2236
|
+
`Ticket action "${String(receipt.action)}" does not match the requested action "${expected.action}" \u2014 refusing to execute.`
|
|
2237
|
+
);
|
|
2238
|
+
}
|
|
2239
|
+
if (expected.executionContext !== void 0 && hashToolArgs(receipt.executionContext ?? {}) !== hashToolArgs(expected.executionContext)) {
|
|
2240
|
+
throw new TicketBindingMismatchError(
|
|
2241
|
+
"Ticket executionContext does not match what this call requested \u2014 refusing to execute."
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
if (expected.authorizationId !== void 0 && receipt.authorizationId !== expected.authorizationId) {
|
|
2245
|
+
throw new TicketBindingMismatchError(
|
|
2246
|
+
`Ticket authorizationId "${String(receipt.authorizationId)}" does not match the requested grant "${expected.authorizationId}" \u2014 refusing to execute.`
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
if (expected.profileId !== void 0 && receipt.profileId !== expected.profileId) {
|
|
2250
|
+
throw new TicketBindingMismatchError(
|
|
2251
|
+
`Ticket profileId "${String(receipt.profileId)}" does not match the requested profile "${expected.profileId}" \u2014 refusing to execute.`
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
if (expected.proposalId !== void 0 && receipt.proposalId !== expected.proposalId) {
|
|
2255
|
+
throw new TicketBindingMismatchError(
|
|
2256
|
+
`Ticket proposalId "${String(receipt.proposalId)}" does not match the proposal being executed "${expected.proposalId}" \u2014 refusing to execute.`
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
if (expected.idempotencyKey !== void 0 && receipt.idempotencyKey !== expected.idempotencyKey) {
|
|
2260
|
+
throw new TicketBindingMismatchError(
|
|
2261
|
+
`Ticket idempotencyKey "${String(receipt.idempotencyKey)}" does not match the one this call sent "${expected.idempotencyKey}" \u2014 refusing to execute.`
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
if (expected.contentHash !== void 0) {
|
|
2265
|
+
if (receipt.contentHash !== expected.contentHash) {
|
|
2266
|
+
throw new TicketBindingMismatchError(
|
|
2267
|
+
"Ticket contentHash does not match the content this call is bound to \u2014 refusing to execute."
|
|
2268
|
+
);
|
|
2269
|
+
}
|
|
2270
|
+
if (expected.contentBinding !== void 0 && hashToolArgs(receipt.contentBinding ?? {}) !== hashToolArgs(expected.contentBinding)) {
|
|
2271
|
+
throw new TicketBindingMismatchError(
|
|
2272
|
+
"Ticket contentBinding does not match what this call requested \u2014 refusing to execute."
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
const timestamp = receipt.timestamp;
|
|
2277
|
+
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
|
|
2278
|
+
throw new TicketBindingMismatchError("Ticket carries no valid timestamp \u2014 refusing to execute.");
|
|
2279
|
+
}
|
|
2280
|
+
const nowSec3 = Math.floor(Date.now() / 1e3);
|
|
2281
|
+
const ageSec = nowSec3 - timestamp;
|
|
2282
|
+
if (ageSec > TICKET_MAX_AGE_SECONDS) {
|
|
2283
|
+
throw new TicketBindingMismatchError(
|
|
2284
|
+
`Ticket is ${ageSec}s old, older than the ${TICKET_MAX_AGE_SECONDS}s freshness window \u2014 refusing to execute.`
|
|
2285
|
+
);
|
|
2286
|
+
}
|
|
2287
|
+
if (ageSec < -TICKET_MAX_CLOCK_SKEW_SECONDS) {
|
|
2288
|
+
throw new TicketBindingMismatchError(
|
|
2289
|
+
`Ticket is timestamped ${-ageSec}s in the future, beyond the ${TICKET_MAX_CLOCK_SKEW_SECONDS}s clock-skew tolerance \u2014 refusing to execute.`
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
1742
2294
|
// src/lib/arg-encoding.ts
|
|
1743
2295
|
function rfc2047Encode(value) {
|
|
1744
2296
|
if (!/[^\x00-\x7F]/.test(value)) return value;
|
|
@@ -2454,6 +3006,14 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
2454
3006
|
toolArgs: enrichedArgs,
|
|
2455
3007
|
executionContext: { ...execution }
|
|
2456
3008
|
});
|
|
3009
|
+
state2.proposalSubmissions.record({
|
|
3010
|
+
proposalId: proposal.id,
|
|
3011
|
+
tool: tool.namespacedName,
|
|
3012
|
+
toolArgs: enrichedArgs,
|
|
3013
|
+
executionContext: { ...execution },
|
|
3014
|
+
authorizationId: authzId,
|
|
3015
|
+
profileId: auth.profileId
|
|
3016
|
+
});
|
|
2457
3017
|
return {
|
|
2458
3018
|
content: [{
|
|
2459
3019
|
type: "text",
|
|
@@ -2478,6 +3038,7 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2478
3038
|
try {
|
|
2479
3039
|
const actionType = declaredActionType;
|
|
2480
3040
|
const binding = computeContentBinding(auth.profileId, tool, args, actionType);
|
|
3041
|
+
const idempotencyKey = randomUUID();
|
|
2481
3042
|
const { receipt } = await state2.spClient.postReceipt({
|
|
2482
3043
|
authorizationId: authzId,
|
|
2483
3044
|
// Optional cross-check — the AS fails closed on a mismatch.
|
|
@@ -2487,7 +3048,7 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2487
3048
|
actionType,
|
|
2488
3049
|
executionContext: { ...execution },
|
|
2489
3050
|
amount: typeof execution.amount === "number" ? execution.amount : void 0,
|
|
2490
|
-
idempotencyKey
|
|
3051
|
+
idempotencyKey,
|
|
2491
3052
|
// Privacy: send the hash and how to reproduce it — never the
|
|
2492
3053
|
// preimage. `binding` also carries `boundContent`, the plaintext
|
|
2493
3054
|
// that was hashed (an email's to/cc/subject/body); it stays on
|
|
@@ -2496,6 +3057,15 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2496
3057
|
...binding ? { contentHash: binding.contentHash, contentBinding: binding.contentBinding } : {}
|
|
2497
3058
|
});
|
|
2498
3059
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
3060
|
+
await verifyTicket(state2.cache, receipt, {
|
|
3061
|
+
action: tool.namespacedName,
|
|
3062
|
+
executionContext: { ...execution },
|
|
3063
|
+
authorizationId: authzId,
|
|
3064
|
+
profileId: auth.profileId,
|
|
3065
|
+
idempotencyKey,
|
|
3066
|
+
contentHash: binding?.contentHash,
|
|
3067
|
+
contentBinding: binding?.contentBinding
|
|
3068
|
+
});
|
|
2499
3069
|
await state2.archiveReceipt(receipt, {
|
|
2500
3070
|
authorizationId: authzId,
|
|
2501
3071
|
profileId: auth.profileId,
|
|
@@ -2510,6 +3080,13 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2510
3080
|
boundContent: binding?.boundContent
|
|
2511
3081
|
});
|
|
2512
3082
|
} catch (err) {
|
|
3083
|
+
if (err instanceof AsKeyMismatchError || err instanceof TicketBindingMismatchError) {
|
|
3084
|
+
void notifyControlPlane("as-key-mismatch");
|
|
3085
|
+
return {
|
|
3086
|
+
content: [{ type: "text", text: `Blocked: ${err.message}` }],
|
|
3087
|
+
isError: true
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
2513
3090
|
if (err instanceof ContentBindingError) {
|
|
2514
3091
|
return {
|
|
2515
3092
|
content: [{
|
|
@@ -2555,6 +3132,14 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2555
3132
|
executionContext: { ...execution },
|
|
2556
3133
|
pendingApprovers: uniqueApprovers
|
|
2557
3134
|
});
|
|
3135
|
+
state2.proposalSubmissions.record({
|
|
3136
|
+
proposalId: proposal.id,
|
|
3137
|
+
tool: tool.namespacedName,
|
|
3138
|
+
toolArgs: enrichedArgs,
|
|
3139
|
+
executionContext: { ...execution },
|
|
3140
|
+
authorizationId: authzId,
|
|
3141
|
+
profileId: auth.profileId
|
|
3142
|
+
});
|
|
2558
3143
|
return {
|
|
2559
3144
|
content: [{
|
|
2560
3145
|
type: "text",
|
|
@@ -2962,6 +3547,9 @@ function listIntegrationsHandler(state2, integrationManager2) {
|
|
|
2962
3547
|
|
|
2963
3548
|
// src/tools/commitments.ts
|
|
2964
3549
|
import { ContentBindingError as ContentBindingError2 } from "@hap/core";
|
|
3550
|
+
function buildSkippedProposalNote(proposalId) {
|
|
3551
|
+
return `Proposal ${proposalId} was approved, but was submitted from another device/installation of this operator (or one whose local record is gone) \u2014 this gateway will not execute it. Re-run the same request here to execute it from this gateway.`;
|
|
3552
|
+
}
|
|
2965
3553
|
var installedExecutor = null;
|
|
2966
3554
|
function installCommittedExecutor(executor) {
|
|
2967
3555
|
installedExecutor = executor;
|
|
@@ -2987,6 +3575,28 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2987
3575
|
);
|
|
2988
3576
|
}
|
|
2989
3577
|
const cachedAuth = state2.cache.getAllAuthorizations().find((a) => a.authorizationId === proposal.authorizationId);
|
|
3578
|
+
const submitted = state2.proposalSubmissions.get(proposal.id);
|
|
3579
|
+
if (!submitted) {
|
|
3580
|
+
console.error(
|
|
3581
|
+
`[Suveren MCP] Proposal ${proposal.id} is committed but has no local submission record on this gateway \u2014 leaving it for whichever gateway submitted it (this is normal for a different device of the same operator, or the AS lists a proposal we never submitted).`
|
|
3582
|
+
);
|
|
3583
|
+
return { text: buildSkippedProposalNote(proposal.id) };
|
|
3584
|
+
}
|
|
3585
|
+
{
|
|
3586
|
+
const mismatches = [];
|
|
3587
|
+
if (submitted.tool !== proposal.tool) mismatches.push("tool");
|
|
3588
|
+
if (submitted.toolArgsHash !== hashToolArgs(proposal.toolArgs)) mismatches.push("arguments");
|
|
3589
|
+
if (submitted.executionContextHash !== hashToolArgs(proposal.executionContext)) mismatches.push("executionContext");
|
|
3590
|
+
if (submitted.authorizationId !== proposal.authorizationId) mismatches.push("authorizationId");
|
|
3591
|
+
if (submitted.profileId !== proposal.profileId) mismatches.push("profileId");
|
|
3592
|
+
if (mismatches.length > 0) {
|
|
3593
|
+
void notifyControlPlane("as-key-mismatch");
|
|
3594
|
+
return {
|
|
3595
|
+
text: `Blocked: proposal ${proposal.id} no longer matches what this gateway submitted (${mismatches.join(", ")} differ) \u2014 refusing to execute.`,
|
|
3596
|
+
isError: true
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
2990
3600
|
let receiptId;
|
|
2991
3601
|
let replayed = false;
|
|
2992
3602
|
try {
|
|
@@ -3022,6 +3632,15 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
3022
3632
|
});
|
|
3023
3633
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
3024
3634
|
replayed = idempotent;
|
|
3635
|
+
await verifyTicket(state2.cache, receipt, {
|
|
3636
|
+
action: proposal.tool,
|
|
3637
|
+
executionContext: proposal.executionContext,
|
|
3638
|
+
authorizationId: proposal.authorizationId,
|
|
3639
|
+
profileId: proposal.profileId,
|
|
3640
|
+
proposalId: proposal.id,
|
|
3641
|
+
contentHash: binding?.contentHash,
|
|
3642
|
+
contentBinding: binding?.contentBinding
|
|
3643
|
+
});
|
|
3025
3644
|
await state2.archiveReceipt(receipt, {
|
|
3026
3645
|
authorizationId: proposal.authorizationId,
|
|
3027
3646
|
profileId: proposal.profileId,
|
|
@@ -3036,6 +3655,13 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
3036
3655
|
boundContent: binding?.boundContent
|
|
3037
3656
|
});
|
|
3038
3657
|
} catch (err) {
|
|
3658
|
+
if (err instanceof AsKeyMismatchError || err instanceof TicketBindingMismatchError) {
|
|
3659
|
+
void notifyControlPlane("as-key-mismatch");
|
|
3660
|
+
return {
|
|
3661
|
+
text: `Proposal ${proposal.id}: blocked \u2014 ${err.message}`,
|
|
3662
|
+
isError: true
|
|
3663
|
+
};
|
|
3664
|
+
}
|
|
3039
3665
|
if (err instanceof ContentBindingError2) {
|
|
3040
3666
|
return {
|
|
3041
3667
|
text: `Proposal ${proposal.id}: blocked \u2014 the approved content cannot be bound to the receipt. ${err.message}`,
|
|
@@ -3195,9 +3821,13 @@ Wait for the human to approve; do not re-submit the tool call.`
|
|
|
3195
3821
|
}]
|
|
3196
3822
|
};
|
|
3197
3823
|
}
|
|
3198
|
-
const lines = committed.map(
|
|
3199
|
-
|
|
3200
|
-
|
|
3824
|
+
const lines = committed.map((p) => {
|
|
3825
|
+
const base = `${p.id}: tool=${p.tool}, status=${p.status}, committed=[${Object.keys(p.committedBy).join(",")}]`;
|
|
3826
|
+
if (p.status === "committed" && !state2.proposalSubmissions.get(p.id)) {
|
|
3827
|
+
return `${base} \u2014 SKIPPED HERE: ${buildSkippedProposalNote(p.id)}`;
|
|
3828
|
+
}
|
|
3829
|
+
return base;
|
|
3830
|
+
});
|
|
3201
3831
|
return {
|
|
3202
3832
|
content: [{
|
|
3203
3833
|
type: "text",
|
|
@@ -3394,16 +4024,16 @@ function verifyGateContentHashes(content, auth) {
|
|
|
3394
4024
|
}
|
|
3395
4025
|
|
|
3396
4026
|
// src/lib/integration-registry.ts
|
|
3397
|
-
import { mkdirSync as
|
|
3398
|
-
import { homedir as
|
|
3399
|
-
import { dirname as
|
|
3400
|
-
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
4027
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync11 } from "fs";
|
|
4028
|
+
import { homedir as homedir8 } from "os";
|
|
4029
|
+
import { dirname as dirname9, join as join11 } from "path";
|
|
4030
|
+
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join11(homedir8(), ".suveren");
|
|
3401
4031
|
var IntegrationRegistry = class {
|
|
3402
4032
|
integrations = /* @__PURE__ */ new Map();
|
|
3403
4033
|
filePath;
|
|
3404
|
-
constructor(
|
|
3405
|
-
const dir =
|
|
3406
|
-
this.filePath =
|
|
4034
|
+
constructor(dataDir2) {
|
|
4035
|
+
const dir = dataDir2 ?? DEFAULT_DATA_DIR;
|
|
4036
|
+
this.filePath = join11(dir, "integrations.json");
|
|
3407
4037
|
this.load();
|
|
3408
4038
|
}
|
|
3409
4039
|
// ─── CRUD ───────────────────────────────────────────────────────────────
|
|
@@ -3434,12 +4064,12 @@ var IntegrationRegistry = class {
|
|
|
3434
4064
|
}
|
|
3435
4065
|
// ─── Load / Save ────────────────────────────────────────────────────────
|
|
3436
4066
|
load() {
|
|
3437
|
-
if (!
|
|
3438
|
-
|
|
4067
|
+
if (!existsSync11(this.filePath)) {
|
|
4068
|
+
mkdirSync9(dirname9(this.filePath), { recursive: true });
|
|
3439
4069
|
return;
|
|
3440
4070
|
}
|
|
3441
4071
|
try {
|
|
3442
|
-
const raw =
|
|
4072
|
+
const raw = readFileSync12(this.filePath, "utf-8");
|
|
3443
4073
|
const data = JSON.parse(raw);
|
|
3444
4074
|
const migrated = data.integrations.map((i) => {
|
|
3445
4075
|
if ("toolGating" in i && !("profile" in i)) {
|
|
@@ -3468,45 +4098,45 @@ var IntegrationRegistry = class {
|
|
|
3468
4098
|
version: 1,
|
|
3469
4099
|
integrations: Array.from(this.integrations.values())
|
|
3470
4100
|
};
|
|
3471
|
-
|
|
3472
|
-
|
|
4101
|
+
mkdirSync9(dirname9(this.filePath), { recursive: true });
|
|
4102
|
+
writeFileSync9(this.filePath, JSON.stringify(data, null, 2), { encoding: "utf-8" });
|
|
3473
4103
|
}
|
|
3474
4104
|
};
|
|
3475
4105
|
|
|
3476
4106
|
// src/lib/integration-manager.ts
|
|
3477
|
-
import { homedir as
|
|
3478
|
-
import { join as
|
|
3479
|
-
import { existsSync as
|
|
4107
|
+
import { homedir as homedir9 } from "os";
|
|
4108
|
+
import { join as join13, delimiter } from "path";
|
|
4109
|
+
import { existsSync as existsSync13, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync14, rmSync } from "fs";
|
|
3480
4110
|
import { execFile } from "child_process";
|
|
3481
4111
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3482
4112
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3483
4113
|
import { getProfile as getProfile5 } from "@hap/core";
|
|
3484
4114
|
|
|
3485
4115
|
// src/lib/manifest-loader.ts
|
|
3486
|
-
import { readFileSync as
|
|
3487
|
-
import { join as
|
|
4116
|
+
import { readFileSync as readFileSync13, existsSync as existsSync12 } from "fs";
|
|
4117
|
+
import { join as join12, resolve } from "path";
|
|
3488
4118
|
var manifests = /* @__PURE__ */ new Map();
|
|
3489
4119
|
function loadManifests(integrationsDir) {
|
|
3490
4120
|
const dir = resolve(
|
|
3491
|
-
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ??
|
|
4121
|
+
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ?? join12(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "content", "integrations")
|
|
3492
4122
|
);
|
|
3493
|
-
const indexPath =
|
|
3494
|
-
if (!
|
|
4123
|
+
const indexPath = join12(dir, "index.json");
|
|
4124
|
+
if (!existsSync12(indexPath)) {
|
|
3495
4125
|
console.error(`[ManifestLoader] No index.json found at ${indexPath}, skipping manifest loading`);
|
|
3496
4126
|
return 0;
|
|
3497
4127
|
}
|
|
3498
4128
|
let index;
|
|
3499
4129
|
try {
|
|
3500
|
-
index = JSON.parse(
|
|
4130
|
+
index = JSON.parse(readFileSync13(indexPath, "utf-8"));
|
|
3501
4131
|
} catch (err) {
|
|
3502
4132
|
console.error(`[ManifestLoader] Failed to parse ${indexPath}:`, err);
|
|
3503
4133
|
return 0;
|
|
3504
4134
|
}
|
|
3505
4135
|
let loaded = 0;
|
|
3506
4136
|
for (const [id, relativePath] of Object.entries(index.integrations)) {
|
|
3507
|
-
const manifestPath =
|
|
4137
|
+
const manifestPath = join12(dir, relativePath);
|
|
3508
4138
|
try {
|
|
3509
|
-
const manifest = JSON.parse(
|
|
4139
|
+
const manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
|
|
3510
4140
|
manifests.set(id, manifest);
|
|
3511
4141
|
loaded++;
|
|
3512
4142
|
} catch (err) {
|
|
@@ -3594,26 +4224,26 @@ function safeHost(url) {
|
|
|
3594
4224
|
}
|
|
3595
4225
|
|
|
3596
4226
|
// src/lib/integration-manager.ts
|
|
3597
|
-
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
3598
|
-
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ??
|
|
4227
|
+
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join13(homedir9(), ".suveren");
|
|
4228
|
+
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ?? join13(DEFAULT_DATA_DIR2, "integrations");
|
|
3599
4229
|
var installLock = Promise.resolve();
|
|
3600
4230
|
function withInstallLock(task) {
|
|
3601
4231
|
const run = installLock.then(task, task);
|
|
3602
4232
|
installLock = run.then(() => void 0, () => void 0);
|
|
3603
4233
|
return run;
|
|
3604
4234
|
}
|
|
3605
|
-
var INTEGRATIONS_BIN =
|
|
4235
|
+
var INTEGRATIONS_BIN = join13(INTEGRATIONS_DIR, "node_modules", ".bin");
|
|
3606
4236
|
function buildPath() {
|
|
3607
4237
|
const base = process.env.PATH ?? "";
|
|
3608
4238
|
return [INTEGRATIONS_BIN, base].join(delimiter);
|
|
3609
4239
|
}
|
|
3610
4240
|
function ensureIntegrationsDir() {
|
|
3611
|
-
if (!
|
|
3612
|
-
|
|
4241
|
+
if (!existsSync13(INTEGRATIONS_DIR)) {
|
|
4242
|
+
mkdirSync10(INTEGRATIONS_DIR, { recursive: true });
|
|
3613
4243
|
}
|
|
3614
|
-
const pkgPath =
|
|
3615
|
-
if (!
|
|
3616
|
-
|
|
4244
|
+
const pkgPath = join13(INTEGRATIONS_DIR, "package.json");
|
|
4245
|
+
if (!existsSync13(pkgPath)) {
|
|
4246
|
+
writeFileSync10(pkgPath, JSON.stringify({ name: "suveren-integrations", version: "1.0.0", private: true }, null, 2));
|
|
3617
4247
|
}
|
|
3618
4248
|
}
|
|
3619
4249
|
function readAgeOf(config) {
|
|
@@ -3679,19 +4309,19 @@ var IntegrationManager = class {
|
|
|
3679
4309
|
* exist, and treat anything else as not-installed (and reinstallable).
|
|
3680
4310
|
*/
|
|
3681
4311
|
isUsableInstall(npmPackage) {
|
|
3682
|
-
const pkgDir =
|
|
3683
|
-
const pkgJson =
|
|
3684
|
-
if (!
|
|
4312
|
+
const pkgDir = join13(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
4313
|
+
const pkgJson = join13(pkgDir, "package.json");
|
|
4314
|
+
if (!existsSync13(pkgDir) || !existsSync13(pkgJson)) return false;
|
|
3685
4315
|
try {
|
|
3686
|
-
const pkg = JSON.parse(
|
|
4316
|
+
const pkg = JSON.parse(readFileSync14(pkgJson, "utf8"));
|
|
3687
4317
|
const defaultBinName = (pkg.name ?? npmPackage).split("/").pop() ?? "";
|
|
3688
4318
|
const binMap = typeof pkg.bin === "string" ? { [defaultBinName]: pkg.bin } : pkg.bin ?? {};
|
|
3689
4319
|
const binEntries = Object.entries(binMap);
|
|
3690
4320
|
for (const [binName, target] of binEntries) {
|
|
3691
|
-
if (!
|
|
4321
|
+
if (!existsSync13(join13(pkgDir, target))) return false;
|
|
3692
4322
|
if (!this.binShimExists(binName)) return false;
|
|
3693
4323
|
}
|
|
3694
|
-
if (binEntries.length === 0 && pkg.main && !
|
|
4324
|
+
if (binEntries.length === 0 && pkg.main && !existsSync13(join13(pkgDir, pkg.main))) return false;
|
|
3695
4325
|
return true;
|
|
3696
4326
|
} catch {
|
|
3697
4327
|
return false;
|
|
@@ -3705,7 +4335,7 @@ var IntegrationManager = class {
|
|
|
3705
4335
|
binShimExists(binName) {
|
|
3706
4336
|
if (!binName) return false;
|
|
3707
4337
|
const candidates = process.platform === "win32" ? [binName, `${binName}.cmd`, `${binName}.CMD`, `${binName}.ps1`] : [binName];
|
|
3708
|
-
return candidates.some((c) =>
|
|
4338
|
+
return candidates.some((c) => existsSync13(join13(INTEGRATIONS_BIN, c)));
|
|
3709
4339
|
}
|
|
3710
4340
|
/**
|
|
3711
4341
|
* Install an npm package into the managed integrations directory if not
|
|
@@ -3729,8 +4359,8 @@ var IntegrationManager = class {
|
|
|
3729
4359
|
}
|
|
3730
4360
|
/** The actual install. Callers MUST hold the install lock. */
|
|
3731
4361
|
async installNow(npmPackage) {
|
|
3732
|
-
const pkgDir =
|
|
3733
|
-
if (
|
|
4362
|
+
const pkgDir = join13(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
4363
|
+
if (existsSync13(pkgDir)) {
|
|
3734
4364
|
console.error(`[IntegrationManager] Removing unusable install of ${npmPackage}`);
|
|
3735
4365
|
try {
|
|
3736
4366
|
rmSync(pkgDir, { recursive: true, force: true });
|
|
@@ -3844,6 +4474,11 @@ var IntegrationManager = class {
|
|
|
3844
4474
|
const transport = new StdioClientTransport({
|
|
3845
4475
|
command: config.command,
|
|
3846
4476
|
args,
|
|
4477
|
+
// `...process.env` is also how a saved `--ca-file` reaches an
|
|
4478
|
+
// integration: NODE_EXTRA_CA_CERTS (read by Node only at process
|
|
4479
|
+
// start) is already set on THIS process by bundle/server.js before
|
|
4480
|
+
// the MCP server ever starts, so every integration this manager spawns
|
|
4481
|
+
// inherits it here for free — no separate handling needed.
|
|
3847
4482
|
env: {
|
|
3848
4483
|
...process.env,
|
|
3849
4484
|
PATH: buildPath(),
|
|
@@ -4160,28 +4795,28 @@ var IntegrationManager = class {
|
|
|
4160
4795
|
};
|
|
4161
4796
|
|
|
4162
4797
|
// src/lib/profile-loader.ts
|
|
4163
|
-
import { readFileSync as
|
|
4164
|
-
import { join as
|
|
4798
|
+
import { readFileSync as readFileSync15, existsSync as existsSync14 } from "fs";
|
|
4799
|
+
import { join as join14, resolve as resolve2 } from "path";
|
|
4165
4800
|
import { registerProfile } from "@hap/core";
|
|
4166
4801
|
function loadProfiles(profilesDir) {
|
|
4167
|
-
const dir = resolve2(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ??
|
|
4168
|
-
const indexPath =
|
|
4169
|
-
if (!
|
|
4802
|
+
const dir = resolve2(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ?? join14(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "..", "hap-profiles"));
|
|
4803
|
+
const indexPath = join14(dir, "index.json");
|
|
4804
|
+
if (!existsSync14(indexPath)) {
|
|
4170
4805
|
warnNoProfiles(`No index.json at ${indexPath}`);
|
|
4171
4806
|
return 0;
|
|
4172
4807
|
}
|
|
4173
4808
|
let index;
|
|
4174
4809
|
try {
|
|
4175
|
-
index = JSON.parse(
|
|
4810
|
+
index = JSON.parse(readFileSync15(indexPath, "utf-8"));
|
|
4176
4811
|
} catch (err) {
|
|
4177
4812
|
console.error(`[ProfileLoader] Failed to parse ${indexPath}:`, err);
|
|
4178
4813
|
return 0;
|
|
4179
4814
|
}
|
|
4180
4815
|
let loaded = 0;
|
|
4181
4816
|
for (const [profileId, relativePath] of Object.entries(index.profiles)) {
|
|
4182
|
-
const profilePath =
|
|
4817
|
+
const profilePath = join14(dir, relativePath);
|
|
4183
4818
|
try {
|
|
4184
|
-
const profile = JSON.parse(
|
|
4819
|
+
const profile = JSON.parse(readFileSync15(profilePath, "utf-8"));
|
|
4185
4820
|
registerProfile(profileId, profile);
|
|
4186
4821
|
const shortName = profileId.split("/").pop()?.replace(/@.*$/, "");
|
|
4187
4822
|
if (shortName && shortName !== profileId) {
|
|
@@ -4217,8 +4852,8 @@ function warnNoProfiles(reason) {
|
|
|
4217
4852
|
import { decodeAttestationBlob as decodeAttestationBlob3 } from "@hap/core";
|
|
4218
4853
|
|
|
4219
4854
|
// src/lib/committed-executor.ts
|
|
4220
|
-
import { existsSync as
|
|
4221
|
-
import { dirname as
|
|
4855
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync16, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
4856
|
+
import { dirname as dirname10, join as join15 } from "path";
|
|
4222
4857
|
var CommittedExecutor = class {
|
|
4223
4858
|
constructor(run) {
|
|
4224
4859
|
this.run = run;
|
|
@@ -4245,8 +4880,8 @@ var CommittedExecutor = class {
|
|
|
4245
4880
|
var ExecutorLock = class {
|
|
4246
4881
|
path;
|
|
4247
4882
|
held = false;
|
|
4248
|
-
constructor(
|
|
4249
|
-
this.path =
|
|
4883
|
+
constructor(dataDir2) {
|
|
4884
|
+
this.path = join15(dataDir2, "executor.lock");
|
|
4250
4885
|
}
|
|
4251
4886
|
/** Try to take the lock. Returns the holder's pid when someone else has it. */
|
|
4252
4887
|
acquire() {
|
|
@@ -4254,9 +4889,9 @@ var ExecutorLock = class {
|
|
|
4254
4889
|
if (current && current.pid !== process.pid && isAlive(current.pid)) {
|
|
4255
4890
|
return { held: false, holderPid: current.pid };
|
|
4256
4891
|
}
|
|
4257
|
-
|
|
4892
|
+
mkdirSync11(dirname10(this.path), { recursive: true, mode: 448 });
|
|
4258
4893
|
const lock = { pid: process.pid, startedAt: Math.floor(Date.now() / 1e3) };
|
|
4259
|
-
|
|
4894
|
+
writeFileSync11(this.path, JSON.stringify(lock), { mode: 384 });
|
|
4260
4895
|
this.held = true;
|
|
4261
4896
|
return { held: true };
|
|
4262
4897
|
}
|
|
@@ -4272,15 +4907,15 @@ var ExecutorLock = class {
|
|
|
4272
4907
|
const current = this.read();
|
|
4273
4908
|
if (current?.pid === process.pid) {
|
|
4274
4909
|
try {
|
|
4275
|
-
|
|
4910
|
+
unlinkSync6(this.path);
|
|
4276
4911
|
} catch {
|
|
4277
4912
|
}
|
|
4278
4913
|
}
|
|
4279
4914
|
}
|
|
4280
4915
|
read() {
|
|
4281
|
-
if (!
|
|
4916
|
+
if (!existsSync15(this.path)) return null;
|
|
4282
4917
|
try {
|
|
4283
|
-
const parsed = JSON.parse(
|
|
4918
|
+
const parsed = JSON.parse(readFileSync16(this.path, "utf8"));
|
|
4284
4919
|
return typeof parsed?.pid === "number" ? parsed : null;
|
|
4285
4920
|
} catch {
|
|
4286
4921
|
return null;
|
|
@@ -4297,11 +4932,48 @@ function isAlive(pid) {
|
|
|
4297
4932
|
}
|
|
4298
4933
|
|
|
4299
4934
|
// bin/http.ts
|
|
4300
|
-
import { homedir as
|
|
4301
|
-
import { join as
|
|
4302
|
-
|
|
4935
|
+
import { homedir as homedir10 } from "os";
|
|
4936
|
+
import { join as join17 } from "path";
|
|
4937
|
+
|
|
4938
|
+
// src/lib/mcp-as-tracker.ts
|
|
4939
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync12 } from "fs";
|
|
4940
|
+
import { dirname as dirname11, join as join16 } from "path";
|
|
4941
|
+
function trackerPath(dataDir2) {
|
|
4942
|
+
return join16(dataDir2, "mcp-as-pairing.json");
|
|
4943
|
+
}
|
|
4944
|
+
function readMcpPairedAsUrl(dataDir2) {
|
|
4945
|
+
const path = trackerPath(dataDir2);
|
|
4946
|
+
if (!existsSync16(path)) return null;
|
|
4947
|
+
try {
|
|
4948
|
+
const data = JSON.parse(readFileSync17(path, "utf-8"));
|
|
4949
|
+
return typeof data.asUrl === "string" ? data.asUrl : null;
|
|
4950
|
+
} catch {
|
|
4951
|
+
return null;
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
function writeMcpPairedAsUrl(dataDir2, asUrl) {
|
|
4955
|
+
const path = trackerPath(dataDir2);
|
|
4956
|
+
mkdirSync12(dirname11(path), { recursive: true, mode: 448 });
|
|
4957
|
+
writeFileSync12(path, JSON.stringify({ asUrl }, null, 2), { encoding: "utf-8", mode: 384 });
|
|
4958
|
+
}
|
|
4959
|
+
|
|
4960
|
+
// bin/http.ts
|
|
4961
|
+
var dataDir = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
4962
|
+
var spUrl = resolveAsUrl(dataDir);
|
|
4963
|
+
validatePinTlsForUrl(resolvePinTls(dataDir), spUrl);
|
|
4303
4964
|
var port = parseInt(process.env.SUVEREN_MCP_PORT ?? "3430", 10);
|
|
4304
|
-
|
|
4965
|
+
setAsBaseUrl(spUrl);
|
|
4966
|
+
var state = new SharedState(spUrl, void 0, dataDir);
|
|
4967
|
+
(function repairIfAsUrlChanged() {
|
|
4968
|
+
const lastKnown = readMcpPairedAsUrl(dataDir);
|
|
4969
|
+
if (lastKnown !== null && lastKnown !== spUrl) {
|
|
4970
|
+
console.error(
|
|
4971
|
+
`[Suveren MCP] Authority Server changed (${lastKnown} \u2192 ${spUrl}) \u2014 clearing cached mandates. Sign in again to re-pair.`
|
|
4972
|
+
);
|
|
4973
|
+
state.gateStore.clearAll();
|
|
4974
|
+
}
|
|
4975
|
+
writeMcpPairedAsUrl(dataDir, spUrl);
|
|
4976
|
+
})();
|
|
4305
4977
|
var spApiKey = process.env.SUVEREN_AS_API_KEY ?? "";
|
|
4306
4978
|
if (spApiKey) {
|
|
4307
4979
|
state.spClient.setApiKey(spApiKey);
|
|
@@ -4371,9 +5043,11 @@ app.post("/internal/configure", internalOnly, (req, res) => {
|
|
|
4371
5043
|
}
|
|
4372
5044
|
res.json({ ok: true });
|
|
4373
5045
|
});
|
|
4374
|
-
app.post("/internal/clear-session", internalOnly, (
|
|
4375
|
-
|
|
4376
|
-
|
|
5046
|
+
app.post("/internal/clear-session", internalOnly, (req, res) => {
|
|
5047
|
+
const reason = req.body?.reason;
|
|
5048
|
+
const validReason = reason === "as-key-mismatch" || reason === "as-tls-mismatch" || reason === "as-url-changed" ? reason : void 0;
|
|
5049
|
+
state.spClient.clearSession(validReason);
|
|
5050
|
+
console.error(`[Suveren MCP] Session cleared by control-plane (${validReason ?? "expired"})`);
|
|
4377
5051
|
res.json({ ok: true });
|
|
4378
5052
|
});
|
|
4379
5053
|
app.post("/internal/gate-content", internalOnly, async (req, res) => {
|
|
@@ -4665,6 +5339,15 @@ app.get("/internal/authorizations", internalOnly, (_req, res) => {
|
|
|
4665
5339
|
app.get("/internal/manifests", internalOnly, (_req, res) => {
|
|
4666
5340
|
res.json({ manifests: getAllManifests() });
|
|
4667
5341
|
});
|
|
5342
|
+
app.get("/internal/skipped-commitments", internalOnly, async (_req, res) => {
|
|
5343
|
+
try {
|
|
5344
|
+
const committed = await state.spClient.getCommittedProposals();
|
|
5345
|
+
const skipped = committed.filter((p) => !state.proposalSubmissions.get(p.id)).map((p) => ({ id: p.id, tool: p.tool, note: buildSkippedProposalNote(p.id) }));
|
|
5346
|
+
res.json({ skipped });
|
|
5347
|
+
} catch (err) {
|
|
5348
|
+
res.status(502).json({ error: err instanceof Error ? err.message : "Could not reach the Authority Server" });
|
|
5349
|
+
}
|
|
5350
|
+
});
|
|
4668
5351
|
app.get("/internal/evidence", internalOnly, (_req, res) => {
|
|
4669
5352
|
if (state.receiptArchive.isLocked()) {
|
|
4670
5353
|
res.status(503).json({ error: "Vault locked \u2014 the evidence archive is encrypted until sign-in." });
|
|
@@ -4798,12 +5481,12 @@ app.listen(port, "0.0.0.0", () => {
|
|
|
4798
5481
|
(proposal) => executeCommitted(proposal, state, integrationManager)
|
|
4799
5482
|
);
|
|
4800
5483
|
installCommittedExecutor(committedExecutor);
|
|
4801
|
-
const
|
|
4802
|
-
const executorLock = new ExecutorLock(
|
|
5484
|
+
const dataDir2 = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
5485
|
+
const executorLock = new ExecutorLock(dataDir2);
|
|
4803
5486
|
const lock = executorLock.acquire();
|
|
4804
5487
|
if (!lock.held) {
|
|
4805
5488
|
console.error(
|
|
4806
|
-
`[Suveren MCP] Committed-proposal execution is DISABLED in this process: pid ${lock.holderPid} holds ${
|
|
5489
|
+
`[Suveren MCP] Committed-proposal execution is DISABLED in this process: pid ${lock.holderPid} holds ${dataDir2}/executor.lock. Approved proposals will run there. Stop that gateway if this one should execute.`
|
|
4807
5490
|
);
|
|
4808
5491
|
}
|
|
4809
5492
|
for (const sig of ["SIGINT", "SIGTERM", "exit"]) {
|