@redocly/revel 0.138.0-next.9 → 0.138.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/CHANGELOG.md +265 -0
- package/dist/api-schemas/mcp-fetch-count.d.ts +24 -0
- package/dist/api-schemas/mcp-fetch-count.js +1 -0
- package/dist/bin.js +0 -0
- package/dist/cli/build/analytics/collect-analytics.js +1 -1
- package/dist/cli/build/analytics/collectors/get-processed-config-stats-usage.js +1 -1
- package/dist/cli/build/index.js +1 -1
- package/dist/cli/develop.js +1 -1
- package/dist/cli/eject/ejectTheme.js +1 -1
- package/dist/cli/translations/collect-config-translations.js +1 -1
- package/dist/client/App.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/openapi-response-sample.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/app/pages/Invite/Invite.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.js +1 -1
- package/dist/client/polyfills.js +1 -1
- package/dist/client/runtime/loader.js +1 -1
- package/dist/client/utils/catalog/parse-filter-query.js +1 -1
- package/dist/compiled/svgo/svgo-node.js +39 -39
- package/dist/constants/api.d.ts +1 -0
- package/dist/constants/api.js +1 -1
- package/dist/constants/common.d.ts +6 -0
- package/dist/constants/common.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/markdoc/helpers/get-inner-text.js +2 -2
- package/dist/markdoc/helpers/guards/is-prompt-node.d.ts +13 -0
- package/dist/markdoc/helpers/guards/is-prompt-node.js +1 -0
- package/dist/server/config/env-config.d.ts +0 -2
- package/dist/server/config/env-schema.d.ts +0 -5
- package/dist/server/config/env-schemas/feature-flags.d.ts +0 -4
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/constants/entitlements.js +1 -1
- package/dist/server/entitlements/entitlements-provider.js +1 -1
- package/dist/server/esbuild/esbuild.js +3 -3
- package/dist/server/esbuild/plugins/on-rebuild.js +1 -1
- package/dist/server/esbuild/plugins/styled-components-ssr.js +1 -1
- package/dist/server/esbuild/plugins/yaml-loader.js +1 -1
- package/dist/server/fs/content-fs.js +1 -1
- package/dist/server/fs/utils/is-l10n-root-file.d.ts +3 -0
- package/dist/server/fs/utils/is-l10n-root-file.js +1 -0
- package/dist/server/plugins/analytics/amplitude/index.js +1 -1
- package/dist/server/plugins/analytics/heap/browser-hooks.js +1 -1
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/loader.js +3 -3
- package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/api-docs/utils/apply-nav-item-to-root.js +1 -1
- package/dist/server/plugins/api-docs/utils/decorators.d.ts +11 -0
- package/dist/server/plugins/api-docs/utils/decorators.js +1 -1
- package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.js +2 -2
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/utils/extract-parts-from-channels-message-ref.js +1 -1
- package/dist/server/plugins/config-parser/format-custom-tags.js +1 -1
- package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
- package/dist/server/plugins/config-parser/loaders/versions-config-loader.js +1 -1
- package/dist/server/plugins/config-parser/resolve-mutual-exclusion.js +1 -1
- package/dist/server/plugins/config-parser/safe-parse.js +1 -1
- package/dist/server/plugins/default-theme/resolve-logo.js +1 -1
- package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.js +2 -2
- package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.js +2 -2
- package/dist/server/plugins/dev-onboarding/api/combine.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/AppOverview.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/useSortableData.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/file-chunk-parser.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/index.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.d.ts +4 -0
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.js +2 -0
- package/dist/server/plugins/markdown/compiler.js +1 -1
- package/dist/server/plugins/markdown/create-source-lines-reader.d.ts +7 -0
- package/dist/server/plugins/markdown/create-source-lines-reader.js +1 -0
- package/dist/server/plugins/markdown/html/normalize-html-headings.d.ts +9 -0
- package/dist/server/plugins/markdown/html/normalize-html-headings.js +1 -0
- package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.js +1 -1
- package/dist/server/plugins/markdown/markdown-static-data-loader.js +1 -1
- package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
- package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
- package/dist/server/plugins/markdown/search/to-markdown.js +13 -13
- package/dist/server/plugins/markdown/search/walk-sections.d.ts +3 -1
- package/dist/server/plugins/markdown/search/walk-sections.js +3 -3
- package/dist/server/plugins/markdown/utils/sanitize-malformed-md-content.js +2 -2
- package/dist/server/plugins/mcp/audit/audit-log.d.ts +1 -1
- package/dist/server/plugins/mcp/audit/audit-log.js +1 -1
- package/dist/server/plugins/mcp/audit/code-credentials.d.ts +9 -0
- package/dist/server/plugins/mcp/audit/code-credentials.js +2 -0
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +5 -5
- package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +3 -1
- package/dist/server/plugins/mcp/codemode/capabilities/utils.d.ts +2 -1
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +3 -3
- package/dist/server/plugins/mcp/codemode/code-audit.d.ts +4 -3
- package/dist/server/plugins/mcp/codemode/code-execution-audit.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.d.ts +12 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/utils/resolve-refs.d.ts +2 -2
- package/dist/server/plugins/mcp/docs-mcp/utils/resolve-refs.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/api-call-operations.d.ts +32 -0
- package/dist/server/plugins/mcp/gateway-mcp/api-call-operations.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.d.ts +7 -4
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.d.ts +9 -0
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -5
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +8 -4
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.d.ts +2 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +11 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-client.d.ts +4 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-client.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.d.ts +4 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.d.ts +13 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.js +13 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{limits.d.ts → fetch-limiter/fetch-limits.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-limits.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{apply-edge-rate-limit.d.ts → request-limiter/apply-edge-rate-limit.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/apply-edge-rate-limit.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{edge-limiter.d.ts → request-limiter/edge-limiter.d.ts} +3 -3
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/edge-limiter.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/rate-limit-telemetry.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/request-limits.d.ts +6 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/request-limits.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/utils/ip-key.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{window-counter.d.ts → utils/window-counter.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/utils/window-counter.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/route-pattern.d.ts +18 -0
- package/dist/server/plugins/mcp/gateway-mcp/route-pattern.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +9 -3
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/subject.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +2 -0
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +0 -2
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
- package/dist/server/plugins/mcp/handlers/credentials-page/constants.d.ts +7 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/constants.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-contract.d.ts +5 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-contract.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-page.d.ts +14 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-page.js +62 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/layout.d.ts +17 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/layout.js +11 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/outcome-pages.d.ts +10 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/outcome-pages.js +11 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/site-branding.d.ts +10 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/site-branding.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/styles.d.ts +4 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/styles.js +186 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/types.d.ts +32 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/types.js +0 -0
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.d.ts +0 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
- package/dist/server/plugins/mcp/index.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.js +2 -2
- package/dist/server/plugins/mcp/types.d.ts +16 -1
- package/dist/server/plugins/mcp/utils/mode.d.ts +4 -1
- package/dist/server/plugins/mcp/utils/mode.js +1 -1
- package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +3 -5
- package/dist/server/plugins/mcp/utils/xmcp-utils.js +1 -1
- package/dist/server/plugins/nav-utils.js +1 -1
- package/dist/server/plugins/scorecard-classic/loaders/scorecard.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/components.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/useData.js +1 -1
- package/dist/server/plugins/search/engines/flexsearch/index.js +2 -2
- package/dist/server/plugins/sidebars/index.js +2 -2
- package/dist/server/plugins/sidebars/utils.js +1 -1
- package/dist/server/providers/database/client.d.ts +5 -0
- package/dist/server/providers/database/client.js +1 -1
- package/dist/server/providers/database/copy-migrations.js +1 -1
- package/dist/server/providers/database/database-connections-manager.js +1 -1
- package/dist/server/providers/database/has-project-database.d.ts +3 -0
- package/dist/server/providers/database/has-project-database.js +1 -0
- package/dist/server/store.d.ts +2 -0
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/formatter.js +1 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +1 -1
- package/dist/server/tools/notifiers/logger.js +1 -1
- package/dist/server/types/plugins/markdown.d.ts +2 -0
- package/dist/server/types/web-server.d.ts +1 -0
- package/dist/server/utils/codeframes/codeframes.js +2 -2
- package/dist/server/utils/entitlements/read-entitlement-number.d.ts +3 -0
- package/dist/server/utils/entitlements/read-entitlement-number.js +1 -0
- package/dist/server/utils/fs.js +1 -1
- package/dist/server/utils/is-api-download-link.d.ts +1 -0
- package/dist/server/utils/is-api-download-link.js +1 -1
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/utils/redact-url.d.ts +3 -2
- package/dist/server/utils/redact-url.js +1 -1
- package/dist/server/utils/sandbox-context.d.ts +7 -4
- package/dist/server/utils/sandbox-context.js +1 -1
- package/dist/server/web-server/auth.d.ts +0 -1
- package/dist/server/web-server/auth.js +4 -4
- package/dist/server/web-server/dev-server.js +1 -1
- package/dist/server/web-server/http.d.ts +2 -1
- package/dist/server/web-server/http.js +2 -2
- package/dist/server/web-server/jwt/token-types.d.ts +1 -0
- package/dist/server/web-server/jwt/token-types.js +1 -1
- package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
- package/dist/server/web-server/middleware/dynamic-middleware/hono-compose.js +1 -1
- package/dist/server/web-server/middleware/responseHeadersMiddleware.js +1 -1
- package/dist/server/web-server/routes/auth.d.ts +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +1756 -1756
- package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +295 -295
- package/dist/server/web-server/routes/cors-proxy.js +2 -2
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.d.ts +24 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.js +35 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-fetch-count.d.ts +8 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-fetch-count.js +1 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth-store.d.ts +15 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth-store.js +1 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +3 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/server/web-server/routes/resolve-route.js +1 -1
- package/dist/server/workers/worker-pool.js +1 -1
- package/dist/types/entitlements.d.ts +2 -0
- package/dist/utils/time/debounce.js +1 -1
- package/package.json +9 -10
- package/dist/client/app/utils/withLoadProgress.d.ts +0 -2
- package/dist/client/app/utils/withLoadProgress.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/rate-limit-telemetry.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +0 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-page.d.ts +0 -12
- package/dist/server/plugins/mcp/handlers/mcp-credentials-page.js +0 -225
- /package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{rate-limit-telemetry.d.ts → request-limiter/rate-limit-telemetry.d.ts} +0 -0
- /package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{ip-key.d.ts → utils/ip-key.d.ts} +0 -0
package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{sql as t}from"drizzle-orm";import{createDatabaseRepositoryInstance as s}from"../../../../../providers/database/instance-cache-resolver.js";import{KvRepository as u}from"../../../../../persistence/kv/repositories/kv-repository.js";import{createKvDbRecord as _}from"../../../../../persistence/kv/mappers/create-kv-db-record.js";class o extends u{static create(a){return s(a,"fetch counter",o)}async incrementBelowLimits(a){const d=t.join(a.map(({key:c,limit:n,ttlInSeconds:r})=>{const e=_({key:c,value:{count:1},ttlInSeconds:r});return t`(${e.encodedKey}, ${e.value}, ${e.expiresAt}, ${e.createdAt}, ${e.updatedAt}, ${n})`}),t`, `);return(await this.databaseClient.dbClient.all(t`
|
|
2
|
+
WITH slot (encoded_key, value, expires_at, created_at, updated_at, max_count) AS (VALUES ${d})
|
|
3
|
+
INSERT INTO kv (encoded_key, value, expires_at, created_at, updated_at)
|
|
4
|
+
SELECT encoded_key, value, expires_at, created_at, updated_at FROM slot
|
|
5
|
+
WHERE NOT EXISTS (
|
|
6
|
+
SELECT 1 FROM slot AS s JOIN kv ON kv.encoded_key = s.encoded_key
|
|
7
|
+
WHERE json_extract(kv.value, '$.count') >= s.max_count
|
|
8
|
+
)
|
|
9
|
+
ON CONFLICT (encoded_key) DO UPDATE SET
|
|
10
|
+
value = json_object('count', json_extract(kv.value, '$.count') + 1),
|
|
11
|
+
updated_at = excluded.updated_at
|
|
12
|
+
RETURNING encoded_key
|
|
13
|
+
`)).length>0}}export{o as FetchCounterRepository};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{FEATURE as e,GATEWAY_FETCH_LIMIT_DEFAULTS as t}from"../../../../../../constants/common.js";import{readEntitlementNumber as r}from"../../../../../utils/entitlements/read-entitlement-number.js";function i(){return{ratePerMin:r(e.gatewayFetchRatePerMin,t.ratePerMin),quotaPerDay:r(e.gatewayFetchQuotaPerDay,t.quotaPerDay),budgetPerExec:r(e.gatewayFetchBudgetPerExec,t.budgetPerExec)}}export{i as resolveGatewayFetchLimits};
|
package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/apply-edge-rate-limit.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{envConfig as o}from"../../../../../config/env-config.js";import{isRealmOrReef as s}from"../../../../../utils/is-realm-or-reef.js";import{KvRepository as m}from"../../../../../persistence/kv/repositories/kv-repository.js";import{logger as p}from"../../../../../tools/notifiers/logger.js";import{ipRateLimitKey as f}from"../utils/ip-key.js";import{checkEdgeRateLimit as c}from"./edge-limiter.js";import{resolveMcpRequestLimits as d}from"./request-limits.js";import{reportMcpRateLimited as l}from"./rate-limit-telemetry.js";async function w(n,a){if(!s())return;const i=f(n);if(!i)return;let e,r;try{const t=await m.create({baseDbDir:a.serverOutDir,sqldRemoteDatabaseUrl:o.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:o.SQLD_REMOTE_DATABASE_AUTH_TOKEN});r=d(),e=await c({kv:t,ip:i,limits:r,now:Date.now()})}catch(t){p.warn(`gateway rate-limit init error, failing open: ${String(t)}`);return}if(!e.allowed)return l({scope:e.scope,retryAfterSeconds:e.retryAfterSeconds,limit:e.scope==="rate"?r.ratePerMin:r.quotaPerDay}),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32029,message:`Rate limit exceeded (${e.scope}); retry after ${e.retryAfterSeconds}s`},id:null}),{status:429,headers:{"Content-Type":"application/json","Retry-After":String(e.retryAfterSeconds)}})}export{w as applyEdgeRateLimit};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { KvRepository } from '
|
|
2
|
-
import type {
|
|
1
|
+
import type { KvRepository } from '../../../../../persistence/kv/repositories/kv-repository.js';
|
|
2
|
+
import type { McpRequestLimits } from './request-limits.js';
|
|
3
3
|
export type EdgeDecision = {
|
|
4
4
|
allowed: true;
|
|
5
5
|
} | {
|
|
@@ -10,7 +10,7 @@ export type EdgeDecision = {
|
|
|
10
10
|
export declare function checkEdgeRateLimit(params: {
|
|
11
11
|
kv: KvRepository;
|
|
12
12
|
ip: string;
|
|
13
|
-
limits:
|
|
13
|
+
limits: McpRequestLimits;
|
|
14
14
|
now: number;
|
|
15
15
|
}): Promise<EdgeDecision>;
|
|
16
16
|
//# sourceMappingURL=edge-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{checkAndIncrement as c}from"../utils/window-counter.js";const s=60,d=86400;async function w(i){const{kv:e,ip:t,limits:o,now:r}=i;await e.sync();const n=await c({kv:e,ip:t,windowSeconds:s,limit:o.ratePerMin,now:r});if(!n.allowed)return{allowed:!1,retryAfterSeconds:n.retryAfterSeconds,scope:"rate"};const a=await c({kv:e,ip:t,windowSeconds:d,limit:o.quotaPerDay,now:r});return a.allowed?{allowed:!0}:{allowed:!1,retryAfterSeconds:a.retryAfterSeconds,scope:"quota"}}export{w as checkEdgeRateLimit};
|
package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/rate-limit-telemetry.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{telemetry as o}from"../../../../../telemetry/index.js";import{logger as i}from"../../../../../tools/notifiers/logger.js";import{McpServerType as m}from"../../../constants.js";import{serverAttributes as p}from"../../../utils/telemetry-attributes.js";function d({scope:e,retryAfterSeconds:r,limit:t}){try{o.sendMcpRateLimitedMessage([{...p(m.Docs),scope:e,retry_after_seconds:r,limit:t}])}catch{}i.warn(`Gateway MCP rate limited [scope=${e}] retryAfterSeconds=${r} limit=${t}`)}export{d as reportMcpRateLimited};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{FEATURE as e,MCP_REQUEST_LIMIT_DEFAULTS as r}from"../../../../../../constants/common.js";import{readEntitlementNumber as t}from"../../../../../utils/entitlements/read-entitlement-number.js";function i(){return{ratePerMin:t(e.mcpRequestRatePerMin,r.ratePerMin),quotaPerDay:t(e.mcpRequestQuotaPerDay,r.quotaPerDay)}}export{i as resolveMcpRequestLimits};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"../../../../../web-server/utils/ssrf-blocklist.js";function I(t){const n=a(t);if(n)return f(n)}function f(t){if(l(t)===6){const n=c(t);return n||`${u(t)}::/64`}return t}function u(t){const n=t.split("%")[0],[e,i=""]=n.split("::"),r=e?e.split(":"):[],o=i?i.split(":"):[],s=8-r.length-o.length;return[...r,...Array(Math.max(0,s)).fill("0"),...o].slice(0,4).map(p=>parseInt(p||"0",16).toString(16)).join(":")}export{I as ipRateLimitKey};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{logger as d}from"../../../../../tools/notifiers/logger.js";function g(e,t,r){return["mcp","request-rl",e,String(t),String(r)]}async function S(e){const{kv:t,ip:r,windowSeconds:n,limit:l,now:w}=e,o=Math.floor(w/1e3),c=Math.floor(o/n),i=g(r,n,c);try{const s=(await t.get(i))?.count??0;if(s>=l){const u=(c+1)*n-o;return{allowed:!1,retryAfterSeconds:Math.max(1,u)}}return await t.set(i,{count:s+1},{ttlInSeconds:n}),{allowed:!0}}catch(a){return d.warn(`gateway rate-limit store error, failing open: ${String(a)}`),{allowed:!0}}}export{S as checkAndIncrement};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OpenAPIServer } from '@redocly/api-docs';
|
|
2
|
+
/** Regex for request pathnames of the OpenAPI `path` below the base path that `prefix` matches. */
|
|
3
|
+
export declare function pathPattern(prefix: string, path: string): RegExp | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Regex group matching any of the servers' base paths: required when every server has one,
|
|
6
|
+
* optional when some server has none, `''` when none has one.
|
|
7
|
+
*/
|
|
8
|
+
export declare function basePathPrefix(servers: readonly OpenAPIServer[]): string;
|
|
9
|
+
/** Number of `{variable}` segments in an OpenAPI path; fewer means a more specific path. */
|
|
10
|
+
export declare function pathVariableCount(path: string): number;
|
|
11
|
+
/**
|
|
12
|
+
* Identity of an OpenAPI path template for comparison: variable names and a trailing slash do not
|
|
13
|
+
* change which requests the path matches, so `/users/{id}/` and `/users/{userId}` are equal.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pathTemplateKey(path: string): string;
|
|
16
|
+
/** The upper-case HTTP method sent for an OpenAPI operation key or a request method; `x-query` sends `QUERY`. */
|
|
17
|
+
export declare function operationHttpMethod(key: string): string;
|
|
18
|
+
//# sourceMappingURL=route-pattern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const r=/\{(?<!\{[^}]*?\{)[^}]*\}/g;function u(e,t){if(t.startsWith("/"))return new RegExp(`^${e}${a(t)}/?$`)}function s(e){const t=e.map(c=>p(c.url)),n=[...new Set(t.filter(Boolean).map(a))];if(n.length===0)return"";const o=`(?:${n.join("|")})`;return t.every(Boolean)?o:`${o}?`}function l(e){return e.match(r)?.length??0}function f(e){return e.replace(r,"{}").replace(/(?<!\/)\/+$/,"")||"/"}function h(e){const t=e.toUpperCase();return t==="X-QUERY"?"QUERY":t}function a(e){return e.split(r).map(i).join("[^/]+").replace(/(?<!\/)\/+$/,"")}function p(e){if(!e)return"";const t=e.replace(/^[a-z][a-z0-9+.-]*:\/\//i,""),n=t.indexOf("/");return n===-1?"":t.slice(n).split(/[?#]/)[0].replace(/(?<!\/)\/+$/,"")}function i(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}export{s as basePathPrefix,h as operationHttpMethod,u as pathPattern,f as pathTemplateKey,l as pathVariableCount};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KvService } from '@redocly/config';
|
|
2
2
|
import type { UpstreamAuthScheme } from './upstream-auth-scheme.js';
|
|
3
|
+
export declare const ELICITATION_TTL_MINUTES = 15;
|
|
3
4
|
export declare const ELICITATION_TTL_MS: number;
|
|
4
5
|
export type StoredSecret = {
|
|
5
6
|
header: string;
|
|
@@ -11,7 +12,6 @@ export type ElicitationScheme = {
|
|
|
11
12
|
name: string;
|
|
12
13
|
label?: string;
|
|
13
14
|
auth: UpstreamAuthScheme;
|
|
14
|
-
hasExistingSecret: boolean;
|
|
15
15
|
operations?: string[];
|
|
16
16
|
};
|
|
17
17
|
export type ElicitationTarget = {
|
|
@@ -21,17 +21,23 @@ export type ElicitationTarget = {
|
|
|
21
21
|
scheme: string;
|
|
22
22
|
schemeLabel?: string;
|
|
23
23
|
auth: UpstreamAuthScheme;
|
|
24
|
-
hasExistingSecret?: boolean;
|
|
25
24
|
schemes?: ElicitationScheme[];
|
|
25
|
+
/** The schemes the failing operation accepts, when it accepts more than one. */
|
|
26
|
+
acceptedSchemes?: string[];
|
|
27
|
+
expiresAt: number;
|
|
26
28
|
};
|
|
29
|
+
export type StoredSchemes = Record<string, {
|
|
30
|
+
savedAt?: number;
|
|
31
|
+
}>;
|
|
27
32
|
export declare class SecretStore {
|
|
28
33
|
#private;
|
|
29
34
|
setSecret(kv: KvService, subject: string, api: string, scheme: string, secret: StoredSecret): Promise<void>;
|
|
30
35
|
getSecretsForSubject(kv: KvService, subject: string): Promise<UpstreamSecrets>;
|
|
36
|
+
getStoredSchemes(kv: KvService, subject: string, api: string): Promise<StoredSchemes>;
|
|
31
37
|
hasSecret(kv: KvService, subject: string, api: string, scheme: string): Promise<boolean>;
|
|
32
38
|
deleteSecret(kv: KvService, subject: string, api: string, scheme: string): Promise<void>;
|
|
33
39
|
deleteSubject(kv: KvService, subject: string): Promise<void>;
|
|
34
|
-
createElicitation(kv: KvService, target: ElicitationTarget): Promise<string>;
|
|
40
|
+
createElicitation(kv: KvService, target: Omit<ElicitationTarget, 'expiresAt'>): Promise<string>;
|
|
35
41
|
peekElicitation(kv: KvService, token: string): Promise<ElicitationTarget | undefined>;
|
|
36
42
|
consumeElicitation(kv: KvService, token: string): Promise<ElicitationTarget | undefined>;
|
|
37
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createCipheriv as
|
|
1
|
+
import{createCipheriv as d,createDecipheriv as l,createHash as p,hkdfSync as f,randomBytes as y,randomUUID as S}from"node:crypto";import{JWT_SECRET_KEY as u}from"../../../constants/common.js";import{assertHeaderSafe as I}from"./credential-validation.js";import{secretTtlSeconds as T}from"./subject.js";const g=15,h=g*60*1e3,w="mcp-upstream-secrets",A="mcp-elicitation",E="mcp-elicitation";class v{async setSecret(t,e,r,s,n){I(n.header,n.value);const i={...n,savedAt:Date.now()},a={api:r,scheme:s,...this.#f(this.#o(e),i,this.#a(r,s))};await t.set(this.#e(e,r,s),a,{ttlInSeconds:T(e)})}async getSecretsForSubject(t,e){return this.#i(t,e,this.#t(e))}async getStoredSchemes(t,e,r){const s=[...this.#t(e),r],n=(await this.#i(t,e,s))[r]??{};return Object.fromEntries(Object.entries(n).map(([i,{savedAt:a}])=>[i,{savedAt:a}]))}async#i(t,e,r){const s=this.#o(e),{items:n}=await t.list({prefix:r}),i={};for(const a of n){if(!a.value?.scheme)continue;const{api:c,scheme:o}=a.value;try{const m=this.#n(s,a.value,this.#a(c,o));i[c]={...i[c],[o]:m}}catch{continue}}return i}async hasSecret(t,e,r,s){return!!await t.get(this.#e(e,r,s))}async deleteSecret(t,e,r,s){await t.delete(this.#e(e,r,s))}async deleteSubject(t,e){const{items:r}=await t.list({prefix:this.#t(e)}),s=r.flatMap(n=>n.value?[n.key]:[]);s.length!==0&&await t.transaction(async n=>{for(const i of s)await n.delete(i)})}async createElicitation(t,e){const r=S(),s={...e,expiresAt:Date.now()+h};return await t.set(this.#r(r),this.#f(this.#s(),s),{ttlInSeconds:h/1e3}),r}async peekElicitation(t,e){const r=await t.get(this.#r(e));if(r)try{return this.#n(this.#s(),r)}catch{return}}async consumeElicitation(t,e){const r=this.#r(e),s=await t.transaction(async n=>{const i=await n.get(r);return i&&await n.delete(r),i});if(s)try{return this.#n(this.#s(),s)}catch{return}}#t(t){return["mcp","secret",this.#c(t)]}#e(t,e,r){return["mcp","secret",this.#c(t),e,r]}#a(t,e){return`${t}\0${e}`}#r(t){return["mcp","elicitation",t]}#c(t){return p("sha256").update(t).digest("hex")}#o(t){return Buffer.from(f("sha256",u,t,w,32))}#s(){return Buffer.from(f("sha256",u,E,A,32))}#f(t,e,r){const s=y(12),n=d("aes-256-gcm",t,s);r&&n.setAAD(Buffer.from(r,"utf8"));const i=Buffer.concat([n.update(JSON.stringify(e),"utf8"),n.final()]);return{iv:s.toString("base64"),tag:n.getAuthTag().toString("base64"),data:i.toString("base64")}}#n(t,e,r){const s=l("aes-256-gcm",t,Buffer.from(e.iv,"base64"));r&&s.setAAD(Buffer.from(r,"utf8")),s.setAuthTag(Buffer.from(e.tag,"base64"));const n=Buffer.concat([s.update(Buffer.from(e.data,"base64")),s.final()]).toString("utf8");return JSON.parse(n)}}const K=new v;export{g as ELICITATION_TTL_MINUTES,h as ELICITATION_TTL_MS,v as SecretStore,K as secretStore};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomBytes as r}from"node:crypto";const i=32,S=/^[A-Za-z0-9_-]{43}$/,c=1440*60,u=
|
|
1
|
+
import{randomBytes as r}from"node:crypto";const i=32,S=/^[A-Za-z0-9_-]{43}$/,c=1440*60,u=10080*60,s="anon:",d="user:",f="This API requires credentials and the caller is anonymous; call createAnonymousSession first, then retry with sessionHandle",a="The sessionHandle is not a valid handle; call createAnonymousSession to obtain one";function N(){return r(i).toString("base64url")}function E(e){return S.test(e)}function l(e){if(!e?.isAuthenticated)return;const n=e.claims,o=(typeof n?.sub=="string"&&n.sub?n.sub:void 0)??(e.email||void 0);if(o)return`${d}${e.idpId??"local"}:${o}`}function A(e,n){const t=l(e);return t?{kind:"resolved",subject:t}:n===void 0?{kind:"anonymous"}:E(n)?{kind:"resolved",subject:`${s}${n}`}:{kind:"invalid",message:a}}function T(e){return e.startsWith(s)?c:u}export{s as ANONYMOUS_SUBJECT_PREFIX,a as MALFORMED_SESSION_HANDLE_MESSAGE,f as MISSING_SESSION_HANDLE_MESSAGE,d as USER_SUBJECT_PREFIX,N as createSessionHandle,E as isValidSessionHandle,A as resolveSecretSubject,T as secretTtlSeconds,l as userSubject};
|
|
@@ -26,6 +26,8 @@ export type UpstreamApiAuth = {
|
|
|
26
26
|
defaultScheme: string;
|
|
27
27
|
routes: UpstreamAuthRoute[];
|
|
28
28
|
descriptions?: Record<string, string>;
|
|
29
|
+
/** Query parameter names of the `apiKey` schemes with `in: query`. */
|
|
30
|
+
credentialQueryParams: string[];
|
|
29
31
|
};
|
|
30
32
|
type SecuritySchemeLoader = typeof getApiDescriptionFromFs;
|
|
31
33
|
export declare const DEFAULT_SCHEME_NAME = "default";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getApiDescriptionFromFs as
|
|
2
|
-
`)[0].trim();
|
|
1
|
+
import{getApiDescriptionFromFs as k}from"../docs-mcp/tools/openapi/utils.js";import{OPERATION_METHODS as b}from"../docs-mcp/tools/openapi/constants.js";import{basePathPrefix as S,operationHttpMethod as A,pathPattern as C}from"./route-pattern.js";const P=120,l="default",j={kind:"raw"},y=["oauth2ClientCredentials","bearer","apiKey","cookie","raw"],E=new Set(b);function c(){return{schemes:{[l]:j},defaultScheme:l,routes:[],credentialQueryParams:[]}}async function q(e,n,t=k){const r=Object.values(e.apiDescriptionsMap??{}).find(o=>o.relativePath===n);if(!r)return c();try{const o=await t({relativePath:r.relativePath,outdir:e.outdir||"",user:e.user,rbac:e.config?.access?.rbac||{},requiresLogin:!!e.config?.access?.requiresLogin});return o?w(o,r.servers??[]):c()}catch{return c()}}function w(e,n){const t=K(e),r=Object.keys(t),o=g(e);if(r.length===0)return{...c(),credentialQueryParams:o};const s=h(e.security,t)[0]??a(r,t)[0],i=v(e,r);return{schemes:t,defaultScheme:s,routes:T(e,t,n),credentialQueryParams:o,...Object.keys(i).length>0?{descriptions:i}:{}}}function g(e){const n=new Set;for(const t of Object.values(e.components?.securitySchemes??{}))f(t)&&t.type==="apiKey"&&t.in==="query"&&t.name&&n.add(t.name);return[...n]}function L(e){return[...new Set(Object.values(e).map(H))]}function R(e){return a(Object.keys(e),e)}function N(e,n){const t=new Set;for(const r of e.routes)r.schemes.includes(n)&&t.add(`${r.method} ${r.path}`);return[...t]}function H(e){return e.kind==="apiKey"?e.header:e.kind==="cookie"?"Cookie":"Authorization"}function v(e,n){const t={};for(const r of n){const o=e.components?.securitySchemes?.[r],s=f(o)?o.description:void 0;if(typeof s!="string")continue;const i=s.split(`
|
|
2
|
+
`)[0].trim();i&&(t[r]=i.slice(0,P))}return t}function K(e){const n={};for(const[t,r]of Object.entries(e.components?.securitySchemes??{})){if(!f(r))continue;const o=M(r);o&&(n[t]=o)}return n}function M(e){if(e.type==="oauth2"){const n=e.flows?.clientCredentials;return n?{kind:"oauth2ClientCredentials",tokenUrl:n.tokenUrl,scopes:Object.keys(n.scopes??{})}:{kind:"bearer"}}if(e.type==="openIdConnect")return{kind:"bearer"};if(e.type==="http"&&e.scheme?.toLowerCase()==="bearer")return{kind:"bearer"};if(e.type==="apiKey"&&e.in==="header")return{kind:"apiKey",header:e.name||"X-Api-Key"};if(e.type==="apiKey"&&e.in==="cookie"&&e.name)return{kind:"cookie",name:e.name}}function a(e,n){return[...e].sort((t,r)=>y.indexOf(n[t].kind)-y.indexOf(n[r].kind)||e.indexOf(t)-e.indexOf(r))}function h(e,n){const t=[];for(const r of e??[])for(const o of Object.keys(r))n[o]&&!t.includes(o)&&t.push(o);return t}function T(e,n,t){const r=S(t),o=[];for(const[s,i]of Object.entries(e.paths??{})){if(!i||typeof i!="object")continue;const p=C(r,s);if(p)for(const[d,O]of Object.entries(i)){if(!E.has(d.toLowerCase()))continue;const u=O?.security??e.security;if(u===void 0)continue;const m=h(u,n);m.length===0&&u.length>0||o.push({pattern:p,path:s,method:A(d),schemes:a(m,n)})}}return o}function f(e){return typeof e=="object"&&e!==null&&"type"in e}export{l as DEFAULT_SCHEME_NAME,L as credentialHeadersOf,N as operationsForScheme,R as orderedSchemesOf,q as resolveUpstreamApiAuth};
|
|
@@ -8,8 +8,6 @@ export type UpstreamAuthRequiredEvent = {
|
|
|
8
8
|
schemes?: string[];
|
|
9
9
|
/** Scheme whose stored credential the bridge actually sent; absent when nothing was injected. */
|
|
10
10
|
sentScheme?: string;
|
|
11
|
-
/** Lower-cased credential header the sandbox code set itself, which suppressed the injection. */
|
|
12
|
-
callerHeader?: string;
|
|
13
11
|
/** The upstream's own explanation of the failure, taken from the response body. */
|
|
14
12
|
detail?: string;
|
|
15
13
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const i="com.redocly/upstream-auth-required";function
|
|
1
|
+
const i="com.redocly/upstream-auth-required";function f(e){return`${e.api}\0${e.scheme??""}`}function m(e,n){const t=new Map;for(const a of n){const s=f(a),o=t.get(s);(!o||u(a)>u(o))&&t.set(s,a)}const r=[...t.values()];return r.length===0?e:{...e,_meta:{...e._meta,[i]:r}}}function u(e){return e.status!==401?0:e.sentScheme?2:1}function h(e){const n=e._meta?.[i];return Array.isArray(n)?n.filter(t=>typeof t?.api=="string"&&typeof t?.name=="string"&&typeof t?.status=="number").map(t=>{const r=Array.isArray(t.schemes)?t.schemes.filter(p=>typeof p=="string"):[],{schemes:a,sentScheme:s,detail:o,...c}=t;return{...c,...r.length>0?{schemes:r}:{},...typeof s=="string"?{sentScheme:s}:{},...typeof o=="string"?{detail:o}:{}}}):[]}function y(e){if(!e._meta||!(i in e._meta))return e;const{[i]:n,...t}=e._meta,r={...e};return Object.keys(t).length>0?r._meta=t:delete r._meta,r}export{i as UPSTREAM_AUTH_REQUIRED_META,h as readAuthRequiredMeta,y as stripAuthRequiredMeta,f as upstreamAuthKey,m as withAuthRequiredMeta};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={save:"save",remove:"remove",removeAll:"remove-all",decline:"decline"};export{e as FORM_ACTIONS};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ElicitationScheme, ElicitationTarget } from '../../gateway-mcp/secret-store.js';
|
|
2
|
+
import type { SchemeField } from './types.js';
|
|
3
|
+
export declare function schemeFieldName(field: SchemeField, schemeIndex: number): string;
|
|
4
|
+
export declare function credentialSchemesOf(target: ElicitationTarget): ElicitationScheme[];
|
|
5
|
+
//# sourceMappingURL=form-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function c(e,n){return`${e}__${n}`}function h(e){return e.schemes??[{name:e.scheme,auth:e.auth}]}export{h as credentialSchemesOf,c as schemeFieldName};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ElicitationTarget, StoredSchemes } from '../../gateway-mcp/secret-store.js';
|
|
2
|
+
import type { FormError, PageContent, PageSite } from './types.js';
|
|
3
|
+
type FormPageInput = {
|
|
4
|
+
site: PageSite;
|
|
5
|
+
target: ElicitationTarget;
|
|
6
|
+
token: string;
|
|
7
|
+
stored: StoredSchemes;
|
|
8
|
+
error?: FormError;
|
|
9
|
+
/** Client IDs to put back into the OAuth2 fields after a rejected submission, by scheme index. */
|
|
10
|
+
clientIds?: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export declare function formPage(input: FormPageInput): PageContent;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=form-page.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import{withPathPrefix as D}from"@redocly/theme/core/utils";import{MCP_CREDENTIALS_ROUTE as R}from"../../../../constants/mcp.js";import{ELICITATION_TTL_MS as _}from"../../gateway-mcp/secret-store.js";import{secretTtlSeconds as I}from"../../gateway-mcp/subject.js";import{FORM_ACTIONS as $}from"./constants.js";import{credentialSchemesOf as F,schemeFieldName as M}from"./form-contract.js";import{ICONS as v,code as h,escapeHtml as r,siteHeader as N,targetTitle as A}from"./layout.js";const S=10,g="form-error",T=new Intl.DateTimeFormat("en-GB",{day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}),P={bearer:{title:"API token",noun:"API token",placeholder:"Paste your API token"},apiKey:{title:"API key",noun:"API key",placeholder:"Paste your API key"},cookie:{title:"Cookie",noun:"cookie value",placeholder:"Paste the cookie value"},oauth2ClientCredentials:{title:"OAuth2",noun:"access token",placeholder:"Paste an access token"},raw:{title:"Authorization header",noun:"header value",placeholder:"Bearer <token>"}};function te(e){const{site:t,target:n,token:o,error:s}=e,a=D(R),u=F(n),i=u.length>1,c=L(e,u),l=c.some(f=>f.isStored),d=i&&l,m=c.map(f=>i?U(f):B(f)).join(""),p=d?'<button class="text-danger" type="submit" form="remove-all">Remove all credentials</button>':"",O=s?`<div class="banner" role="alert" id="${g}">${v.alert}<p>${r(s.message)}</p></div>`:"";return{title:`Credentials for ${A(n)}`,body:`<div class="page">
|
|
2
|
+
<main class="card">
|
|
3
|
+
${N(t)}
|
|
4
|
+
<h1>${l?"Update":"Add"} credentials for ${r(A(n))}</h1>
|
|
5
|
+
<p class="lede">${i?"This API accepts more than one kind of credential. Fill in the one that you have.":"This API needs one credential to authenticate your calls."}</p>
|
|
6
|
+
${O}
|
|
7
|
+
<form class="credentials" method="post" action="${a}" autocomplete="off">
|
|
8
|
+
${y(o,$.save)}
|
|
9
|
+
<div class="schemes">${m}</div>
|
|
10
|
+
<div class="actions">
|
|
11
|
+
<div class="actions-row">${p}<button class="primary" type="submit">Save credentials</button></div>
|
|
12
|
+
<p class="decline small">Did not ask for this link? <button class="link-button" type="submit" form="decline">Decline it</button></p>
|
|
13
|
+
</div>
|
|
14
|
+
</form>
|
|
15
|
+
${H(a,o,c,d)}
|
|
16
|
+
</main>
|
|
17
|
+
${W(n,t.host)}
|
|
18
|
+
</div>`}}function L(e,t){const{target:n,stored:o,error:s,clientIds:a}=e,u=n.acceptedSchemes??[n.scheme],i=s?.schemeIndex??Math.max(0,t.findIndex(({name:l})=>u.includes(l))),c=t.length>1;return t.map((l,d)=>{const m=o[l.name],p=s?.schemeIndex===d?s:void 0;return{scheme:l,index:d,isMulti:c,title:c?l.name:P[l.auth.kind].title,savedAt:m?.savedAt,deletedAt:m?.savedAt===void 0?void 0:m.savedAt+I(n.subject)*1e3,isStored:m!==void 0,isOpen:d===i||u.includes(l.name)||m!==void 0,error:p,clientId:a?.[d]??"",autofocusField:d===i?p?.field??"secret":void 0}})}function B(e){return`<section class="scheme" aria-labelledby="scheme-${e.index}-title">
|
|
19
|
+
<div class="scheme-body">
|
|
20
|
+
<div class="scheme-head">
|
|
21
|
+
<h2 id="scheme-${e.index}-title">${r(e.title)}</h2>
|
|
22
|
+
<p>${E(e.scheme.auth)}</p>
|
|
23
|
+
</div>
|
|
24
|
+
${C(e)}
|
|
25
|
+
</div>
|
|
26
|
+
</section>`}function U(e){const t=e.isStored?'<span class="tag stored">Stored</span>':'<span class="tag">Not set</span>';return`<details class="scheme" aria-labelledby="scheme-${e.index}-title"${e.isOpen?" open":""}>
|
|
27
|
+
<summary><span class="summary-title" id="scheme-${e.index}-title">${r(e.title)}</span><span class="summary-tag">${t}</span><span class="summary-line">${E(e.scheme.auth)}</span>${e.scheme.label?`<span class="summary-line">${r(e.scheme.label)}</span>`:""}</summary>
|
|
28
|
+
<div class="scheme-body">
|
|
29
|
+
${C(e)}
|
|
30
|
+
</div>
|
|
31
|
+
</details>`}function C(e){const t=e.isStored?j(e):"",n=e.isMulti?K(e.scheme.operations):"";return e.scheme.auth.kind==="oauth2ClientCredentials"?`${t}${x(e,!1)}${n}${z(e)}`:`${t}${x(e,!e.isMulti&&!e.isStored)}${n}`}function j({savedAt:e,deletedAt:t,index:n,title:o}){return`<div class="stored-box">
|
|
32
|
+
<div>${e===void 0||t===void 0?"<p>A credential is stored for this scheme.</p>":`<p>Saved on ${T.format(e)}</p><p class="muted small">Kept until ${T.format(t)} at ${b(t)} UTC</p>`}</div>
|
|
33
|
+
<button class="text-danger small" type="submit" form="remove-${n}" aria-label="Remove the stored ${r(o)} credential">Remove</button>
|
|
34
|
+
</div>`}function x(e,t){const{auth:n}=e.scheme,{noun:o,placeholder:s}=P[n.kind];return k({view:e,field:"secret",type:"password",label:e.isStored?`Replace the ${o}`:Y(o),placeholder:e.isStored&&e.isMulti?"Leave empty to keep the stored value":s,hint:q(n),isRequired:t})}function z(e){return`<hr class="divider">
|
|
35
|
+
<div class="scheme-head">
|
|
36
|
+
<p class="strong">No token yet?</p>
|
|
37
|
+
<p>We exchange your client ID and secret for a token and store only the token.</p>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="field-row">
|
|
40
|
+
${k({view:e,field:"client_id",type:"text",label:"Client ID",placeholder:"Enter the client ID",value:e.clientId})}
|
|
41
|
+
${k({view:e,field:"client_secret",type:"password",label:"Client secret",placeholder:"Enter the client secret"})}
|
|
42
|
+
</div>`}function k({view:e,field:t,type:n,label:o,placeholder:s,hint:a,value:u,isRequired:i}){const c=M(t,e.index),l=e.error!==void 0&&e.error.field===t,d=`${c}-hint`,m=[a?d:"",l?g:""].filter(Boolean).join(" "),p=[`type="${n}"`,`id="${c}"`,`name="${c}"`,`placeholder="${r(s)}"`,'autocomplete="off"','autocapitalize="off"','spellcheck="false"',u?`value="${r(u)}"`:"",m?`aria-describedby="${m}"`:"",l?'aria-invalid="true"':"",i?"required":"",e.autofocusField===t?"autofocus":""].filter(Boolean);return`<div class="field">
|
|
43
|
+
<label for="${c}">${r(o)}</label>
|
|
44
|
+
<input ${p.join(" ")}>
|
|
45
|
+
${a?`<p class="muted small" id="${d}">${a}</p>`:""}
|
|
46
|
+
</div>`}function K(e){if(!e||e.length===0)return"";const t=e.slice(0,S).map(s=>`<li>${h(s)}</li>`).join(""),n=e.length-S,o=n>0?`<li class="muted">and ${n} more</li>`:"";return`<details class="operations"><summary>Which operations use it</summary><ul>${t}${o}</ul></details>`}function W({name:e,subject:t,expiresAt:n},o){const s=`${v.shield}What happens to your credentials`,a=`<ol class="steps">
|
|
47
|
+
<li>Sent straight to ${r(o)}, never through your AI client</li>
|
|
48
|
+
<li>Stored encrypted and never shown again</li>
|
|
49
|
+
<li>Added only to calls to ${r(e)} from the AI client that asked for this link</li>
|
|
50
|
+
<li>You can delete them anytime</li>
|
|
51
|
+
</ol>`;return`<aside class="panel" aria-labelledby="panel-title">
|
|
52
|
+
<div class="panel-steps"><h2 id="panel-title">${s}</h2>${a}</div>
|
|
53
|
+
<details class="panel-steps-toggle"><summary><h2>${s}</h2></summary>${a}</details>
|
|
54
|
+
<div class="link-facts">
|
|
55
|
+
<p>Link requested at ${b(n-_)} UTC</p>
|
|
56
|
+
<span class="pill">Open until ${b(n)} UTC</span>
|
|
57
|
+
<p>This link works one time.</p>
|
|
58
|
+
<p>Kept for ${V(I(t))} after you save them.</p>
|
|
59
|
+
<p>To delete them, ask your AI client for a new link.</p>
|
|
60
|
+
</div>
|
|
61
|
+
</aside>`}function H(e,t,n,o){const s=n.filter(i=>i.isStored).map(i=>`<form id="remove-${i.index}" method="post" action="${e}">${y(t,$.remove)}<input type="hidden" name="scheme" value="${i.index}"></form>`),a=o?`<form id="remove-all" method="post" action="${e}">${y(t,$.removeAll)}</form>`:"",u=`<form id="decline" method="post" action="${e}">${y(t,$.decline)}</form>`;return[...s,a,u].join(`
|
|
62
|
+
`)}function y(e,t){return`<input type="hidden" name="token" value="${r(e)}"><input type="hidden" name="action" value="${t}">`}function E(e){return e.kind==="apiKey"?`Sent to the API as the ${h(e.header)} header.`:e.kind==="cookie"?`Sent to the API as the ${h(e.name)} cookie.`:`Sent to the API as the ${h("Authorization")} header.`}function q(e){if(e.kind==="cookie")return`Paste only the value. We send it as ${h(`${e.name}=<value>`)}.`;if(e.kind==="raw")return`Paste the full header value, for example ${h("Bearer <token>")}.`}function b(e){return new Date(e).toISOString().slice(11,16)}function V(e){const t=e/86400;return Number.isInteger(t)&&t>1?`${t} days`:`${Math.round(e/3600)} hours`}function Y(e){return e.charAt(0).toUpperCase()+e.slice(1)}export{te as formPage};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ElicitationTarget } from '../../gateway-mcp/secret-store.js';
|
|
2
|
+
import type { PageColorScheme, PageContent, PageSite } from './types.js';
|
|
3
|
+
export declare function escapeHtml(value: string): string;
|
|
4
|
+
/** The API name, plus the scheme when the link names one scheme of a multi-scheme API. */
|
|
5
|
+
export declare function targetTitle({ name, schemeLabel, schemes }: ElicitationTarget): string;
|
|
6
|
+
export declare function code(value: string): string;
|
|
7
|
+
export declare function htmlDocument({ title, body }: PageContent, colorScheme: PageColorScheme | undefined): string;
|
|
8
|
+
export declare function siteHeader({ name, logo, host, colorScheme }: PageSite): string;
|
|
9
|
+
export declare const ICONS: {
|
|
10
|
+
readonly shield: '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M10 2.5 3.75 4.8v4.7c0 3.9 2.6 6.9 6.25 8 3.65-1.1 6.25-4.1 6.25-8V4.8L10 2.5Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="m7.3 10 1.9 1.9 3.6-3.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
11
|
+
readonly alert: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/><path d="m3.8 12.2 8.4-8.4" stroke="currentColor" stroke-width="1.5"/></svg>';
|
|
12
|
+
readonly warning: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 2.2 1.9 13h12.2L8 2.2Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M8 6.5v3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="11.3" r=".8" fill="currentColor"/></svg>';
|
|
13
|
+
readonly check: '<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="m4.5 9.2 3 3 6-6.4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
14
|
+
readonly cross: '<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="m5.5 5.5 7 7m0-7-7 7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>';
|
|
15
|
+
readonly clock: '<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><circle cx="9" cy="9" r="5.75" stroke="currentColor" stroke-width="1.6"/><path d="M9 6v3.2l2 1.3" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{pageStyles as l}from"./styles.js";function o(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function a({name:e,schemeLabel:r,schemes:t}){return t&&t.length>1?e:r?`${e} (${r})`:e}function h(e){return`<code>${o(e)}</code>`}function u({title:e,body:r},t){return`<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="robots" content="noindex">
|
|
7
|
+
<title>${o(e)}</title>
|
|
8
|
+
<style>${l(t)}</style>
|
|
9
|
+
</head>
|
|
10
|
+
<body>${r}</body>
|
|
11
|
+
</html>`}function k({name:e,logo:r,host:t,colorScheme:i}){const n=r?d(r,e??t,i):`<span class="site-name">${o(e??t)}</span>`,s=r||e?`<span class="site-host">${o(t)}</span>`:"";return`<header class="site">${n}${s}</header>`}function d(e,r,t){const i=n=>`<img class="site-logo" src="${o(n)}" alt="${o(r)}">`;return!e.dark||t==="light"?i(e.light):t==="dark"?i(e.dark):`<picture><source srcset="${o(e.dark)}" media="(prefers-color-scheme: dark)">${i(e.light)}</picture>`}const p={shield:'<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M10 2.5 3.75 4.8v4.7c0 3.9 2.6 6.9 6.25 8 3.65-1.1 6.25-4.1 6.25-8V4.8L10 2.5Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="m7.3 10 1.9 1.9 3.6-3.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',alert:'<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.5"/><path d="m3.8 12.2 8.4-8.4" stroke="currentColor" stroke-width="1.5"/></svg>',warning:'<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 2.2 1.9 13h12.2L8 2.2Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M8 6.5v3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="11.3" r=".8" fill="currentColor"/></svg>',check:'<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="m4.5 9.2 3 3 6-6.4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',cross:'<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="m5.5 5.5 7 7m0-7-7 7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',clock:'<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><circle cx="9" cy="9" r="5.75" stroke="currentColor" stroke-width="1.6"/><path d="M9 6v3.2l2 1.3" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>'};export{p as ICONS,h as code,o as escapeHtml,u as htmlDocument,k as siteHeader,a as targetTitle};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ElicitationTarget } from '../../gateway-mcp/secret-store.js';
|
|
2
|
+
import type { CredentialsOutcome, PageContent } from './types.js';
|
|
3
|
+
type Tone = 'success' | 'danger' | 'neutral' | 'warning';
|
|
4
|
+
export declare function outcomePage(target: ElicitationTarget, { action, schemes, stored }: CredentialsOutcome): PageContent;
|
|
5
|
+
export declare function declinedPage(): PageContent;
|
|
6
|
+
export declare function expiredPage(): PageContent;
|
|
7
|
+
/** A centered status card; `lines` are trusted HTML. */
|
|
8
|
+
export declare function statusPage(tone: Tone, title: string, lines: readonly string[]): PageContent;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=outcome-pages.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{ELICITATION_TTL_MINUTES as p}from"../../gateway-mcp/secret-store.js";import{credentialSchemesOf as $}from"./form-contract.js";import{ICONS as a,code as f,escapeHtml as r,targetTitle as k}from"./layout.js";const v={success:a.check,danger:a.cross,neutral:a.cross,warning:a.clock};function y(n,{action:e,schemes:o,stored:t}){const s=e==="saved",i=$(n).length>1,c=r(n.name),d=t.filter(m=>!o.includes(m)),g=i?`We ${e} ${u(o)} for ${c}.`:`We ${e} your credentials for ${r(k(n))}.`,h=t.length===0?`Calls to ${c} now go without credentials.`:d.length>0?`${s?"Also stored":"Still stored"}: ${u(d)}.`:"";return l(s?"success":"danger",s?"Credentials saved":"Credentials removed",[g,h,s?"Go back to your AI client and tell it that you saved them.":""])}function S(){return l("neutral","Link declined",["We saved nothing, and this link no longer works.","If you did not ask for this link, tell your AI client to stop."])}function A(){return l("warning","This link no longer works",[`The link is not valid, was already used, or is older than ${p} minutes.`,"Ask your AI client for a new link."])}function l(n,e,o){const t=o.filter(Boolean).map(i=>`<p>${i}</p>`).join(`
|
|
2
|
+
`),s=n==="warning"?"":'<p class="muted small">You can close this tab.</p>';return{title:e,body:`<div class="page narrow">
|
|
3
|
+
<main class="card outcome">
|
|
4
|
+
<span class="status-icon ${n}">${v[n]}</span>
|
|
5
|
+
<h1>${r(e)}</h1>
|
|
6
|
+
<div class="message">
|
|
7
|
+
${t}
|
|
8
|
+
${s}
|
|
9
|
+
</div>
|
|
10
|
+
</main>
|
|
11
|
+
</div>`}}function u(n){const e=n.map(f);return e.length>1?`${e.slice(0,-1).join(", ")} and ${e.at(-1)}`:e.join("")}export{S as declinedPage,A as expiredPage,y as outcomePage,l as statusPage};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RedoclyConfig } from '@redocly/config';
|
|
2
|
+
import type { GlobalData } from '../../../../../types/index.js';
|
|
3
|
+
import type { SiteBranding } from './types.js';
|
|
4
|
+
/** `logo` is the resolved theme logo from global data, whose paths point at served assets. */
|
|
5
|
+
export declare function resolveSiteBranding({ seo, logo, colorMode, }: {
|
|
6
|
+
seo?: RedoclyConfig['seo'];
|
|
7
|
+
logo?: GlobalData['logo'];
|
|
8
|
+
colorMode?: RedoclyConfig['colorMode'];
|
|
9
|
+
}): SiteBranding;
|
|
10
|
+
//# sourceMappingURL=site-branding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parseSrcSet as h}from"../../../../utils/attribute-parser.js";function o({seo:t,logo:e,colorMode:d}){const n=t?.title||t?.projectTitle||e?.altText||void 0,i=e?.srcSet?h(e.srcSet):new Map,r=s(i.get("light")??e?.image),a=s(i.get("dark")),c=f(d);return{...n?{name:n}:{},...r?{logo:{light:r,...a?{dark:a}:{}}}:{},...c?{colorScheme:c}:{}}}function f(t){if(t?.hide)return"light";if(t?.ignoreDetection)return t.modes?.[0]==="dark"?"dark":"light"}function s(t){return t?.startsWith("/")&&!t.startsWith("//")?t:void 0}export{o as resolveSiteBranding};
|