@suveren/gateway 0.8.6 → 0.9.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/bin/suveren-gateway.js +165 -9
- package/dist/control-plane/index.mjs +546 -87
- package/dist/mcp-server/http.mjs +727 -187
- package/dist/ui/assets/index-CIiOCgjJ.js +110 -0
- package/dist/ui/icons/apple-touch-icon.png +0 -0
- package/dist/ui/icons/icon-192.png +0 -0
- package/dist/ui/icons/icon-512.png +0 -0
- package/dist/ui/icons/icon-maskable-512.png +0 -0
- package/dist/ui/index.html +7 -1
- package/dist/ui/manifest.webmanifest +15 -0
- package/lib/config.d.mts +37 -0
- package/lib/config.mjs +150 -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 +26 -4
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js +118 -17
- 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/server/express.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/express.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/express.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/requestBody.d.ts +25 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/requestBody.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/requestBody.js +64 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/requestBody.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.d.ts +10 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.js +13 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.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 +26 -4
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js +118 -17
- 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/server/express.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/express.js +3 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/express.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.d.ts +25 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.js +58 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.d.ts +10 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js +13 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.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 -341
- 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 -87
- 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 -370
- 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 +105 -119
- 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 -70
- 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 -36
- 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 -205
- 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 -49
- 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 -16
- 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 -197
- 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/package.json +2 -2
- 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/ui/assets/index-DWpjjPIf.js +0 -110
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -134,6 +134,13 @@ var SPClient = class {
|
|
|
134
134
|
sessionCookie = "";
|
|
135
135
|
apiKey = "";
|
|
136
136
|
receiptRetry;
|
|
137
|
+
/** Set when a call comes back 401 while we held a session — distinct from
|
|
138
|
+
* never having logged in. Cleared the moment a fresh cookie is configured. */
|
|
139
|
+
lockReason = null;
|
|
140
|
+
/** Single-flight per client instance: only the FIRST 401 after a session
|
|
141
|
+
* was active tells the control plane. Concurrent in-flight calls that were
|
|
142
|
+
* all sent under the same now-dead cookie would otherwise all report it. */
|
|
143
|
+
sessionExpiredNotified = false;
|
|
137
144
|
/** The AS base URL this client talks to (for provenance records). */
|
|
138
145
|
get url() {
|
|
139
146
|
return this.baseUrl;
|
|
@@ -143,6 +150,29 @@ var SPClient = class {
|
|
|
143
150
|
}
|
|
144
151
|
setSessionCookie(cookie) {
|
|
145
152
|
this.sessionCookie = cookie;
|
|
153
|
+
this.lockReason = null;
|
|
154
|
+
this.sessionExpiredNotified = false;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Drop the session because the control plane learned (by whatever path —
|
|
158
|
+
* one of OUR calls 401ing, its own AS proxy 401ing, or an AS key mismatch)
|
|
159
|
+
* that it ended. Idempotent: safe to call redundantly from the
|
|
160
|
+
* control-plane's push.
|
|
161
|
+
*
|
|
162
|
+
* @param reason Defaults to 'expired' for the original caller (a 401 really
|
|
163
|
+
* does mean the session ended) — but the control plane's own lock
|
|
164
|
+
* procedures (session-lock.ts) know the REAL reason and must pass it, or
|
|
165
|
+
* an agent told "your sign-in ended, sign in again" for an AS key
|
|
166
|
+
* mismatch would be sent to a sign-in that is itself refused.
|
|
167
|
+
*/
|
|
168
|
+
clearSession(reason = "expired") {
|
|
169
|
+
this.sessionCookie = "";
|
|
170
|
+
this.lockReason = reason;
|
|
171
|
+
}
|
|
172
|
+
/** Why we are currently locked, if known. `null` means the default
|
|
173
|
+
* boot-locked case (nobody has signed in yet this run). */
|
|
174
|
+
getLockReason() {
|
|
175
|
+
return this.sessionCookie === "" ? this.lockReason : null;
|
|
146
176
|
}
|
|
147
177
|
/**
|
|
148
178
|
* Has anyone signed in yet this run?
|
|
@@ -174,10 +204,20 @@ var SPClient = class {
|
|
|
174
204
|
if (this.apiKey) {
|
|
175
205
|
headers["X-API-Key"] = this.apiKey;
|
|
176
206
|
}
|
|
177
|
-
|
|
207
|
+
const hadSession = this.sessionCookie !== "";
|
|
208
|
+
const res = await globalThis.fetch(url, {
|
|
178
209
|
...init,
|
|
179
210
|
headers
|
|
180
211
|
});
|
|
212
|
+
if (res.status === 401 && hadSession) {
|
|
213
|
+
this.sessionCookie = "";
|
|
214
|
+
this.lockReason = "expired";
|
|
215
|
+
if (!this.sessionExpiredNotified) {
|
|
216
|
+
this.sessionExpiredNotified = true;
|
|
217
|
+
void notifyControlPlane("session-expired");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return res;
|
|
181
221
|
}
|
|
182
222
|
/**
|
|
183
223
|
* Get SP public key.
|
|
@@ -331,13 +371,52 @@ var SPClient = class {
|
|
|
331
371
|
|
|
332
372
|
// src/lib/attestation-cache.ts
|
|
333
373
|
import { decodeAttestationBlob } from "@hap/core";
|
|
374
|
+
|
|
375
|
+
// src/lib/as-pairing.ts
|
|
376
|
+
import { createHash } from "crypto";
|
|
377
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
|
|
378
|
+
import { dirname, join as join2 } from "path";
|
|
379
|
+
function pairingPath(dataDir2) {
|
|
380
|
+
return join2(dataDir2, "as-pairing.json");
|
|
381
|
+
}
|
|
382
|
+
function readPairing(dataDir2) {
|
|
383
|
+
const path = pairingPath(dataDir2);
|
|
384
|
+
if (!existsSync2(path)) return null;
|
|
385
|
+
try {
|
|
386
|
+
const data = JSON.parse(readFileSync2(path, "utf-8"));
|
|
387
|
+
if (typeof data.asUrl !== "string" || typeof data.publicKeyHex !== "string") return null;
|
|
388
|
+
return { asUrl: data.asUrl, publicKeyHex: data.publicKeyHex, pairedAt: data.pairedAt ?? "" };
|
|
389
|
+
} catch {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function fingerprintOf(publicKeyHex) {
|
|
394
|
+
const raw = Buffer.from(publicKeyHex, "hex");
|
|
395
|
+
const digest = createHash("sha256").update(raw).digest("hex").toUpperCase();
|
|
396
|
+
return digest.match(/.{1,4}/g)?.join(":") ?? digest;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/lib/attestation-cache.ts
|
|
400
|
+
var AsKeyMismatchError = class extends Error {
|
|
401
|
+
constructor(message) {
|
|
402
|
+
super(message);
|
|
403
|
+
this.name = "AsKeyMismatchError";
|
|
404
|
+
}
|
|
405
|
+
};
|
|
334
406
|
function isCommitmentDowngrade(auth) {
|
|
335
407
|
const requiresReview = auth.signedCommitmentMode === "review" || auth.signedCommitmentMode === "review_above_cap";
|
|
336
408
|
return requiresReview && (auth.deferredCommitmentDomains ?? []).length === 0;
|
|
337
409
|
}
|
|
338
410
|
var AttestationCache = class {
|
|
339
|
-
|
|
411
|
+
/**
|
|
412
|
+
* @param dataDir Where to look for a pinned key (as-pairing.json). Optional
|
|
413
|
+
* and defaults to "no pin enforced" — kept optional so existing
|
|
414
|
+
* constructions (and this class's own unit tests) that pass only an
|
|
415
|
+
* SPClient keep working unpinned, exactly as before pinning existed.
|
|
416
|
+
*/
|
|
417
|
+
constructor(spClient, dataDir2) {
|
|
340
418
|
this.spClient = spClient;
|
|
419
|
+
this.dataDir = dataDir2;
|
|
341
420
|
}
|
|
342
421
|
spPublicKey = null;
|
|
343
422
|
spPublicKeyFetchedAt = 0;
|
|
@@ -347,15 +426,29 @@ var AttestationCache = class {
|
|
|
347
426
|
authorizations = /* @__PURE__ */ new Map();
|
|
348
427
|
lastSync = 0;
|
|
349
428
|
/**
|
|
350
|
-
* Get the SP public key, fetching from SP if not cached or expired
|
|
429
|
+
* Get the SP public key, fetching from SP if not cached or expired, then —
|
|
430
|
+
* when a pin exists for this exact AS URL — verifying the live key still
|
|
431
|
+
* matches it.
|
|
432
|
+
*
|
|
433
|
+
* Trust-on-first-use before any pairing exists (or when no `dataDir` was
|
|
434
|
+
* given): the fetched key is cached and returned, same as before pinning.
|
|
435
|
+
* Once paired, a live key that differs from the pin throws
|
|
436
|
+
* {@link AsKeyMismatchError} — fail closed, never silently re-pin.
|
|
351
437
|
*/
|
|
352
438
|
async getPublicKey() {
|
|
353
439
|
const now = Math.floor(Date.now() / 1e3);
|
|
354
|
-
if (this.spPublicKey && now - this.spPublicKeyFetchedAt < this.SP_PUBKEY_TTL) {
|
|
355
|
-
|
|
440
|
+
if (!(this.spPublicKey && now - this.spPublicKeyFetchedAt < this.SP_PUBKEY_TTL)) {
|
|
441
|
+
this.spPublicKey = await this.spClient.getPublicKey();
|
|
442
|
+
this.spPublicKeyFetchedAt = now;
|
|
443
|
+
}
|
|
444
|
+
if (this.dataDir) {
|
|
445
|
+
const pin = readPairing(this.dataDir);
|
|
446
|
+
if (pin && pin.asUrl === this.spClient.url && pin.publicKeyHex !== this.spPublicKey) {
|
|
447
|
+
throw new AsKeyMismatchError(
|
|
448
|
+
`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.`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
356
451
|
}
|
|
357
|
-
this.spPublicKey = await this.spClient.getPublicKey();
|
|
358
|
-
this.spPublicKeyFetchedAt = now;
|
|
359
452
|
return this.spPublicKey;
|
|
360
453
|
}
|
|
361
454
|
/**
|
|
@@ -465,18 +558,18 @@ var AttestationCache = class {
|
|
|
465
558
|
};
|
|
466
559
|
|
|
467
560
|
// src/lib/gate-store.ts
|
|
468
|
-
import { mkdirSync, readFileSync as
|
|
561
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
469
562
|
import { homedir } from "os";
|
|
470
|
-
import { dirname, join as
|
|
563
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
471
564
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
472
|
-
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
565
|
+
var DEFAULT_DIR = process.env.SUVEREN_DATA_DIR ?? join3(homedir(), ".suveren");
|
|
473
566
|
var GateStore = class {
|
|
474
567
|
entries = /* @__PURE__ */ new Map();
|
|
475
568
|
baseDir;
|
|
476
569
|
vaultKey = null;
|
|
477
570
|
constructor(filePath) {
|
|
478
571
|
if (filePath && filePath.endsWith(".json")) {
|
|
479
|
-
this.baseDir =
|
|
572
|
+
this.baseDir = dirname2(filePath);
|
|
480
573
|
} else {
|
|
481
574
|
this.baseDir = filePath ?? DEFAULT_DIR;
|
|
482
575
|
}
|
|
@@ -487,13 +580,13 @@ var GateStore = class {
|
|
|
487
580
|
*/
|
|
488
581
|
setVaultKey(key) {
|
|
489
582
|
this.vaultKey = key;
|
|
490
|
-
if (
|
|
583
|
+
if (existsSync3(this.encryptedFilePath)) {
|
|
491
584
|
this.loadEncrypted();
|
|
492
585
|
} else if (this.entries.size > 0) {
|
|
493
586
|
this.persistEncrypted();
|
|
494
|
-
if (
|
|
587
|
+
if (existsSync3(this.plaintextFilePath)) {
|
|
495
588
|
try {
|
|
496
|
-
|
|
589
|
+
unlinkSync2(this.plaintextFilePath);
|
|
497
590
|
} catch {
|
|
498
591
|
}
|
|
499
592
|
}
|
|
@@ -513,6 +606,30 @@ var GateStore = class {
|
|
|
513
606
|
this.entries.delete(path);
|
|
514
607
|
this.persist();
|
|
515
608
|
}
|
|
609
|
+
/**
|
|
610
|
+
* Wipe every locally cached gate. Used when the Authority Server this
|
|
611
|
+
* gateway points at changes (re-pairing, see as-pairing.ts): a stored
|
|
612
|
+
* authorization id and its intent/context are meaningless against a
|
|
613
|
+
* different AS's grants, and keeping them around risks a `getAll()` caller
|
|
614
|
+
* (e.g. list-authorizations) advertising authority that no longer exists.
|
|
615
|
+
*
|
|
616
|
+
* Removes BOTH the plaintext and encrypted files, not just the one
|
|
617
|
+
* currently active — this runs at boot, before any vault key is set, so
|
|
618
|
+
* `persist()` would otherwise only touch `gates.json` and leave a stale
|
|
619
|
+
* `gates.enc.json` in place for `setVaultKey()` to resurrect on the next
|
|
620
|
+
* unlock.
|
|
621
|
+
*/
|
|
622
|
+
clearAll() {
|
|
623
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
624
|
+
try {
|
|
625
|
+
if (existsSync3(this.plaintextFilePath)) unlinkSync2(this.plaintextFilePath);
|
|
626
|
+
} catch {
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
if (existsSync3(this.encryptedFilePath)) unlinkSync2(this.encryptedFilePath);
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
}
|
|
516
633
|
// ─── Encryption helpers ─────────────────────────────────────────────────
|
|
517
634
|
encrypt(plaintext) {
|
|
518
635
|
if (!this.vaultKey) throw new Error("No vault key");
|
|
@@ -542,19 +659,19 @@ var GateStore = class {
|
|
|
542
659
|
}
|
|
543
660
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
544
661
|
get plaintextFilePath() {
|
|
545
|
-
return
|
|
662
|
+
return join3(this.baseDir, "gates.json");
|
|
546
663
|
}
|
|
547
664
|
get encryptedFilePath() {
|
|
548
|
-
return
|
|
665
|
+
return join3(this.baseDir, "gates.enc.json");
|
|
549
666
|
}
|
|
550
667
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
551
668
|
loadPlaintext() {
|
|
552
|
-
if (!
|
|
553
|
-
|
|
669
|
+
if (!existsSync3(this.plaintextFilePath)) {
|
|
670
|
+
mkdirSync2(this.baseDir, { recursive: true });
|
|
554
671
|
return;
|
|
555
672
|
}
|
|
556
673
|
try {
|
|
557
|
-
const raw =
|
|
674
|
+
const raw = readFileSync3(this.plaintextFilePath, "utf-8");
|
|
558
675
|
const data = JSON.parse(raw);
|
|
559
676
|
this.entries = new Map(Object.entries(data.entries));
|
|
560
677
|
} catch {
|
|
@@ -563,9 +680,9 @@ var GateStore = class {
|
|
|
563
680
|
}
|
|
564
681
|
}
|
|
565
682
|
loadEncrypted() {
|
|
566
|
-
if (!
|
|
683
|
+
if (!existsSync3(this.encryptedFilePath)) return;
|
|
567
684
|
try {
|
|
568
|
-
const raw =
|
|
685
|
+
const raw = readFileSync3(this.encryptedFilePath, "utf-8");
|
|
569
686
|
const data = JSON.parse(raw);
|
|
570
687
|
this.entries = /* @__PURE__ */ new Map();
|
|
571
688
|
for (const [key, blob] of Object.entries(data.entries)) {
|
|
@@ -589,8 +706,8 @@ var GateStore = class {
|
|
|
589
706
|
version: 1,
|
|
590
707
|
entries: Object.fromEntries(this.entries)
|
|
591
708
|
};
|
|
592
|
-
|
|
593
|
-
|
|
709
|
+
mkdirSync2(this.baseDir, { recursive: true, mode: 448 });
|
|
710
|
+
writeFileSync2(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
594
711
|
}
|
|
595
712
|
persistEncrypted() {
|
|
596
713
|
const data = {
|
|
@@ -600,17 +717,17 @@ var GateStore = class {
|
|
|
600
717
|
for (const [key, entry] of this.entries) {
|
|
601
718
|
data.entries[key] = this.encrypt(JSON.stringify(entry));
|
|
602
719
|
}
|
|
603
|
-
|
|
604
|
-
|
|
720
|
+
mkdirSync2(this.baseDir, { recursive: true, mode: 448 });
|
|
721
|
+
writeFileSync2(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
605
722
|
}
|
|
606
723
|
};
|
|
607
724
|
|
|
608
725
|
// src/lib/execution-log.ts
|
|
609
|
-
import { mkdirSync as
|
|
726
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
610
727
|
import { homedir as homedir2 } from "os";
|
|
611
|
-
import { dirname as
|
|
728
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
612
729
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
613
|
-
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
730
|
+
var DEFAULT_DIR2 = process.env.SUVEREN_DATA_DIR ?? join4(homedir2(), ".suveren");
|
|
614
731
|
var MAX_AGE_SECONDS = 31 * 24 * 60 * 60;
|
|
615
732
|
var ExecutionLog = class {
|
|
616
733
|
entries = [];
|
|
@@ -618,7 +735,7 @@ var ExecutionLog = class {
|
|
|
618
735
|
vaultKey = null;
|
|
619
736
|
constructor(filePath) {
|
|
620
737
|
if (filePath && filePath.endsWith(".json")) {
|
|
621
|
-
this.baseDir =
|
|
738
|
+
this.baseDir = dirname3(filePath);
|
|
622
739
|
} else {
|
|
623
740
|
this.baseDir = filePath ?? DEFAULT_DIR2;
|
|
624
741
|
}
|
|
@@ -629,13 +746,13 @@ var ExecutionLog = class {
|
|
|
629
746
|
*/
|
|
630
747
|
setVaultKey(key) {
|
|
631
748
|
this.vaultKey = key;
|
|
632
|
-
if (
|
|
749
|
+
if (existsSync4(this.encryptedFilePath)) {
|
|
633
750
|
this.loadEncrypted();
|
|
634
751
|
} else if (this.entries.length > 0) {
|
|
635
752
|
this.persistEncrypted();
|
|
636
|
-
if (
|
|
753
|
+
if (existsSync4(this.plaintextFilePath)) {
|
|
637
754
|
try {
|
|
638
|
-
|
|
755
|
+
unlinkSync3(this.plaintextFilePath);
|
|
639
756
|
} catch {
|
|
640
757
|
}
|
|
641
758
|
}
|
|
@@ -657,14 +774,23 @@ var ExecutionLog = class {
|
|
|
657
774
|
* @param field - The execution field to sum ("_count" for plain counting)
|
|
658
775
|
* @param window - Time window (daily, weekly, monthly)
|
|
659
776
|
* @param now - Current timestamp in seconds (for testing)
|
|
777
|
+
* @param actionTypes - Only count entries whose `execution.action_type` is one
|
|
778
|
+
* of these (omitted → all). Consumption is partitioned by action type, as at
|
|
779
|
+
* the Authority Server: without it, the usage shown for sales' "orders per
|
|
780
|
+
* day" counted every quote and send. An entry with no action_type counts against every filter —
|
|
781
|
+
* an unknown action is not evidence of headroom.
|
|
660
782
|
*/
|
|
661
|
-
sumByWindow(profileId, path, field, window, now = Math.floor(Date.now() / 1e3)) {
|
|
783
|
+
sumByWindow(profileId, path, field, window, now = Math.floor(Date.now() / 1e3), actionTypes) {
|
|
662
784
|
const cutoff = windowCutoff(window, now);
|
|
663
785
|
let total = 0;
|
|
664
786
|
for (const entry of this.entries) {
|
|
665
787
|
if (entry.profileId !== profileId) continue;
|
|
666
788
|
if (entry.path !== path) continue;
|
|
667
789
|
if (entry.timestamp < cutoff) continue;
|
|
790
|
+
if (actionTypes) {
|
|
791
|
+
const at = entry.execution.action_type;
|
|
792
|
+
if (typeof at === "string" && !actionTypes.includes(at)) continue;
|
|
793
|
+
}
|
|
668
794
|
if (field === "_count") {
|
|
669
795
|
total += 1;
|
|
670
796
|
} else {
|
|
@@ -728,19 +854,19 @@ var ExecutionLog = class {
|
|
|
728
854
|
}
|
|
729
855
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
730
856
|
get plaintextFilePath() {
|
|
731
|
-
return
|
|
857
|
+
return join4(this.baseDir, "execution-log.json");
|
|
732
858
|
}
|
|
733
859
|
get encryptedFilePath() {
|
|
734
|
-
return
|
|
860
|
+
return join4(this.baseDir, "execution-log.enc.json");
|
|
735
861
|
}
|
|
736
862
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
737
863
|
loadPlaintext() {
|
|
738
|
-
if (!
|
|
739
|
-
|
|
864
|
+
if (!existsSync4(this.plaintextFilePath)) {
|
|
865
|
+
mkdirSync3(this.baseDir, { recursive: true });
|
|
740
866
|
return;
|
|
741
867
|
}
|
|
742
868
|
try {
|
|
743
|
-
const raw =
|
|
869
|
+
const raw = readFileSync4(this.plaintextFilePath, "utf-8");
|
|
744
870
|
const data = JSON.parse(raw);
|
|
745
871
|
this.entries = data.entries;
|
|
746
872
|
this.prune();
|
|
@@ -750,9 +876,9 @@ var ExecutionLog = class {
|
|
|
750
876
|
}
|
|
751
877
|
}
|
|
752
878
|
loadEncrypted() {
|
|
753
|
-
if (!
|
|
879
|
+
if (!existsSync4(this.encryptedFilePath)) return;
|
|
754
880
|
try {
|
|
755
|
-
const raw =
|
|
881
|
+
const raw = readFileSync4(this.encryptedFilePath, "utf-8");
|
|
756
882
|
const data = JSON.parse(raw);
|
|
757
883
|
const decrypted = this.decrypt(data.blob);
|
|
758
884
|
const logFile = JSON.parse(decrypted);
|
|
@@ -772,8 +898,8 @@ var ExecutionLog = class {
|
|
|
772
898
|
}
|
|
773
899
|
persistPlaintext() {
|
|
774
900
|
const data = { version: 1, entries: this.entries };
|
|
775
|
-
|
|
776
|
-
|
|
901
|
+
mkdirSync3(this.baseDir, { recursive: true, mode: 448 });
|
|
902
|
+
writeFileSync3(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
777
903
|
}
|
|
778
904
|
persistEncrypted() {
|
|
779
905
|
const logFile = { version: 1, entries: this.entries };
|
|
@@ -781,8 +907,8 @@ var ExecutionLog = class {
|
|
|
781
907
|
version: 1,
|
|
782
908
|
blob: this.encrypt(JSON.stringify(logFile))
|
|
783
909
|
};
|
|
784
|
-
|
|
785
|
-
|
|
910
|
+
mkdirSync3(this.baseDir, { recursive: true, mode: 448 });
|
|
911
|
+
writeFileSync3(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
786
912
|
}
|
|
787
913
|
};
|
|
788
914
|
function windowCutoff(window, now) {
|
|
@@ -799,11 +925,11 @@ function windowCutoff(window, now) {
|
|
|
799
925
|
}
|
|
800
926
|
|
|
801
927
|
// src/lib/denial-log.ts
|
|
802
|
-
import { mkdirSync as
|
|
928
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
803
929
|
import { homedir as homedir3 } from "os";
|
|
804
|
-
import { dirname as
|
|
930
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
805
931
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes3 } from "crypto";
|
|
806
|
-
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ??
|
|
932
|
+
var DEFAULT_DIR3 = process.env.SUVEREN_DATA_DIR ?? join5(homedir3(), ".suveren");
|
|
807
933
|
var MAX_RECORDS = 200;
|
|
808
934
|
var MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
809
935
|
var DenialLog = class {
|
|
@@ -811,18 +937,18 @@ var DenialLog = class {
|
|
|
811
937
|
baseDir;
|
|
812
938
|
vaultKey = null;
|
|
813
939
|
constructor(filePath) {
|
|
814
|
-
this.baseDir = filePath && filePath.endsWith(".json") ?
|
|
940
|
+
this.baseDir = filePath && filePath.endsWith(".json") ? dirname4(filePath) : filePath ?? DEFAULT_DIR3;
|
|
815
941
|
this.loadPlaintext();
|
|
816
942
|
}
|
|
817
943
|
setVaultKey(key) {
|
|
818
944
|
this.vaultKey = key;
|
|
819
|
-
if (
|
|
945
|
+
if (existsSync5(this.encryptedFilePath)) {
|
|
820
946
|
this.loadEncrypted();
|
|
821
947
|
} else if (this.records.length > 0) {
|
|
822
948
|
this.persistEncrypted();
|
|
823
|
-
if (
|
|
949
|
+
if (existsSync5(this.plaintextFilePath)) {
|
|
824
950
|
try {
|
|
825
|
-
|
|
951
|
+
unlinkSync4(this.plaintextFilePath);
|
|
826
952
|
} catch {
|
|
827
953
|
}
|
|
828
954
|
}
|
|
@@ -870,18 +996,18 @@ var DenialLog = class {
|
|
|
870
996
|
return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, "hex")), decipher.final()]).toString("utf8");
|
|
871
997
|
}
|
|
872
998
|
get plaintextFilePath() {
|
|
873
|
-
return
|
|
999
|
+
return join5(this.baseDir, "denials.json");
|
|
874
1000
|
}
|
|
875
1001
|
get encryptedFilePath() {
|
|
876
|
-
return
|
|
1002
|
+
return join5(this.baseDir, "denials.enc.json");
|
|
877
1003
|
}
|
|
878
1004
|
loadPlaintext() {
|
|
879
|
-
if (!
|
|
880
|
-
|
|
1005
|
+
if (!existsSync5(this.plaintextFilePath)) {
|
|
1006
|
+
mkdirSync4(this.baseDir, { recursive: true });
|
|
881
1007
|
return;
|
|
882
1008
|
}
|
|
883
1009
|
try {
|
|
884
|
-
const data = JSON.parse(
|
|
1010
|
+
const data = JSON.parse(readFileSync5(this.plaintextFilePath, "utf-8"));
|
|
885
1011
|
this.records = data.records ?? [];
|
|
886
1012
|
} catch {
|
|
887
1013
|
console.error(`[DenialLog] Could not parse ${this.plaintextFilePath}, starting fresh`);
|
|
@@ -889,9 +1015,9 @@ var DenialLog = class {
|
|
|
889
1015
|
}
|
|
890
1016
|
}
|
|
891
1017
|
loadEncrypted() {
|
|
892
|
-
if (!
|
|
1018
|
+
if (!existsSync5(this.encryptedFilePath)) return;
|
|
893
1019
|
try {
|
|
894
|
-
const data = JSON.parse(
|
|
1020
|
+
const data = JSON.parse(readFileSync5(this.encryptedFilePath, "utf-8"));
|
|
895
1021
|
const logFile = JSON.parse(this.decrypt(data.blob));
|
|
896
1022
|
this.records = logFile.records ?? [];
|
|
897
1023
|
} catch (err) {
|
|
@@ -905,23 +1031,23 @@ var DenialLog = class {
|
|
|
905
1031
|
}
|
|
906
1032
|
persistPlaintext() {
|
|
907
1033
|
const data = { version: 1, records: this.records };
|
|
908
|
-
|
|
909
|
-
|
|
1034
|
+
mkdirSync4(this.baseDir, { recursive: true, mode: 448 });
|
|
1035
|
+
writeFileSync4(this.plaintextFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
910
1036
|
}
|
|
911
1037
|
persistEncrypted() {
|
|
912
1038
|
const logFile = { version: 1, records: this.records };
|
|
913
1039
|
const data = { version: 1, blob: this.encrypt(JSON.stringify(logFile)) };
|
|
914
|
-
|
|
915
|
-
|
|
1040
|
+
mkdirSync4(this.baseDir, { recursive: true, mode: 448 });
|
|
1041
|
+
writeFileSync4(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
916
1042
|
}
|
|
917
1043
|
};
|
|
918
1044
|
|
|
919
1045
|
// src/lib/receipt-archive.ts
|
|
920
|
-
import { mkdirSync as
|
|
1046
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
921
1047
|
import { homedir as homedir4 } from "os";
|
|
922
|
-
import { dirname as
|
|
1048
|
+
import { dirname as dirname5, join as join6 } from "path";
|
|
923
1049
|
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes4 } from "crypto";
|
|
924
|
-
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ??
|
|
1050
|
+
var DEFAULT_DIR4 = process.env.SUVEREN_DATA_DIR ?? join6(homedir4(), ".suveren");
|
|
925
1051
|
function stripPreviews(proposal) {
|
|
926
1052
|
const args = proposal.toolArgs;
|
|
927
1053
|
if (!args || typeof args !== "object") return proposal;
|
|
@@ -935,7 +1061,7 @@ var ReceiptArchive = class {
|
|
|
935
1061
|
vaultKey = null;
|
|
936
1062
|
constructor(filePath) {
|
|
937
1063
|
if (filePath && filePath.endsWith(".json")) {
|
|
938
|
-
this.baseDir =
|
|
1064
|
+
this.baseDir = dirname5(filePath);
|
|
939
1065
|
} else {
|
|
940
1066
|
this.baseDir = filePath ?? DEFAULT_DIR4;
|
|
941
1067
|
}
|
|
@@ -946,13 +1072,13 @@ var ReceiptArchive = class {
|
|
|
946
1072
|
*/
|
|
947
1073
|
setVaultKey(key) {
|
|
948
1074
|
this.vaultKey = key;
|
|
949
|
-
if (
|
|
1075
|
+
if (existsSync6(this.encryptedFilePath)) {
|
|
950
1076
|
this.loadEncrypted();
|
|
951
1077
|
} else if (this.data.receipts.length > 0 || Object.keys(this.data.authorizations).length > 0) {
|
|
952
1078
|
this.persistEncrypted();
|
|
953
|
-
if (
|
|
1079
|
+
if (existsSync6(this.plaintextFilePath)) {
|
|
954
1080
|
try {
|
|
955
|
-
|
|
1081
|
+
unlinkSync5(this.plaintextFilePath);
|
|
956
1082
|
} catch {
|
|
957
1083
|
}
|
|
958
1084
|
}
|
|
@@ -964,7 +1090,7 @@ var ReceiptArchive = class {
|
|
|
964
1090
|
* this state — that would report a hollow success over unreadable evidence.
|
|
965
1091
|
*/
|
|
966
1092
|
isLocked() {
|
|
967
|
-
return this.vaultKey === null &&
|
|
1093
|
+
return this.vaultKey === null && existsSync6(this.encryptedFilePath);
|
|
968
1094
|
}
|
|
969
1095
|
/**
|
|
970
1096
|
* Archive a signed receipt (and the grant it was issued under).
|
|
@@ -1065,19 +1191,19 @@ var ReceiptArchive = class {
|
|
|
1065
1191
|
}
|
|
1066
1192
|
// ─── File paths ─────────────────────────────────────────────────────────
|
|
1067
1193
|
get plaintextFilePath() {
|
|
1068
|
-
return
|
|
1194
|
+
return join6(this.baseDir, "receipt-archive.json");
|
|
1069
1195
|
}
|
|
1070
1196
|
get encryptedFilePath() {
|
|
1071
|
-
return
|
|
1197
|
+
return join6(this.baseDir, "receipt-archive.enc.json");
|
|
1072
1198
|
}
|
|
1073
1199
|
// ─── Load / Persist ─────────────────────────────────────────────────────
|
|
1074
1200
|
loadPlaintext() {
|
|
1075
|
-
if (!
|
|
1076
|
-
|
|
1201
|
+
if (!existsSync6(this.plaintextFilePath)) {
|
|
1202
|
+
mkdirSync5(this.baseDir, { recursive: true });
|
|
1077
1203
|
return;
|
|
1078
1204
|
}
|
|
1079
1205
|
try {
|
|
1080
|
-
const raw =
|
|
1206
|
+
const raw = readFileSync6(this.plaintextFilePath, "utf-8");
|
|
1081
1207
|
const parsed = JSON.parse(raw);
|
|
1082
1208
|
this.data = {
|
|
1083
1209
|
version: 1,
|
|
@@ -1087,18 +1213,18 @@ var ReceiptArchive = class {
|
|
|
1087
1213
|
} catch {
|
|
1088
1214
|
console.error(`[ReceiptArchive] Could not parse ${this.plaintextFilePath} \u2014 preserving as .corrupt`);
|
|
1089
1215
|
try {
|
|
1090
|
-
|
|
1216
|
+
writeFileSync5(
|
|
1091
1217
|
`${this.plaintextFilePath}.corrupt-${Date.now()}`,
|
|
1092
|
-
|
|
1218
|
+
readFileSync6(this.plaintextFilePath)
|
|
1093
1219
|
);
|
|
1094
1220
|
} catch {
|
|
1095
1221
|
}
|
|
1096
1222
|
}
|
|
1097
1223
|
}
|
|
1098
1224
|
loadEncrypted() {
|
|
1099
|
-
if (!
|
|
1225
|
+
if (!existsSync6(this.encryptedFilePath)) return;
|
|
1100
1226
|
try {
|
|
1101
|
-
const raw =
|
|
1227
|
+
const raw = readFileSync6(this.encryptedFilePath, "utf-8");
|
|
1102
1228
|
const data = JSON.parse(raw);
|
|
1103
1229
|
const decrypted = this.decrypt(data.blob);
|
|
1104
1230
|
const parsed = JSON.parse(decrypted);
|
|
@@ -1110,9 +1236,9 @@ var ReceiptArchive = class {
|
|
|
1110
1236
|
} catch (err) {
|
|
1111
1237
|
console.error(`[ReceiptArchive] Could not decrypt ${this.encryptedFilePath} \u2014 preserving as .corrupt:`, err);
|
|
1112
1238
|
try {
|
|
1113
|
-
|
|
1239
|
+
writeFileSync5(
|
|
1114
1240
|
`${this.encryptedFilePath}.corrupt-${Date.now()}`,
|
|
1115
|
-
|
|
1241
|
+
readFileSync6(this.encryptedFilePath)
|
|
1116
1242
|
);
|
|
1117
1243
|
} catch {
|
|
1118
1244
|
}
|
|
@@ -1126,29 +1252,29 @@ var ReceiptArchive = class {
|
|
|
1126
1252
|
}
|
|
1127
1253
|
}
|
|
1128
1254
|
persistPlaintext() {
|
|
1129
|
-
|
|
1130
|
-
|
|
1255
|
+
mkdirSync5(this.baseDir, { recursive: true, mode: 448 });
|
|
1256
|
+
writeFileSync5(this.plaintextFilePath, JSON.stringify(this.data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1131
1257
|
}
|
|
1132
1258
|
persistEncrypted() {
|
|
1133
1259
|
const data = {
|
|
1134
1260
|
version: 1,
|
|
1135
1261
|
blob: this.encrypt(JSON.stringify(this.data))
|
|
1136
1262
|
};
|
|
1137
|
-
|
|
1138
|
-
|
|
1263
|
+
mkdirSync5(this.baseDir, { recursive: true, mode: 448 });
|
|
1264
|
+
writeFileSync5(this.encryptedFilePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1139
1265
|
}
|
|
1140
1266
|
};
|
|
1141
1267
|
|
|
1142
1268
|
// src/lib/execution-journal.ts
|
|
1143
|
-
import { mkdirSync as
|
|
1269
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync7, renameSync } from "fs";
|
|
1144
1270
|
import { homedir as homedir5 } from "os";
|
|
1145
|
-
import { dirname as
|
|
1146
|
-
import { createHash } from "crypto";
|
|
1147
|
-
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ??
|
|
1271
|
+
import { dirname as dirname6, join as join7 } from "path";
|
|
1272
|
+
import { createHash as createHash2 } from "crypto";
|
|
1273
|
+
var DEFAULT_DIR5 = process.env.SUVEREN_DATA_DIR ?? join7(homedir5(), ".suveren");
|
|
1148
1274
|
var FILE_NAME = "execution-journal.json";
|
|
1149
1275
|
var MAX_AGE_SECONDS2 = 90 * 24 * 60 * 60;
|
|
1150
1276
|
function hashToolArgs(args) {
|
|
1151
|
-
return "sha256:" +
|
|
1277
|
+
return "sha256:" + createHash2("sha256").update(stableStringify(args)).digest("hex");
|
|
1152
1278
|
}
|
|
1153
1279
|
function stableStringify(value) {
|
|
1154
1280
|
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
|
|
@@ -1160,8 +1286,8 @@ function stableStringify(value) {
|
|
|
1160
1286
|
var ExecutionJournal = class {
|
|
1161
1287
|
filePath;
|
|
1162
1288
|
constructor(filePath) {
|
|
1163
|
-
const baseDir = filePath && filePath.endsWith(".json") ?
|
|
1164
|
-
this.filePath =
|
|
1289
|
+
const baseDir = filePath && filePath.endsWith(".json") ? dirname6(filePath) : filePath ?? DEFAULT_DIR5;
|
|
1290
|
+
this.filePath = join7(baseDir, FILE_NAME);
|
|
1165
1291
|
}
|
|
1166
1292
|
/** Look a ticket up. Always reads from disk — another process may have written. */
|
|
1167
1293
|
get(ticketId) {
|
|
@@ -1200,9 +1326,9 @@ var ExecutionJournal = class {
|
|
|
1200
1326
|
}
|
|
1201
1327
|
// ─── Persistence ────────────────────────────────────────────────────────
|
|
1202
1328
|
load() {
|
|
1203
|
-
if (!
|
|
1329
|
+
if (!existsSync7(this.filePath)) return { version: 1, entries: [] };
|
|
1204
1330
|
try {
|
|
1205
|
-
const parsed = JSON.parse(
|
|
1331
|
+
const parsed = JSON.parse(readFileSync7(this.filePath, "utf8"));
|
|
1206
1332
|
if (parsed?.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
1207
1333
|
throw new Error("unexpected shape");
|
|
1208
1334
|
}
|
|
@@ -1216,9 +1342,9 @@ var ExecutionJournal = class {
|
|
|
1216
1342
|
persist(file) {
|
|
1217
1343
|
const cutoff = nowSec() - MAX_AGE_SECONDS2;
|
|
1218
1344
|
file.entries = file.entries.filter((e) => e.startedAt >= cutoff);
|
|
1219
|
-
|
|
1345
|
+
mkdirSync6(dirname6(this.filePath), { recursive: true, mode: 448 });
|
|
1220
1346
|
const tmp = this.filePath + ".tmp";
|
|
1221
|
-
|
|
1347
|
+
writeFileSync6(tmp, JSON.stringify(file, null, 2), { mode: 384 });
|
|
1222
1348
|
renameSync(tmp, this.filePath);
|
|
1223
1349
|
}
|
|
1224
1350
|
};
|
|
@@ -1226,6 +1352,61 @@ function nowSec() {
|
|
|
1226
1352
|
return Math.floor(Date.now() / 1e3);
|
|
1227
1353
|
}
|
|
1228
1354
|
|
|
1355
|
+
// src/lib/proposal-submission-store.ts
|
|
1356
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync8, renameSync as renameSync2 } from "fs";
|
|
1357
|
+
import { homedir as homedir6 } from "os";
|
|
1358
|
+
import { dirname as dirname7, join as join8 } from "path";
|
|
1359
|
+
var DEFAULT_DIR6 = process.env.SUVEREN_DATA_DIR ?? join8(homedir6(), ".suveren");
|
|
1360
|
+
var FILE_NAME2 = "proposal-submissions.json";
|
|
1361
|
+
var MAX_AGE_SECONDS3 = 90 * 24 * 60 * 60;
|
|
1362
|
+
function nowSec2() {
|
|
1363
|
+
return Math.floor(Date.now() / 1e3);
|
|
1364
|
+
}
|
|
1365
|
+
var ProposalSubmissionStore = class {
|
|
1366
|
+
filePath;
|
|
1367
|
+
constructor(filePath) {
|
|
1368
|
+
const baseDir = filePath && filePath.endsWith(".json") ? dirname7(filePath) : filePath ?? DEFAULT_DIR6;
|
|
1369
|
+
this.filePath = join8(baseDir, FILE_NAME2);
|
|
1370
|
+
}
|
|
1371
|
+
/** Record what was submitted, right after a successful submitProposal(). */
|
|
1372
|
+
record(entry) {
|
|
1373
|
+
const file = this.load();
|
|
1374
|
+
file.entries = file.entries.filter((e) => e.proposalId !== entry.proposalId);
|
|
1375
|
+
file.entries.push({
|
|
1376
|
+
proposalId: entry.proposalId,
|
|
1377
|
+
tool: entry.tool,
|
|
1378
|
+
toolArgsHash: hashToolArgs(entry.toolArgs),
|
|
1379
|
+
executionContextHash: hashToolArgs(entry.executionContext),
|
|
1380
|
+
authorizationId: entry.authorizationId,
|
|
1381
|
+
profileId: entry.profileId,
|
|
1382
|
+
submittedAt: nowSec2()
|
|
1383
|
+
});
|
|
1384
|
+
this.persist(file);
|
|
1385
|
+
}
|
|
1386
|
+
/** Always reads from disk — another process (the poll loop lives in the
|
|
1387
|
+
* same process, but this stays consistent with execution-journal.ts). */
|
|
1388
|
+
get(proposalId) {
|
|
1389
|
+
return this.load().entries.find((e) => e.proposalId === proposalId);
|
|
1390
|
+
}
|
|
1391
|
+
load() {
|
|
1392
|
+
if (!existsSync8(this.filePath)) return { version: 1, entries: [] };
|
|
1393
|
+
try {
|
|
1394
|
+
const parsed = JSON.parse(readFileSync8(this.filePath, "utf-8"));
|
|
1395
|
+
const cutoff = nowSec2() - MAX_AGE_SECONDS3;
|
|
1396
|
+
parsed.entries = (parsed.entries ?? []).filter((e) => e.submittedAt >= cutoff);
|
|
1397
|
+
return parsed;
|
|
1398
|
+
} catch {
|
|
1399
|
+
return { version: 1, entries: [] };
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
persist(file) {
|
|
1403
|
+
mkdirSync7(dirname7(this.filePath), { recursive: true, mode: 448 });
|
|
1404
|
+
const tmpPath = `${this.filePath}.tmp`;
|
|
1405
|
+
writeFileSync7(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1406
|
+
renameSync2(tmpPath, this.filePath);
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1229
1410
|
// src/lib/gatekeeper.ts
|
|
1230
1411
|
import { verify } from "@hap/core";
|
|
1231
1412
|
var MCPGatekeeper = class {
|
|
@@ -1276,7 +1457,26 @@ var MCPGatekeeper = class {
|
|
|
1276
1457
|
authorization: auth
|
|
1277
1458
|
};
|
|
1278
1459
|
}
|
|
1279
|
-
|
|
1460
|
+
let publicKeyHex;
|
|
1461
|
+
try {
|
|
1462
|
+
publicKeyHex = await this.cache.getPublicKey();
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
if (err instanceof AsKeyMismatchError) {
|
|
1465
|
+
void notifyControlPlane("as-key-mismatch");
|
|
1466
|
+
return {
|
|
1467
|
+
result: {
|
|
1468
|
+
approved: false,
|
|
1469
|
+
// No dedicated GatekeeperError code exists for this (hap-core's
|
|
1470
|
+
// union predates gateway-side key pinning) — INVALID_SIGNATURE is
|
|
1471
|
+
// the closest fit: it's exactly the claim being made here ("we
|
|
1472
|
+
// will not trust a signature made under this key").
|
|
1473
|
+
errors: [{ code: "INVALID_SIGNATURE", message: err.message }]
|
|
1474
|
+
},
|
|
1475
|
+
authorization: auth
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
throw err;
|
|
1479
|
+
}
|
|
1280
1480
|
const resolvedBounds = override?.bounds ?? auth.bounds ?? auth.frame;
|
|
1281
1481
|
const resolvedContext = override?.context ?? auth.context;
|
|
1282
1482
|
const frame = { ...resolvedBounds, profile: auth.profileId };
|
|
@@ -1308,15 +1508,25 @@ var SharedState = class {
|
|
|
1308
1508
|
receiptArchive;
|
|
1309
1509
|
/** Which tickets this Gatekeeper has executed — the "one execution per ticket" half of exactly-once. */
|
|
1310
1510
|
executionJournal;
|
|
1511
|
+
/** What THIS gateway submitted for each review-mode proposal it created —
|
|
1512
|
+
* see ticket-verify.ts / commitments.ts. */
|
|
1513
|
+
proposalSubmissions;
|
|
1311
1514
|
gatekeeper;
|
|
1312
|
-
|
|
1515
|
+
/**
|
|
1516
|
+
* @param dataDir Passed to the AttestationCache so it can enforce AS key
|
|
1517
|
+
* pinning (as-pairing.ts). Optional for backward compat with existing
|
|
1518
|
+
* constructions/tests that pass only a URL — those get unpinned
|
|
1519
|
+
* trust-on-first-use behavior, same as before pinning existed.
|
|
1520
|
+
*/
|
|
1521
|
+
constructor(spUrl2, gateStorePath, dataDir2) {
|
|
1313
1522
|
this.spClient = new SPClient(spUrl2);
|
|
1314
|
-
this.cache = new AttestationCache(this.spClient);
|
|
1523
|
+
this.cache = new AttestationCache(this.spClient, dataDir2);
|
|
1315
1524
|
this.gateStore = new GateStore(gateStorePath);
|
|
1316
1525
|
this.executionLog = new ExecutionLog(gateStorePath);
|
|
1317
1526
|
this.denialLog = new DenialLog(gateStorePath);
|
|
1318
1527
|
this.receiptArchive = new ReceiptArchive(gateStorePath);
|
|
1319
1528
|
this.executionJournal = new ExecutionJournal(gateStorePath);
|
|
1529
|
+
this.proposalSubmissions = new ProposalSubmissionStore(gateStorePath);
|
|
1320
1530
|
this.gatekeeper = new MCPGatekeeper(this.cache);
|
|
1321
1531
|
}
|
|
1322
1532
|
/**
|
|
@@ -1332,7 +1542,8 @@ var SharedState = class {
|
|
|
1332
1542
|
let asPublicKey;
|
|
1333
1543
|
try {
|
|
1334
1544
|
asPublicKey = await this.cache.getPublicKey();
|
|
1335
|
-
} catch {
|
|
1545
|
+
} catch (err) {
|
|
1546
|
+
if (err instanceof AsKeyMismatchError) throw err;
|
|
1336
1547
|
}
|
|
1337
1548
|
this.receiptArchive.record({
|
|
1338
1549
|
receipt,
|
|
@@ -1354,6 +1565,7 @@ var SharedState = class {
|
|
|
1354
1565
|
} : void 0
|
|
1355
1566
|
});
|
|
1356
1567
|
} catch (err) {
|
|
1568
|
+
if (err instanceof AsKeyMismatchError) throw err;
|
|
1357
1569
|
console.error(
|
|
1358
1570
|
"[Suveren MCP] Receipt archive write failed (execution proceeds \u2014 AS retains authoritative copy):",
|
|
1359
1571
|
err
|
|
@@ -1402,6 +1614,7 @@ import { z } from "zod";
|
|
|
1402
1614
|
import { getProfile } from "@hap/core";
|
|
1403
1615
|
|
|
1404
1616
|
// src/lib/consumption.ts
|
|
1617
|
+
import { boundActionTypes } from "@hap/core";
|
|
1405
1618
|
function getConsumptionState(auth, executionLog, profile) {
|
|
1406
1619
|
if (!profile?.boundsSchema?.fields) return [];
|
|
1407
1620
|
const entries = [];
|
|
@@ -1421,7 +1634,8 @@ function getConsumptionState(auth, executionLog, profile) {
|
|
|
1421
1634
|
auth.path,
|
|
1422
1635
|
cumulativeField,
|
|
1423
1636
|
bt.window,
|
|
1424
|
-
now
|
|
1637
|
+
now,
|
|
1638
|
+
boundActionTypes(fieldName, fieldDef)
|
|
1425
1639
|
);
|
|
1426
1640
|
entries.push({
|
|
1427
1641
|
// displayName FIRST: description is prose meant for a human reading the
|
|
@@ -1465,24 +1679,24 @@ function formatConsumptionFull(entries) {
|
|
|
1465
1679
|
}
|
|
1466
1680
|
|
|
1467
1681
|
// src/lib/context-loader.ts
|
|
1468
|
-
import { readFileSync as
|
|
1469
|
-
import { homedir as
|
|
1470
|
-
import { join as
|
|
1471
|
-
var
|
|
1682
|
+
import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
|
|
1683
|
+
import { homedir as homedir7 } from "os";
|
|
1684
|
+
import { join as join9 } from "path";
|
|
1685
|
+
var DEFAULT_DIR7 = process.env.SUVEREN_DATA_DIR ?? join9(homedir7(), ".suveren");
|
|
1472
1686
|
var BRIEF_MAX_CHARS = 16 * 1024;
|
|
1473
|
-
function readContextFile(
|
|
1474
|
-
const dir =
|
|
1475
|
-
const filePath =
|
|
1476
|
-
if (!
|
|
1687
|
+
function readContextFile(dataDir2) {
|
|
1688
|
+
const dir = dataDir2 ?? DEFAULT_DIR7;
|
|
1689
|
+
const filePath = join9(dir, "context.md");
|
|
1690
|
+
if (!existsSync9(filePath)) return null;
|
|
1477
1691
|
try {
|
|
1478
|
-
const content =
|
|
1692
|
+
const content = readFileSync9(filePath, "utf-8").trim();
|
|
1479
1693
|
return content || null;
|
|
1480
1694
|
} catch {
|
|
1481
1695
|
return null;
|
|
1482
1696
|
}
|
|
1483
1697
|
}
|
|
1484
|
-
function getContextForBrief(
|
|
1485
|
-
const full = readContextFile(
|
|
1698
|
+
function getContextForBrief(dataDir2) {
|
|
1699
|
+
const full = readContextFile(dataDir2);
|
|
1486
1700
|
if (!full) return { brief: null, truncated: false };
|
|
1487
1701
|
if (full.length <= BRIEF_MAX_CHARS) {
|
|
1488
1702
|
return { brief: full, truncated: false };
|
|
@@ -1578,14 +1792,41 @@ function uiUrl() {
|
|
|
1578
1792
|
const port2 = process.env.SUVEREN_CP_PORT ?? "3400";
|
|
1579
1793
|
return `http://localhost:${port2}`;
|
|
1580
1794
|
}
|
|
1581
|
-
function
|
|
1582
|
-
|
|
1583
|
-
return `${what} Suveren gateway is running but LOCKED, so it cannot read any authorizations or credentials.
|
|
1795
|
+
function bootLockedNotice(what) {
|
|
1796
|
+
return `${what} Suveren gateway is running but LOCKED, so it cannot read any mandates or credentials.
|
|
1584
1797
|
|
|
1585
|
-
This is not the same as having no
|
|
1798
|
+
This is not the same as having no mandates \u2014 yours are on disk, encrypted, and unreadable until someone unlocks them.
|
|
1586
1799
|
|
|
1587
1800
|
TELL THE USER: open ${uiUrl()} and enter your Suveren API key to unlock the gateway. It boots locked by design after every restart; the key is never stored.`;
|
|
1588
1801
|
}
|
|
1802
|
+
function expiredSessionNotice(what) {
|
|
1803
|
+
return `${what} Suveren gateway's sign-in has ended (sign-ins last 30 days, or it was revoked), so it is now LOCKED.
|
|
1804
|
+
|
|
1805
|
+
TELL THE USER: open ${uiUrl()} and enter your Suveren API key to sign in again. Your mandates are safe; nothing ran.`;
|
|
1806
|
+
}
|
|
1807
|
+
function asKeyMismatchNotice(what) {
|
|
1808
|
+
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.
|
|
1809
|
+
|
|
1810
|
+
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.`;
|
|
1811
|
+
}
|
|
1812
|
+
function asUrlChangedNotice(what) {
|
|
1813
|
+
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.
|
|
1814
|
+
|
|
1815
|
+
TELL THE USER: open ${uiUrl()} and sign in again to pair with the new Authority Server.`;
|
|
1816
|
+
}
|
|
1817
|
+
function lockedNotice(action, reason = "restart") {
|
|
1818
|
+
const what = action ? `Cannot ${action}: the` : "The";
|
|
1819
|
+
switch (reason) {
|
|
1820
|
+
case "expired":
|
|
1821
|
+
return expiredSessionNotice(what);
|
|
1822
|
+
case "as-key-mismatch":
|
|
1823
|
+
return asKeyMismatchNotice(what);
|
|
1824
|
+
case "as-url-changed":
|
|
1825
|
+
return asUrlChangedNotice(what);
|
|
1826
|
+
default:
|
|
1827
|
+
return bootLockedNotice(what);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1589
1830
|
|
|
1590
1831
|
// src/tools/authorizations.ts
|
|
1591
1832
|
import { getProfile as getProfile4 } from "@hap/core";
|
|
@@ -1593,6 +1834,9 @@ import { getProfile as getProfile4 } from "@hap/core";
|
|
|
1593
1834
|
// src/lib/receipt-footer.ts
|
|
1594
1835
|
import { deriveIdentityLine } from "@hap/core";
|
|
1595
1836
|
var AS_BASE = (process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai").replace(/\/$/, "");
|
|
1837
|
+
function setAsBaseUrl(url) {
|
|
1838
|
+
AS_BASE = url.replace(/\/$/, "");
|
|
1839
|
+
}
|
|
1596
1840
|
var OPERATOR_NAME = process.env.SUVEREN_OPERATOR_NAME ?? "Suveren";
|
|
1597
1841
|
var HAP_URL = "https://www.humanagencyprotocol.org/";
|
|
1598
1842
|
var FOOTER_PROFILES = /* @__PURE__ */ new Set(["email", "calendar", "publish"]);
|
|
@@ -1698,6 +1942,83 @@ function attachReceiptId(tool, args, receiptId) {
|
|
|
1698
1942
|
return { ...args, receipt_id: receiptId };
|
|
1699
1943
|
}
|
|
1700
1944
|
|
|
1945
|
+
// src/lib/ticket-verify.ts
|
|
1946
|
+
import { verifyReceiptSignature } from "@hap/core";
|
|
1947
|
+
var TicketBindingMismatchError = class extends Error {
|
|
1948
|
+
constructor(message) {
|
|
1949
|
+
super(message);
|
|
1950
|
+
this.name = "TicketBindingMismatchError";
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
var TICKET_MAX_AGE_SECONDS = 5 * 60;
|
|
1954
|
+
var TICKET_MAX_CLOCK_SKEW_SECONDS = 30;
|
|
1955
|
+
async function verifyTicket(cache, receipt, expected) {
|
|
1956
|
+
const publicKeyHex = await cache.getPublicKey();
|
|
1957
|
+
if (typeof receipt.signature !== "string" || !receipt.signature) {
|
|
1958
|
+
throw new AsKeyMismatchError("Ticket carries no signature \u2014 refusing to trust it.");
|
|
1959
|
+
}
|
|
1960
|
+
try {
|
|
1961
|
+
await verifyReceiptSignature(receipt, publicKeyHex);
|
|
1962
|
+
} catch (err) {
|
|
1963
|
+
throw new AsKeyMismatchError(
|
|
1964
|
+
`Ticket signature does not verify against the pinned Authority Server key \u2014 ${err instanceof Error ? err.message : String(err)}. Refusing to execute.`
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
if (receipt.action !== expected.action) {
|
|
1968
|
+
throw new TicketBindingMismatchError(
|
|
1969
|
+
`Ticket action "${String(receipt.action)}" does not match the requested action "${expected.action}" \u2014 refusing to execute.`
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
if (expected.executionContext !== void 0 && hashToolArgs(receipt.executionContext ?? {}) !== hashToolArgs(expected.executionContext)) {
|
|
1973
|
+
throw new TicketBindingMismatchError(
|
|
1974
|
+
"Ticket executionContext does not match what this call requested \u2014 refusing to execute."
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
if (expected.authorizationId !== void 0 && receipt.authorizationId !== expected.authorizationId) {
|
|
1978
|
+
throw new TicketBindingMismatchError(
|
|
1979
|
+
`Ticket authorizationId "${String(receipt.authorizationId)}" does not match the requested grant "${expected.authorizationId}" \u2014 refusing to execute.`
|
|
1980
|
+
);
|
|
1981
|
+
}
|
|
1982
|
+
if (expected.profileId !== void 0 && receipt.profileId !== expected.profileId) {
|
|
1983
|
+
throw new TicketBindingMismatchError(
|
|
1984
|
+
`Ticket profileId "${String(receipt.profileId)}" does not match the requested profile "${expected.profileId}" \u2014 refusing to execute.`
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
if (expected.proposalId !== void 0 && receipt.proposalId !== expected.proposalId) {
|
|
1988
|
+
throw new TicketBindingMismatchError(
|
|
1989
|
+
`Ticket proposalId "${String(receipt.proposalId)}" does not match the proposal being executed "${expected.proposalId}" \u2014 refusing to execute.`
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
if (expected.contentHash !== void 0) {
|
|
1993
|
+
if (receipt.contentHash !== expected.contentHash) {
|
|
1994
|
+
throw new TicketBindingMismatchError(
|
|
1995
|
+
"Ticket contentHash does not match the content this call is bound to \u2014 refusing to execute."
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
if (expected.contentBinding !== void 0 && hashToolArgs(receipt.contentBinding ?? {}) !== hashToolArgs(expected.contentBinding)) {
|
|
1999
|
+
throw new TicketBindingMismatchError(
|
|
2000
|
+
"Ticket contentBinding does not match what this call requested \u2014 refusing to execute."
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
const timestamp = receipt.timestamp;
|
|
2005
|
+
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
|
|
2006
|
+
throw new TicketBindingMismatchError("Ticket carries no valid timestamp \u2014 refusing to execute.");
|
|
2007
|
+
}
|
|
2008
|
+
const nowSec3 = Math.floor(Date.now() / 1e3);
|
|
2009
|
+
const ageSec = nowSec3 - timestamp;
|
|
2010
|
+
if (ageSec > TICKET_MAX_AGE_SECONDS) {
|
|
2011
|
+
throw new TicketBindingMismatchError(
|
|
2012
|
+
`Ticket is ${ageSec}s old, older than the ${TICKET_MAX_AGE_SECONDS}s freshness window \u2014 refusing to execute.`
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
if (ageSec < -TICKET_MAX_CLOCK_SKEW_SECONDS) {
|
|
2016
|
+
throw new TicketBindingMismatchError(
|
|
2017
|
+
`Ticket is timestamped ${-ageSec}s in the future, beyond the ${TICKET_MAX_CLOCK_SKEW_SECONDS}s clock-skew tolerance \u2014 refusing to execute.`
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1701
2022
|
// src/lib/arg-encoding.ts
|
|
1702
2023
|
function rfc2047Encode(value) {
|
|
1703
2024
|
if (!/[^\x00-\x7F]/.test(value)) return value;
|
|
@@ -2109,7 +2430,7 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
2109
2430
|
const lockedGuard = (inner) => async (args) => {
|
|
2110
2431
|
if (!state2.spClient.isUnlocked()) {
|
|
2111
2432
|
return {
|
|
2112
|
-
content: [{ type: "text", text: lockedNotice(`use ${tool.namespacedName}
|
|
2433
|
+
content: [{ type: "text", text: lockedNotice(`use ${tool.namespacedName}`, state2.spClient.getLockReason() ?? "restart") }],
|
|
2113
2434
|
isError: true
|
|
2114
2435
|
};
|
|
2115
2436
|
}
|
|
@@ -2413,6 +2734,14 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
2413
2734
|
toolArgs: enrichedArgs,
|
|
2414
2735
|
executionContext: { ...execution }
|
|
2415
2736
|
});
|
|
2737
|
+
state2.proposalSubmissions.record({
|
|
2738
|
+
proposalId: proposal.id,
|
|
2739
|
+
tool: tool.namespacedName,
|
|
2740
|
+
toolArgs: enrichedArgs,
|
|
2741
|
+
executionContext: { ...execution },
|
|
2742
|
+
authorizationId: authzId,
|
|
2743
|
+
profileId: auth.profileId
|
|
2744
|
+
});
|
|
2416
2745
|
return {
|
|
2417
2746
|
content: [{
|
|
2418
2747
|
type: "text",
|
|
@@ -2421,6 +2750,12 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2421
2750
|
}]
|
|
2422
2751
|
};
|
|
2423
2752
|
} catch (err) {
|
|
2753
|
+
if (!state2.spClient.isUnlocked()) {
|
|
2754
|
+
return {
|
|
2755
|
+
content: [{ type: "text", text: lockedNotice(`use ${tool.namespacedName}`, "expired") }],
|
|
2756
|
+
isError: true
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2424
2759
|
return {
|
|
2425
2760
|
content: [{ type: "text", text: `Failed to submit proposal: ${err instanceof Error ? err.message : String(err)}` }],
|
|
2426
2761
|
isError: true
|
|
@@ -2449,6 +2784,14 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2449
2784
|
...binding ? { contentHash: binding.contentHash, contentBinding: binding.contentBinding } : {}
|
|
2450
2785
|
});
|
|
2451
2786
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
2787
|
+
await verifyTicket(state2.cache, receipt, {
|
|
2788
|
+
action: tool.namespacedName,
|
|
2789
|
+
executionContext: { ...execution },
|
|
2790
|
+
authorizationId: authzId,
|
|
2791
|
+
profileId: auth.profileId,
|
|
2792
|
+
contentHash: binding?.contentHash,
|
|
2793
|
+
contentBinding: binding?.contentBinding
|
|
2794
|
+
});
|
|
2452
2795
|
await state2.archiveReceipt(receipt, {
|
|
2453
2796
|
authorizationId: authzId,
|
|
2454
2797
|
profileId: auth.profileId,
|
|
@@ -2463,6 +2806,13 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2463
2806
|
boundContent: binding?.boundContent
|
|
2464
2807
|
});
|
|
2465
2808
|
} catch (err) {
|
|
2809
|
+
if (err instanceof AsKeyMismatchError || err instanceof TicketBindingMismatchError) {
|
|
2810
|
+
void notifyControlPlane("as-key-mismatch");
|
|
2811
|
+
return {
|
|
2812
|
+
content: [{ type: "text", text: `Blocked: ${err.message}` }],
|
|
2813
|
+
isError: true
|
|
2814
|
+
};
|
|
2815
|
+
}
|
|
2466
2816
|
if (err instanceof ContentBindingError) {
|
|
2467
2817
|
return {
|
|
2468
2818
|
content: [{
|
|
@@ -2508,6 +2858,14 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
2508
2858
|
executionContext: { ...execution },
|
|
2509
2859
|
pendingApprovers: uniqueApprovers
|
|
2510
2860
|
});
|
|
2861
|
+
state2.proposalSubmissions.record({
|
|
2862
|
+
proposalId: proposal.id,
|
|
2863
|
+
tool: tool.namespacedName,
|
|
2864
|
+
toolArgs: enrichedArgs,
|
|
2865
|
+
executionContext: { ...execution },
|
|
2866
|
+
authorizationId: authzId,
|
|
2867
|
+
profileId: auth.profileId
|
|
2868
|
+
});
|
|
2511
2869
|
return {
|
|
2512
2870
|
content: [{
|
|
2513
2871
|
type: "text",
|
|
@@ -2516,6 +2874,12 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.`
|
|
|
2516
2874
|
}]
|
|
2517
2875
|
};
|
|
2518
2876
|
} catch (proposalErr) {
|
|
2877
|
+
if (!state2.spClient.isUnlocked()) {
|
|
2878
|
+
return {
|
|
2879
|
+
content: [{ type: "text", text: lockedNotice(`use ${tool.namespacedName}`, "expired") }],
|
|
2880
|
+
isError: true
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2519
2883
|
return {
|
|
2520
2884
|
content: [{ type: "text", text: `Failed to submit approval proposal: ${proposalErr instanceof Error ? proposalErr.message : String(proposalErr)}` }],
|
|
2521
2885
|
isError: true
|
|
@@ -2537,6 +2901,12 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.`
|
|
|
2537
2901
|
isError: true
|
|
2538
2902
|
};
|
|
2539
2903
|
}
|
|
2904
|
+
if (!state2.spClient.isUnlocked()) {
|
|
2905
|
+
return {
|
|
2906
|
+
content: [{ type: "text", text: lockedNotice(`use ${tool.namespacedName}`, "expired") }],
|
|
2907
|
+
isError: true
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2540
2910
|
return {
|
|
2541
2911
|
content: [{ type: "text", text: `SP unavailable \u2014 tool call blocked. ${err instanceof Error ? err.message : ""}` }],
|
|
2542
2912
|
isError: true
|
|
@@ -2667,7 +3037,7 @@ function buildCapabilityMap(profileId, toolGating, integrationManager2) {
|
|
|
2667
3037
|
function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
2668
3038
|
return async (args) => {
|
|
2669
3039
|
if (!state2.spClient.isUnlocked()) {
|
|
2670
|
-
return { content: [{ type: "text", text: lockedNotice("list authorizations") }] };
|
|
3040
|
+
return { content: [{ type: "text", text: lockedNotice("list authorizations", state2.spClient.getLockReason() ?? "restart") }] };
|
|
2671
3041
|
}
|
|
2672
3042
|
const authorizations = state2.getEnrichedAuthorizations();
|
|
2673
3043
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -2861,7 +3231,7 @@ function shortProfileName3(profileId) {
|
|
|
2861
3231
|
function listIntegrationsHandler(state2, integrationManager2) {
|
|
2862
3232
|
return async () => {
|
|
2863
3233
|
if (!state2.spClient.isUnlocked()) {
|
|
2864
|
-
return { content: [{ type: "text", text: lockedNotice("list integrations") }] };
|
|
3234
|
+
return { content: [{ type: "text", text: lockedNotice("list integrations", state2.spClient.getLockReason() ?? "restart") }] };
|
|
2865
3235
|
}
|
|
2866
3236
|
if (!integrationManager2) {
|
|
2867
3237
|
return { content: [{ type: "text", text: "No integration manager available." }] };
|
|
@@ -2903,6 +3273,9 @@ function listIntegrationsHandler(state2, integrationManager2) {
|
|
|
2903
3273
|
|
|
2904
3274
|
// src/tools/commitments.ts
|
|
2905
3275
|
import { ContentBindingError as ContentBindingError2 } from "@hap/core";
|
|
3276
|
+
function buildSkippedProposalNote(proposalId) {
|
|
3277
|
+
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.`;
|
|
3278
|
+
}
|
|
2906
3279
|
var installedExecutor = null;
|
|
2907
3280
|
function installCommittedExecutor(executor) {
|
|
2908
3281
|
installedExecutor = executor;
|
|
@@ -2928,6 +3301,28 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2928
3301
|
);
|
|
2929
3302
|
}
|
|
2930
3303
|
const cachedAuth = state2.cache.getAllAuthorizations().find((a) => a.authorizationId === proposal.authorizationId);
|
|
3304
|
+
const submitted = state2.proposalSubmissions.get(proposal.id);
|
|
3305
|
+
if (!submitted) {
|
|
3306
|
+
console.error(
|
|
3307
|
+
`[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).`
|
|
3308
|
+
);
|
|
3309
|
+
return { text: buildSkippedProposalNote(proposal.id) };
|
|
3310
|
+
}
|
|
3311
|
+
{
|
|
3312
|
+
const mismatches = [];
|
|
3313
|
+
if (submitted.tool !== proposal.tool) mismatches.push("tool");
|
|
3314
|
+
if (submitted.toolArgsHash !== hashToolArgs(proposal.toolArgs)) mismatches.push("arguments");
|
|
3315
|
+
if (submitted.executionContextHash !== hashToolArgs(proposal.executionContext)) mismatches.push("executionContext");
|
|
3316
|
+
if (submitted.authorizationId !== proposal.authorizationId) mismatches.push("authorizationId");
|
|
3317
|
+
if (submitted.profileId !== proposal.profileId) mismatches.push("profileId");
|
|
3318
|
+
if (mismatches.length > 0) {
|
|
3319
|
+
void notifyControlPlane("as-key-mismatch");
|
|
3320
|
+
return {
|
|
3321
|
+
text: `Blocked: proposal ${proposal.id} no longer matches what this gateway submitted (${mismatches.join(", ")} differ) \u2014 refusing to execute.`,
|
|
3322
|
+
isError: true
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
2931
3326
|
let receiptId;
|
|
2932
3327
|
let replayed = false;
|
|
2933
3328
|
try {
|
|
@@ -2963,6 +3358,15 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2963
3358
|
});
|
|
2964
3359
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
2965
3360
|
replayed = idempotent;
|
|
3361
|
+
await verifyTicket(state2.cache, receipt, {
|
|
3362
|
+
action: proposal.tool,
|
|
3363
|
+
executionContext: proposal.executionContext,
|
|
3364
|
+
authorizationId: proposal.authorizationId,
|
|
3365
|
+
profileId: proposal.profileId,
|
|
3366
|
+
proposalId: proposal.id,
|
|
3367
|
+
contentHash: binding?.contentHash,
|
|
3368
|
+
contentBinding: binding?.contentBinding
|
|
3369
|
+
});
|
|
2966
3370
|
await state2.archiveReceipt(receipt, {
|
|
2967
3371
|
authorizationId: proposal.authorizationId,
|
|
2968
3372
|
profileId: proposal.profileId,
|
|
@@ -2977,6 +3381,13 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2977
3381
|
boundContent: binding?.boundContent
|
|
2978
3382
|
});
|
|
2979
3383
|
} catch (err) {
|
|
3384
|
+
if (err instanceof AsKeyMismatchError || err instanceof TicketBindingMismatchError) {
|
|
3385
|
+
void notifyControlPlane("as-key-mismatch");
|
|
3386
|
+
return {
|
|
3387
|
+
text: `Proposal ${proposal.id}: blocked \u2014 ${err.message}`,
|
|
3388
|
+
isError: true
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
2980
3391
|
if (err instanceof ContentBindingError2) {
|
|
2981
3392
|
return {
|
|
2982
3393
|
text: `Proposal ${proposal.id}: blocked \u2014 the approved content cannot be bound to the receipt. ${err.message}`,
|
|
@@ -3067,7 +3478,7 @@ Result: ${resultText}` };
|
|
|
3067
3478
|
function checkPendingCommitmentsHandler(state2, integrationManager2) {
|
|
3068
3479
|
return async (args) => {
|
|
3069
3480
|
if (!state2.spClient.isUnlocked()) {
|
|
3070
|
-
return { content: [{ type: "text", text: lockedNotice("check commitments") }] };
|
|
3481
|
+
return { content: [{ type: "text", text: lockedNotice("check commitments", state2.spClient.getLockReason() ?? "restart") }] };
|
|
3071
3482
|
}
|
|
3072
3483
|
try {
|
|
3073
3484
|
if (args.proposal_id) {
|
|
@@ -3136,9 +3547,13 @@ Wait for the human to approve; do not re-submit the tool call.`
|
|
|
3136
3547
|
}]
|
|
3137
3548
|
};
|
|
3138
3549
|
}
|
|
3139
|
-
const lines = committed.map(
|
|
3140
|
-
|
|
3141
|
-
|
|
3550
|
+
const lines = committed.map((p) => {
|
|
3551
|
+
const base = `${p.id}: tool=${p.tool}, status=${p.status}, committed=[${Object.keys(p.committedBy).join(",")}]`;
|
|
3552
|
+
if (p.status === "committed" && !state2.proposalSubmissions.get(p.id)) {
|
|
3553
|
+
return `${base} \u2014 SKIPPED HERE: ${buildSkippedProposalNote(p.id)}`;
|
|
3554
|
+
}
|
|
3555
|
+
return base;
|
|
3556
|
+
});
|
|
3142
3557
|
return {
|
|
3143
3558
|
content: [{
|
|
3144
3559
|
type: "text",
|
|
@@ -3335,16 +3750,16 @@ function verifyGateContentHashes(content, auth) {
|
|
|
3335
3750
|
}
|
|
3336
3751
|
|
|
3337
3752
|
// src/lib/integration-registry.ts
|
|
3338
|
-
import { mkdirSync as
|
|
3339
|
-
import { homedir as
|
|
3340
|
-
import { dirname as
|
|
3341
|
-
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
3753
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync10 } from "fs";
|
|
3754
|
+
import { homedir as homedir8 } from "os";
|
|
3755
|
+
import { dirname as dirname8, join as join10 } from "path";
|
|
3756
|
+
var DEFAULT_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join10(homedir8(), ".suveren");
|
|
3342
3757
|
var IntegrationRegistry = class {
|
|
3343
3758
|
integrations = /* @__PURE__ */ new Map();
|
|
3344
3759
|
filePath;
|
|
3345
|
-
constructor(
|
|
3346
|
-
const dir =
|
|
3347
|
-
this.filePath =
|
|
3760
|
+
constructor(dataDir2) {
|
|
3761
|
+
const dir = dataDir2 ?? DEFAULT_DATA_DIR;
|
|
3762
|
+
this.filePath = join10(dir, "integrations.json");
|
|
3348
3763
|
this.load();
|
|
3349
3764
|
}
|
|
3350
3765
|
// ─── CRUD ───────────────────────────────────────────────────────────────
|
|
@@ -3375,12 +3790,12 @@ var IntegrationRegistry = class {
|
|
|
3375
3790
|
}
|
|
3376
3791
|
// ─── Load / Save ────────────────────────────────────────────────────────
|
|
3377
3792
|
load() {
|
|
3378
|
-
if (!
|
|
3379
|
-
|
|
3793
|
+
if (!existsSync10(this.filePath)) {
|
|
3794
|
+
mkdirSync8(dirname8(this.filePath), { recursive: true });
|
|
3380
3795
|
return;
|
|
3381
3796
|
}
|
|
3382
3797
|
try {
|
|
3383
|
-
const raw =
|
|
3798
|
+
const raw = readFileSync10(this.filePath, "utf-8");
|
|
3384
3799
|
const data = JSON.parse(raw);
|
|
3385
3800
|
const migrated = data.integrations.map((i) => {
|
|
3386
3801
|
if ("toolGating" in i && !("profile" in i)) {
|
|
@@ -3409,45 +3824,45 @@ var IntegrationRegistry = class {
|
|
|
3409
3824
|
version: 1,
|
|
3410
3825
|
integrations: Array.from(this.integrations.values())
|
|
3411
3826
|
};
|
|
3412
|
-
|
|
3413
|
-
|
|
3827
|
+
mkdirSync8(dirname8(this.filePath), { recursive: true });
|
|
3828
|
+
writeFileSync8(this.filePath, JSON.stringify(data, null, 2), { encoding: "utf-8" });
|
|
3414
3829
|
}
|
|
3415
3830
|
};
|
|
3416
3831
|
|
|
3417
3832
|
// src/lib/integration-manager.ts
|
|
3418
|
-
import { homedir as
|
|
3419
|
-
import { join as
|
|
3420
|
-
import { existsSync as
|
|
3833
|
+
import { homedir as homedir9 } from "os";
|
|
3834
|
+
import { join as join12, delimiter } from "path";
|
|
3835
|
+
import { existsSync as existsSync12, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, readFileSync as readFileSync12, rmSync } from "fs";
|
|
3421
3836
|
import { execFile } from "child_process";
|
|
3422
3837
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3423
3838
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3424
3839
|
import { getProfile as getProfile5 } from "@hap/core";
|
|
3425
3840
|
|
|
3426
3841
|
// src/lib/manifest-loader.ts
|
|
3427
|
-
import { readFileSync as
|
|
3428
|
-
import { join as
|
|
3842
|
+
import { readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
|
|
3843
|
+
import { join as join11, resolve } from "path";
|
|
3429
3844
|
var manifests = /* @__PURE__ */ new Map();
|
|
3430
3845
|
function loadManifests(integrationsDir) {
|
|
3431
3846
|
const dir = resolve(
|
|
3432
|
-
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ??
|
|
3847
|
+
integrationsDir ?? process.env.SUVEREN_MANIFESTS_DIR ?? join11(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "content", "integrations")
|
|
3433
3848
|
);
|
|
3434
|
-
const indexPath =
|
|
3435
|
-
if (!
|
|
3849
|
+
const indexPath = join11(dir, "index.json");
|
|
3850
|
+
if (!existsSync11(indexPath)) {
|
|
3436
3851
|
console.error(`[ManifestLoader] No index.json found at ${indexPath}, skipping manifest loading`);
|
|
3437
3852
|
return 0;
|
|
3438
3853
|
}
|
|
3439
3854
|
let index;
|
|
3440
3855
|
try {
|
|
3441
|
-
index = JSON.parse(
|
|
3856
|
+
index = JSON.parse(readFileSync11(indexPath, "utf-8"));
|
|
3442
3857
|
} catch (err) {
|
|
3443
3858
|
console.error(`[ManifestLoader] Failed to parse ${indexPath}:`, err);
|
|
3444
3859
|
return 0;
|
|
3445
3860
|
}
|
|
3446
3861
|
let loaded = 0;
|
|
3447
3862
|
for (const [id, relativePath] of Object.entries(index.integrations)) {
|
|
3448
|
-
const manifestPath =
|
|
3863
|
+
const manifestPath = join11(dir, relativePath);
|
|
3449
3864
|
try {
|
|
3450
|
-
const manifest = JSON.parse(
|
|
3865
|
+
const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
|
|
3451
3866
|
manifests.set(id, manifest);
|
|
3452
3867
|
loaded++;
|
|
3453
3868
|
} catch (err) {
|
|
@@ -3535,26 +3950,26 @@ function safeHost(url) {
|
|
|
3535
3950
|
}
|
|
3536
3951
|
|
|
3537
3952
|
// src/lib/integration-manager.ts
|
|
3538
|
-
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
3539
|
-
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ??
|
|
3953
|
+
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join12(homedir9(), ".suveren");
|
|
3954
|
+
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ?? join12(DEFAULT_DATA_DIR2, "integrations");
|
|
3540
3955
|
var installLock = Promise.resolve();
|
|
3541
3956
|
function withInstallLock(task) {
|
|
3542
3957
|
const run = installLock.then(task, task);
|
|
3543
3958
|
installLock = run.then(() => void 0, () => void 0);
|
|
3544
3959
|
return run;
|
|
3545
3960
|
}
|
|
3546
|
-
var INTEGRATIONS_BIN =
|
|
3961
|
+
var INTEGRATIONS_BIN = join12(INTEGRATIONS_DIR, "node_modules", ".bin");
|
|
3547
3962
|
function buildPath() {
|
|
3548
3963
|
const base = process.env.PATH ?? "";
|
|
3549
3964
|
return [INTEGRATIONS_BIN, base].join(delimiter);
|
|
3550
3965
|
}
|
|
3551
3966
|
function ensureIntegrationsDir() {
|
|
3552
|
-
if (!
|
|
3553
|
-
|
|
3967
|
+
if (!existsSync12(INTEGRATIONS_DIR)) {
|
|
3968
|
+
mkdirSync9(INTEGRATIONS_DIR, { recursive: true });
|
|
3554
3969
|
}
|
|
3555
|
-
const pkgPath =
|
|
3556
|
-
if (!
|
|
3557
|
-
|
|
3970
|
+
const pkgPath = join12(INTEGRATIONS_DIR, "package.json");
|
|
3971
|
+
if (!existsSync12(pkgPath)) {
|
|
3972
|
+
writeFileSync9(pkgPath, JSON.stringify({ name: "suveren-integrations", version: "1.0.0", private: true }, null, 2));
|
|
3558
3973
|
}
|
|
3559
3974
|
}
|
|
3560
3975
|
function readAgeOf(config) {
|
|
@@ -3620,19 +4035,19 @@ var IntegrationManager = class {
|
|
|
3620
4035
|
* exist, and treat anything else as not-installed (and reinstallable).
|
|
3621
4036
|
*/
|
|
3622
4037
|
isUsableInstall(npmPackage) {
|
|
3623
|
-
const pkgDir =
|
|
3624
|
-
const pkgJson =
|
|
3625
|
-
if (!
|
|
4038
|
+
const pkgDir = join12(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
4039
|
+
const pkgJson = join12(pkgDir, "package.json");
|
|
4040
|
+
if (!existsSync12(pkgDir) || !existsSync12(pkgJson)) return false;
|
|
3626
4041
|
try {
|
|
3627
|
-
const pkg = JSON.parse(
|
|
4042
|
+
const pkg = JSON.parse(readFileSync12(pkgJson, "utf8"));
|
|
3628
4043
|
const defaultBinName = (pkg.name ?? npmPackage).split("/").pop() ?? "";
|
|
3629
4044
|
const binMap = typeof pkg.bin === "string" ? { [defaultBinName]: pkg.bin } : pkg.bin ?? {};
|
|
3630
4045
|
const binEntries = Object.entries(binMap);
|
|
3631
4046
|
for (const [binName, target] of binEntries) {
|
|
3632
|
-
if (!
|
|
4047
|
+
if (!existsSync12(join12(pkgDir, target))) return false;
|
|
3633
4048
|
if (!this.binShimExists(binName)) return false;
|
|
3634
4049
|
}
|
|
3635
|
-
if (binEntries.length === 0 && pkg.main && !
|
|
4050
|
+
if (binEntries.length === 0 && pkg.main && !existsSync12(join12(pkgDir, pkg.main))) return false;
|
|
3636
4051
|
return true;
|
|
3637
4052
|
} catch {
|
|
3638
4053
|
return false;
|
|
@@ -3646,7 +4061,7 @@ var IntegrationManager = class {
|
|
|
3646
4061
|
binShimExists(binName) {
|
|
3647
4062
|
if (!binName) return false;
|
|
3648
4063
|
const candidates = process.platform === "win32" ? [binName, `${binName}.cmd`, `${binName}.CMD`, `${binName}.ps1`] : [binName];
|
|
3649
|
-
return candidates.some((c) =>
|
|
4064
|
+
return candidates.some((c) => existsSync12(join12(INTEGRATIONS_BIN, c)));
|
|
3650
4065
|
}
|
|
3651
4066
|
/**
|
|
3652
4067
|
* Install an npm package into the managed integrations directory if not
|
|
@@ -3670,8 +4085,8 @@ var IntegrationManager = class {
|
|
|
3670
4085
|
}
|
|
3671
4086
|
/** The actual install. Callers MUST hold the install lock. */
|
|
3672
4087
|
async installNow(npmPackage) {
|
|
3673
|
-
const pkgDir =
|
|
3674
|
-
if (
|
|
4088
|
+
const pkgDir = join12(INTEGRATIONS_DIR, "node_modules", ...npmPackage.split("/"));
|
|
4089
|
+
if (existsSync12(pkgDir)) {
|
|
3675
4090
|
console.error(`[IntegrationManager] Removing unusable install of ${npmPackage}`);
|
|
3676
4091
|
try {
|
|
3677
4092
|
rmSync(pkgDir, { recursive: true, force: true });
|
|
@@ -3785,6 +4200,11 @@ var IntegrationManager = class {
|
|
|
3785
4200
|
const transport = new StdioClientTransport({
|
|
3786
4201
|
command: config.command,
|
|
3787
4202
|
args,
|
|
4203
|
+
// `...process.env` is also how a saved `--ca-file` reaches an
|
|
4204
|
+
// integration: NODE_EXTRA_CA_CERTS (read by Node only at process
|
|
4205
|
+
// start) is already set on THIS process by bundle/server.js before
|
|
4206
|
+
// the MCP server ever starts, so every integration this manager spawns
|
|
4207
|
+
// inherits it here for free — no separate handling needed.
|
|
3788
4208
|
env: {
|
|
3789
4209
|
...process.env,
|
|
3790
4210
|
PATH: buildPath(),
|
|
@@ -4101,28 +4521,28 @@ var IntegrationManager = class {
|
|
|
4101
4521
|
};
|
|
4102
4522
|
|
|
4103
4523
|
// src/lib/profile-loader.ts
|
|
4104
|
-
import { readFileSync as
|
|
4105
|
-
import { join as
|
|
4524
|
+
import { readFileSync as readFileSync13, existsSync as existsSync13 } from "fs";
|
|
4525
|
+
import { join as join13, resolve as resolve2 } from "path";
|
|
4106
4526
|
import { registerProfile } from "@hap/core";
|
|
4107
4527
|
function loadProfiles(profilesDir) {
|
|
4108
|
-
const dir = resolve2(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ??
|
|
4109
|
-
const indexPath =
|
|
4110
|
-
if (!
|
|
4528
|
+
const dir = resolve2(profilesDir ?? process.env.SUVEREN_PROFILES_DIR ?? join13(import.meta.dirname ?? __dirname, "..", "..", "..", "..", "..", "hap-profiles"));
|
|
4529
|
+
const indexPath = join13(dir, "index.json");
|
|
4530
|
+
if (!existsSync13(indexPath)) {
|
|
4111
4531
|
warnNoProfiles(`No index.json at ${indexPath}`);
|
|
4112
4532
|
return 0;
|
|
4113
4533
|
}
|
|
4114
4534
|
let index;
|
|
4115
4535
|
try {
|
|
4116
|
-
index = JSON.parse(
|
|
4536
|
+
index = JSON.parse(readFileSync13(indexPath, "utf-8"));
|
|
4117
4537
|
} catch (err) {
|
|
4118
4538
|
console.error(`[ProfileLoader] Failed to parse ${indexPath}:`, err);
|
|
4119
4539
|
return 0;
|
|
4120
4540
|
}
|
|
4121
4541
|
let loaded = 0;
|
|
4122
4542
|
for (const [profileId, relativePath] of Object.entries(index.profiles)) {
|
|
4123
|
-
const profilePath =
|
|
4543
|
+
const profilePath = join13(dir, relativePath);
|
|
4124
4544
|
try {
|
|
4125
|
-
const profile = JSON.parse(
|
|
4545
|
+
const profile = JSON.parse(readFileSync13(profilePath, "utf-8"));
|
|
4126
4546
|
registerProfile(profileId, profile);
|
|
4127
4547
|
const shortName = profileId.split("/").pop()?.replace(/@.*$/, "");
|
|
4128
4548
|
if (shortName && shortName !== profileId) {
|
|
@@ -4158,8 +4578,8 @@ function warnNoProfiles(reason) {
|
|
|
4158
4578
|
import { decodeAttestationBlob as decodeAttestationBlob3 } from "@hap/core";
|
|
4159
4579
|
|
|
4160
4580
|
// src/lib/committed-executor.ts
|
|
4161
|
-
import { existsSync as
|
|
4162
|
-
import { dirname as
|
|
4581
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync14, unlinkSync as unlinkSync6, writeFileSync as writeFileSync10 } from "fs";
|
|
4582
|
+
import { dirname as dirname9, join as join14 } from "path";
|
|
4163
4583
|
var CommittedExecutor = class {
|
|
4164
4584
|
constructor(run) {
|
|
4165
4585
|
this.run = run;
|
|
@@ -4186,8 +4606,8 @@ var CommittedExecutor = class {
|
|
|
4186
4606
|
var ExecutorLock = class {
|
|
4187
4607
|
path;
|
|
4188
4608
|
held = false;
|
|
4189
|
-
constructor(
|
|
4190
|
-
this.path =
|
|
4609
|
+
constructor(dataDir2) {
|
|
4610
|
+
this.path = join14(dataDir2, "executor.lock");
|
|
4191
4611
|
}
|
|
4192
4612
|
/** Try to take the lock. Returns the holder's pid when someone else has it. */
|
|
4193
4613
|
acquire() {
|
|
@@ -4195,9 +4615,9 @@ var ExecutorLock = class {
|
|
|
4195
4615
|
if (current && current.pid !== process.pid && isAlive(current.pid)) {
|
|
4196
4616
|
return { held: false, holderPid: current.pid };
|
|
4197
4617
|
}
|
|
4198
|
-
|
|
4618
|
+
mkdirSync10(dirname9(this.path), { recursive: true, mode: 448 });
|
|
4199
4619
|
const lock = { pid: process.pid, startedAt: Math.floor(Date.now() / 1e3) };
|
|
4200
|
-
|
|
4620
|
+
writeFileSync10(this.path, JSON.stringify(lock), { mode: 384 });
|
|
4201
4621
|
this.held = true;
|
|
4202
4622
|
return { held: true };
|
|
4203
4623
|
}
|
|
@@ -4213,15 +4633,15 @@ var ExecutorLock = class {
|
|
|
4213
4633
|
const current = this.read();
|
|
4214
4634
|
if (current?.pid === process.pid) {
|
|
4215
4635
|
try {
|
|
4216
|
-
|
|
4636
|
+
unlinkSync6(this.path);
|
|
4217
4637
|
} catch {
|
|
4218
4638
|
}
|
|
4219
4639
|
}
|
|
4220
4640
|
}
|
|
4221
4641
|
read() {
|
|
4222
|
-
if (!
|
|
4642
|
+
if (!existsSync14(this.path)) return null;
|
|
4223
4643
|
try {
|
|
4224
|
-
const parsed = JSON.parse(
|
|
4644
|
+
const parsed = JSON.parse(readFileSync14(this.path, "utf8"));
|
|
4225
4645
|
return typeof parsed?.pid === "number" ? parsed : null;
|
|
4226
4646
|
} catch {
|
|
4227
4647
|
return null;
|
|
@@ -4238,11 +4658,115 @@ function isAlive(pid) {
|
|
|
4238
4658
|
}
|
|
4239
4659
|
|
|
4240
4660
|
// bin/http.ts
|
|
4241
|
-
import { homedir as
|
|
4242
|
-
import { join as
|
|
4243
|
-
|
|
4661
|
+
import { homedir as homedir10 } from "os";
|
|
4662
|
+
import { join as join17 } from "path";
|
|
4663
|
+
|
|
4664
|
+
// src/lib/as-config.ts
|
|
4665
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "fs";
|
|
4666
|
+
import { dirname as dirname10, join as join15 } from "path";
|
|
4667
|
+
var DEFAULT_AS_URL = "https://www.suveren.ai";
|
|
4668
|
+
function configPath(dataDir2) {
|
|
4669
|
+
return join15(dataDir2, "config.json");
|
|
4670
|
+
}
|
|
4671
|
+
function readAsConfigStrict(dataDir2) {
|
|
4672
|
+
const path = configPath(dataDir2);
|
|
4673
|
+
if (!existsSync15(path)) return {};
|
|
4674
|
+
let data;
|
|
4675
|
+
try {
|
|
4676
|
+
data = JSON.parse(readFileSync15(path, "utf-8"));
|
|
4677
|
+
} catch (err) {
|
|
4678
|
+
throw new Error(
|
|
4679
|
+
`Could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
4680
|
+
);
|
|
4681
|
+
}
|
|
4682
|
+
const out = {};
|
|
4683
|
+
if (typeof data.asUrl === "string") out.asUrl = data.asUrl;
|
|
4684
|
+
if (typeof data.caFile === "string") out.caFile = data.caFile;
|
|
4685
|
+
return out;
|
|
4686
|
+
}
|
|
4687
|
+
function validateAsUrl(candidate) {
|
|
4688
|
+
const trimmed = candidate.trim();
|
|
4689
|
+
if (!trimmed) return { ok: false, error: "The Authority Server URL is empty." };
|
|
4690
|
+
let parsed;
|
|
4691
|
+
try {
|
|
4692
|
+
parsed = new URL(trimmed);
|
|
4693
|
+
} catch {
|
|
4694
|
+
return { ok: false, error: `"${trimmed}" is not a valid URL.` };
|
|
4695
|
+
}
|
|
4696
|
+
const isLocalHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
4697
|
+
if (parsed.protocol !== "https:" && !isLocalHttp) {
|
|
4698
|
+
return {
|
|
4699
|
+
ok: false,
|
|
4700
|
+
error: `"${trimmed}" must use https:// (http:// is only allowed for http://localhost or http://127.0.0.1).`
|
|
4701
|
+
};
|
|
4702
|
+
}
|
|
4703
|
+
let normalized = `${parsed.origin}${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
4704
|
+
if (normalized.endsWith("/") && normalized !== `${parsed.origin}/`) {
|
|
4705
|
+
normalized = normalized.slice(0, -1);
|
|
4706
|
+
} else if (normalized === `${parsed.origin}/`) {
|
|
4707
|
+
normalized = parsed.origin;
|
|
4708
|
+
}
|
|
4709
|
+
return { ok: true, url: normalized };
|
|
4710
|
+
}
|
|
4711
|
+
function resolveAsUrl(dataDir2, flag) {
|
|
4712
|
+
if (flag) {
|
|
4713
|
+
const v = validateAsUrl(flag);
|
|
4714
|
+
if (!v.ok) throw new Error(`Invalid --as-url: ${v.error}`);
|
|
4715
|
+
return v.url;
|
|
4716
|
+
}
|
|
4717
|
+
const envUrl = process.env.SUVEREN_AS_URL;
|
|
4718
|
+
if (envUrl) {
|
|
4719
|
+
const v = validateAsUrl(envUrl);
|
|
4720
|
+
if (!v.ok) throw new Error(`Invalid SUVEREN_AS_URL: ${v.error}`);
|
|
4721
|
+
return v.url;
|
|
4722
|
+
}
|
|
4723
|
+
const saved = readAsConfigStrict(dataDir2).asUrl;
|
|
4724
|
+
if (saved) {
|
|
4725
|
+
const v = validateAsUrl(saved);
|
|
4726
|
+
if (!v.ok) throw new Error(`Invalid saved as-url "${saved}" in ${dataDir2}/config.json: ${v.error}`);
|
|
4727
|
+
return v.url;
|
|
4728
|
+
}
|
|
4729
|
+
return DEFAULT_AS_URL;
|
|
4730
|
+
}
|
|
4731
|
+
|
|
4732
|
+
// src/lib/mcp-as-tracker.ts
|
|
4733
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync12 } from "fs";
|
|
4734
|
+
import { dirname as dirname11, join as join16 } from "path";
|
|
4735
|
+
function trackerPath(dataDir2) {
|
|
4736
|
+
return join16(dataDir2, "mcp-as-pairing.json");
|
|
4737
|
+
}
|
|
4738
|
+
function readMcpPairedAsUrl(dataDir2) {
|
|
4739
|
+
const path = trackerPath(dataDir2);
|
|
4740
|
+
if (!existsSync16(path)) return null;
|
|
4741
|
+
try {
|
|
4742
|
+
const data = JSON.parse(readFileSync16(path, "utf-8"));
|
|
4743
|
+
return typeof data.asUrl === "string" ? data.asUrl : null;
|
|
4744
|
+
} catch {
|
|
4745
|
+
return null;
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
function writeMcpPairedAsUrl(dataDir2, asUrl) {
|
|
4749
|
+
const path = trackerPath(dataDir2);
|
|
4750
|
+
mkdirSync12(dirname11(path), { recursive: true, mode: 448 });
|
|
4751
|
+
writeFileSync12(path, JSON.stringify({ asUrl }, null, 2), { encoding: "utf-8", mode: 384 });
|
|
4752
|
+
}
|
|
4753
|
+
|
|
4754
|
+
// bin/http.ts
|
|
4755
|
+
var dataDir = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
4756
|
+
var spUrl = resolveAsUrl(dataDir);
|
|
4244
4757
|
var port = parseInt(process.env.SUVEREN_MCP_PORT ?? "3430", 10);
|
|
4245
|
-
|
|
4758
|
+
setAsBaseUrl(spUrl);
|
|
4759
|
+
var state = new SharedState(spUrl, void 0, dataDir);
|
|
4760
|
+
(function repairIfAsUrlChanged() {
|
|
4761
|
+
const lastKnown = readMcpPairedAsUrl(dataDir);
|
|
4762
|
+
if (lastKnown !== null && lastKnown !== spUrl) {
|
|
4763
|
+
console.error(
|
|
4764
|
+
`[Suveren MCP] Authority Server changed (${lastKnown} \u2192 ${spUrl}) \u2014 clearing cached mandates. Sign in again to re-pair.`
|
|
4765
|
+
);
|
|
4766
|
+
state.gateStore.clearAll();
|
|
4767
|
+
}
|
|
4768
|
+
writeMcpPairedAsUrl(dataDir, spUrl);
|
|
4769
|
+
})();
|
|
4246
4770
|
var spApiKey = process.env.SUVEREN_AS_API_KEY ?? "";
|
|
4247
4771
|
if (spApiKey) {
|
|
4248
4772
|
state.spClient.setApiKey(spApiKey);
|
|
@@ -4312,6 +4836,13 @@ app.post("/internal/configure", internalOnly, (req, res) => {
|
|
|
4312
4836
|
}
|
|
4313
4837
|
res.json({ ok: true });
|
|
4314
4838
|
});
|
|
4839
|
+
app.post("/internal/clear-session", internalOnly, (req, res) => {
|
|
4840
|
+
const reason = req.body?.reason;
|
|
4841
|
+
const validReason = reason === "as-key-mismatch" || reason === "as-url-changed" ? reason : void 0;
|
|
4842
|
+
state.spClient.clearSession(validReason);
|
|
4843
|
+
console.error(`[Suveren MCP] Session cleared by control-plane (${validReason ?? "expired"})`);
|
|
4844
|
+
res.json({ ok: true });
|
|
4845
|
+
});
|
|
4315
4846
|
app.post("/internal/gate-content", internalOnly, async (req, res) => {
|
|
4316
4847
|
try {
|
|
4317
4848
|
const { authorizationId, boundsHash, contextHash, context, contextLabels, path: rawPath, gateContent } = req.body;
|
|
@@ -4601,6 +5132,15 @@ app.get("/internal/authorizations", internalOnly, (_req, res) => {
|
|
|
4601
5132
|
app.get("/internal/manifests", internalOnly, (_req, res) => {
|
|
4602
5133
|
res.json({ manifests: getAllManifests() });
|
|
4603
5134
|
});
|
|
5135
|
+
app.get("/internal/skipped-commitments", internalOnly, async (_req, res) => {
|
|
5136
|
+
try {
|
|
5137
|
+
const committed = await state.spClient.getCommittedProposals();
|
|
5138
|
+
const skipped = committed.filter((p) => !state.proposalSubmissions.get(p.id)).map((p) => ({ id: p.id, tool: p.tool, note: buildSkippedProposalNote(p.id) }));
|
|
5139
|
+
res.json({ skipped });
|
|
5140
|
+
} catch (err) {
|
|
5141
|
+
res.status(502).json({ error: err instanceof Error ? err.message : "Could not reach the Authority Server" });
|
|
5142
|
+
}
|
|
5143
|
+
});
|
|
4604
5144
|
app.get("/internal/evidence", internalOnly, (_req, res) => {
|
|
4605
5145
|
if (state.receiptArchive.isLocked()) {
|
|
4606
5146
|
res.status(503).json({ error: "Vault locked \u2014 the evidence archive is encrypted until sign-in." });
|
|
@@ -4734,12 +5274,12 @@ app.listen(port, "0.0.0.0", () => {
|
|
|
4734
5274
|
(proposal) => executeCommitted(proposal, state, integrationManager)
|
|
4735
5275
|
);
|
|
4736
5276
|
installCommittedExecutor(committedExecutor);
|
|
4737
|
-
const
|
|
4738
|
-
const executorLock = new ExecutorLock(
|
|
5277
|
+
const dataDir2 = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
5278
|
+
const executorLock = new ExecutorLock(dataDir2);
|
|
4739
5279
|
const lock = executorLock.acquire();
|
|
4740
5280
|
if (!lock.held) {
|
|
4741
5281
|
console.error(
|
|
4742
|
-
`[Suveren MCP] Committed-proposal execution is DISABLED in this process: pid ${lock.holderPid} holds ${
|
|
5282
|
+
`[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.`
|
|
4743
5283
|
);
|
|
4744
5284
|
}
|
|
4745
5285
|
for (const sig of ["SIGINT", "SIGTERM", "exit"]) {
|