@redocly/redoc-reef 0.140.0-next.5 → 0.140.0-next.7
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 +72 -0
- package/dist/api-schemas/mcp-fetch-count.d.ts +2 -18
- package/dist/api-schemas/otel-traces.d.ts +7 -1345
- package/dist/api-schemas/otel-traces.js +1 -1
- package/dist/api-schemas/search-facets.d.ts +3 -31
- package/dist/api-schemas/search.d.ts +6 -52
- package/dist/cli/build/index.js +1 -1
- package/dist/cli/eject/resolveEjectParams.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +2 -0
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
- package/dist/compiled/@redocly/pii/index.mjs +1 -0
- package/dist/compiled/@redocly/pii/package.json +1 -0
- package/dist/markdoc/tags/openapi-code-sample.js +1 -1
- package/dist/server/api-routes/execute-api-route.js +1 -1
- package/dist/server/api-routes/run-api-routes-worker.js +1 -1
- package/dist/server/config/env-config.d.ts +24 -24
- package/dist/server/config/env-schema.d.ts +83 -326
- package/dist/server/config/env-schemas/api-urls.d.ts +2 -14
- package/dist/server/config/env-schemas/auth.d.ts +10 -32
- package/dist/server/config/env-schemas/catalog.d.ts +6 -9
- package/dist/server/config/env-schemas/database.d.ts +2 -8
- package/dist/server/config/env-schemas/environment-detection.d.ts +20 -18
- package/dist/server/config/env-schemas/feature-flags.d.ts +25 -33
- package/dist/server/config/env-schemas/organization-project.d.ts +3 -21
- package/dist/server/config/env-schemas/scorecards.d.ts +2 -6
- package/dist/server/config/env-schemas/search.d.ts +9 -15
- package/dist/server/config/env-schemas/server-config.d.ts +6 -31
- package/dist/server/config/env-schemas/site.d.ts +1 -5
- package/dist/server/config/env-schemas/ssr.d.ts +7 -12
- package/dist/server/config/env-schemas/telemetry.d.ts +1 -7
- package/dist/server/esbuild/plugins/themes-resolver.js +3 -3
- package/dist/server/external-plugins/resolve-external-plugins.js +1 -1
- package/dist/server/node-bundle-entry.js +1 -1
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/api-docs/store-definition-bundles.d.ts +6 -0
- package/dist/server/plugins/api-docs/store-definition-bundles.js +1 -1
- package/dist/server/plugins/config-parser/index.js +1 -1
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +1 -1
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +4 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -2
- 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/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 +10 -0
- package/dist/server/plugins/mcp/utils/available-tools.d.ts +5 -0
- package/dist/server/plugins/mcp/utils/available-tools.js +1 -0
- package/dist/server/plugins/mcp/workers/worker-context.d.ts +4 -0
- package/dist/server/plugins/mcp/workers/worker-context.js +1 -0
- package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +3 -3
- package/dist/server/store-config.d.ts +33 -0
- package/dist/server/store-config.js +1 -0
- package/dist/server/store.d.ts +10 -15
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/formatter.js +3 -3
- package/dist/server/types/plugins/api-routes.d.ts +4 -1
- package/dist/server/utils/envs/env-boolean-string.d.ts +9 -3
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.d.ts +2 -0
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.js +1 -1
- package/dist/server/utils/envs/interpolate-env-variables.d.ts +5 -1
- package/dist/server/utils/envs/interpolate-env-variables.js +1 -1
- package/dist/server/utils/envs/replace-env-variables-deep.d.ts +17 -9
- package/dist/server/utils/envs/replace-env-variables-deep.js +1 -1
- package/dist/server/web-server/middleware/jsonValidatorMiddleware.d.ts +556 -287
- package/dist/server/workers/mcp-tool-worker-methods.d.ts +7 -0
- package/dist/server/workers/mcp-tool-worker-methods.js +1 -0
- package/dist/server/workers/mcp-tool-worker-pool.d.ts +0 -1
- package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
- package/dist/server/workers/mcp-tool-worker.js +1 -1
- package/dist/server/workers/types.d.ts +4 -8
- package/dist/server/workers/worker-config.d.ts +33 -0
- package/dist/server/workers/worker-config.js +1 -0
- package/package.json +8 -8
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.d.ts +0 -4
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.d.ts +0 -13
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.d.ts +0 -36
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as A}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as M,getInternalOrigin as L}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as B,DEFAULT_ANONYMOUS_VISITOR_TEAM as H,RbacFeatures as j}from"../../../../constants/common.js";import{isObject as V}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as $}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as G}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as J}from"@modelcontextprotocol/server";import{createDocsMcpServer as K}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as Y,filterGraphqlDescriptionsByRbac as z}from"../utils.js";import{userSubject as W}from"../gateway-mcp/subject.js";import{ipRateLimitKey as X}from"../gateway-mcp/rate-limit/utils/ip-key.js";import{McpClientInputError as Q,createMethodNotAllowedError as Z,withErrorHandling as q}from"./errors.js";import{constructForbiddenResponse as x,constructInvalidTokenResponse as ee,constructUnauthorizedResponse as re,handleMcpAuth as oe}from"../auth/auth-handlers.js";import{isAssistantAnonymousToken as se}from"../auth/assistant-anonymous-token.js";import{shouldHandleMcpAuth as ne}from"../../../utils/rbac/should-handle-mcp-auth.js";import{extractTokenFromAuthHeader as ie}from"../utils/jwt.js";import{resolveMcpClient as te}from"../utils/mcp-client.js";import{randomUUID as ce}from"../../../utils/crypto/random-uuid.js";import{getPublicMcpEndpointStatus as ae}from"../utils/public-endpoint.js";import{narrowMcpConfigForCaller as pe}from"../gateway-mcp/caller-api-calls.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as de,SSE_KEEPALIVE_INTERVAL_MS as
|
|
1
|
+
import{logger as A}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as M,getInternalOrigin as L}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as B,DEFAULT_ANONYMOUS_VISITOR_TEAM as H,RbacFeatures as j}from"../../../../constants/common.js";import{isObject as V}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as $}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as G}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as J}from"@modelcontextprotocol/server";import{createDocsMcpServer as K}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as Y,filterGraphqlDescriptionsByRbac as z}from"../utils.js";import{userSubject as W}from"../gateway-mcp/subject.js";import{ipRateLimitKey as X}from"../gateway-mcp/rate-limit/utils/ip-key.js";import{McpClientInputError as Q,createMethodNotAllowedError as Z,withErrorHandling as q}from"./errors.js";import{constructForbiddenResponse as x,constructInvalidTokenResponse as ee,constructUnauthorizedResponse as re,handleMcpAuth as oe}from"../auth/auth-handlers.js";import{isAssistantAnonymousToken as se}from"../auth/assistant-anonymous-token.js";import{shouldHandleMcpAuth as ne}from"../../../utils/rbac/should-handle-mcp-auth.js";import{extractTokenFromAuthHeader as ie}from"../utils/jwt.js";import{resolveMcpClient as te}from"../utils/mcp-client.js";import{randomUUID as ce}from"../../../utils/crypto/random-uuid.js";import{getPublicMcpEndpointStatus as ae}from"../utils/public-endpoint.js";import{narrowMcpConfigForCaller as pe}from"../gateway-mcp/caller-api-calls.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as de,SSE_KEEPALIVE_INTERVAL_MS as le}from"../constants.js";import{withPathPrefix as me}from"@redocly/theme/core/utils";import{PUBLIC_MCP_ROUTE as fe}from"@redocly/theme/core/constants/mcp";import{canAccessFeature as ue}from"../../../utils/rbac.js";import{ANONYMOUS_AUTH_DETAILS as ge}from"../../../constants/rbac.js";const E="X-Redocly-AI-Metadata";function he(r){if(r)try{const e=JSON.parse(r);if(V(e))return e;A.warn(`Ignoring ${E} header: not a JSON object.`)}catch{A.warn(`Ignoring ${E} header: invalid JSON.`)}}function Ae(r,e){return new URL(r).searchParams.get("mode")==="tools"?"tools":e}function I(){return{...ge,email:"",idpAccessToken:void 0,idpId:void 0}}const Me=async(r,e,i)=>{const t=!!e?.config?.access?.requiresLogin,c=e?.config?.access?.rbac||{},y=i?.props?.config?.mcpMode??"tools",p=Ae(r.url,y),C=i?.props?.config?.gatewayFetchBudgetPerExec??B.budgetPerExec,U=i?.props?.config?.searchIgnoredRoutes??[],o=i,R=!!o?.props?.config?.isPublicEndpoint;let u;const T=r.headers.get("Authorization");if(R)e.user=I();else if(ne(t,c)){const{isAuthenticated:n,isTokenValid:d,isFirstPartyAnonymous:g,currentUser:l,accessToken:h}=await oe(r,e);if(g)e.user=I();else if(n)l&&(e.user=l),u=h;else{const a=M(r),m=ae(e.config)==="served"?`${a}${me(fe)}`:void 0;return d===!1?ee(a,m):re(a,m)}}else if(T){const n=ie(T)??void 0;u=(n?await se(n):!1)?void 0:n}const w={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[H],claims:e.user?.claims??{}};return ue(j.MCP,w,c,t)?await q(async()=>{const n=p==="code"&&(i?.props?.config?.elicitationEnabled??!1);if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP client (VS Code, Cursor, Claude Code, etc.) using this URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return Z();const d=o?.props?.config?.apiDescriptionsMap||{},g=o?.props?.config?.graphqlDescriptions||[],l=o?.props?.config?.mcpDocsServerName||de,{config:{mcp:h={}}}=e,a=Y(d,e.user,c,t),m=z(g,e.user,c,t),P=e.config.products?Object.values(e.config.products).map(s=>s?.name):[],D=h.docs?.name||l,f=he(r.headers.get(E)),_=o?.props?.tools||[],O=o?.props?.skillsBaseUrl||M(r),F=$(o?.props?.skills||[],e.user,c,t).map(s=>({slug:s.slug,name:s.name,description:s.description,content:s.content,uri:G(O,s.slug)})),S=await Ee(r),b=o?.props?.fetchCountSecret,k={name:D,tools:_,skills:F,context:{...e,config:{...e.config,mcp:pe(e.config.mcp,f)},configFile:o?.props?.configFile,accessToken:u,outdir:e.outdir||"",baseUrl:e.baseUrl||M(r),internalBaseUrl:L(r),apiDescriptionsMap:a,graphqlDescriptions:m,products:P,metadata:f,mcpMode:p,elicitationEnabled:n,gatewayFetchBudgetPerExec:C,fetchCountRequest:p==="code"&&b?{caller:{subject:W(e.user),ip:X(r)},secret:b}:void 0,searchIgnoredRoutes:U,clientIp:N(r),...te(r),requestId:ce(),messageId:typeof f?.messageId=="string"?f.messageId:void 0}},v=await K({...k,getKv:e.getKv});return await J(async()=>v,{keepAliveMs:le,onerror:s=>A.warn(`MCP handler: ${s.message}`)}).fetch(r,S!==void 0?{parsedBody:S}:void 0)},p):x()};async function Ee(r){try{return await r.json()}catch(e){throw new Q(e instanceof Error?e.message:String(e),{cause:e})}}var ze=Me;export{ze as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{withPathPrefix as g}from"@redocly/theme/core/utils";import{importApiRoutesHandler as h}from"../../../api-routes/import-api-routes-handlers.js";import{enhanceContext as D}from"../../../api-routes/helpers/enhance-context.js";import{telemetry as A}from"../../../telemetry/index.js";import{KvService as E}from"../../../persistence/kv/services/kv-service.js";import{envConfig as l}from"../../../config/env-config.js";import{acceptsHtml as R}from"../../../utils/ai-agent-detection.js";import{handleErrorPageRender as T}from"../../../web-server/utils.js";import{MCP_DOCS_SERVER_HANDLER_ID as _,MCP_NOT_ALLOWED_TEMPLATE_ID as w}from"../../../constants/mcp.js";import{resolvePublicBaseUrl as S}from"../../../web-server/utils/resolve-public-base-url.js";import{getForwardedOrigin as q}from"../../../web-server/utils/get-request-origin.js";import{applyEdgeRateLimit as C}from"../gateway-mcp/rate-limit/request-limiter/apply-edge-rate-limit.js";import{fetchCountSecret as O}from"../gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.js";async function
|
|
1
|
+
import{withPathPrefix as g}from"@redocly/theme/core/utils";import{importApiRoutesHandler as h}from"../../../api-routes/import-api-routes-handlers.js";import{enhanceContext as D}from"../../../api-routes/helpers/enhance-context.js";import{telemetry as A}from"../../../telemetry/index.js";import{KvService as E}from"../../../persistence/kv/services/kv-service.js";import{envConfig as l}from"../../../config/env-config.js";import{acceptsHtml as R}from"../../../utils/ai-agent-detection.js";import{handleErrorPageRender as T}from"../../../web-server/utils.js";import{MCP_DOCS_SERVER_HANDLER_ID as _,MCP_NOT_ALLOWED_TEMPLATE_ID as w}from"../../../constants/mcp.js";import{resolvePublicBaseUrl as S}from"../../../web-server/utils/resolve-public-base-url.js";import{getForwardedOrigin as q}from"../../../web-server/utils/get-request-origin.js";import{applyEdgeRateLimit as C}from"../gateway-mcp/rate-limit/request-limiter/apply-edge-rate-limit.js";import{fetchCountSecret as O}from"../gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.js";async function K(i,t,e){const n=t.req.raw;if(i.requestHandlerId===_&&n.method==="GET"&&R(n.headers.get("accept"))&&e.globalData.mcpData?.docs?.enabled)return T(t,e,{slug:i.slug},405,w);const r=t.get("auth"),o=await C(n,e);if(o)return o;const s=await e.resolveRouteStaticData(i)||{},c=g(i.slug),{requestHandlers:m}=await h(e.serverOutDir),p=m[i.requestHandlerId],d=(await p()).default,u=async()=>await E.getInstance({baseDbDir:e.serverOutDir,sqldRemoteDatabaseUrl:l.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:l.SQLD_REMOTE_DATABASE_AUTH_TOKEN}),f=D({honoCtx:t,ctx:{user:{teams:r.teams,email:r.claims.email,claims:r.claims,idpAccessToken:r.idpAccessToken,idpId:r.claims.idpId,isAuthenticated:r.isAuthenticated},config:e.config,outdir:e.outdir,baseUrl:q(t.req.raw)},telemetry:A,getKv:u}),a=await d(t.req.raw,f,{...s,props:{...s.props,routeSlug:c,outdir:e.outdir,fetchCountSecret:O(),skills:e.config.skills?.hide===!0?[]:e.getSkills(),skillsBaseUrl:S(e,t),configFile:e.configFile}});return a instanceof Response?a:typeof a=="string"?new Response(a,{headers:{"Content-Type":"text/plain"}}):new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}export{K as handleMcpRequest};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as C,MANAGE_API_CREDENTIALS_TOOL_NAME as k,SUBMIT_FEEDBACK_TOOL_NAME as S}from"../constants.js";import{isAnonymousSessionToolAvailable as U}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as w,manageApiCredentials as y,manageApiCredentialsSchema as H}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as h,executeToolTitle as I}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as R,CODE_MODE_TOOL_NAMES as M,FETCH_TOOL_NAME as B}from"../codemode/constants.js";import{buildCodeModeInstructions as F,buildExecuteDescription as x}from"../codemode/prompts.js";import{toToolListEntries as z}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as X,getActiveCapabilities as Y}from"../codemode/capabilities/index.js";import{describeToolsSchema as j,describeTools as G}from"../codemode/tools/describe-tools.js";import{availableTools as g}from"../utils/available-tools.js";import{resolveDocsSiteUrl as K}from"../utils/docs-site-url.js";import{isToolDisabledByCaller as b}from"../utils/disabled-tools.js";import{toRegisterToolConfig as N}from"../utils/tool-registration.js";import{createMcpServer as P,createToolDispatch as W,extractSerializableContext as q}from"./mcp-server.js";const J=new Set([...M].filter(s=>s!==S));function D(s,t){const e=t.schema;if(s)return e;const{sessionHandle:u,...T}=e.properties;return{...e,properties:T}}function Q(s){return Object.fromEntries(s.map(t=>[t.name,t.schema]))}async function pe({name:s,tools:t,context:e,skills:u=[],getKv:T}){const l=q(e),n=e.mcpMode==="code",c=n?Y(e):[],O=c.some(o=>o.id===B),m=n?await g(t.filter(o=>!M.has(o.name)),l):[],_=z(m,c),E=U(e)&&!b(C,e.metadata),v=n&&w(e)&&!b(k,e.metadata),p=P(s,n?F(O,_):void 0),A={getClientCapabilities:()=>p.server.getClientCapabilities(),getKv:T},f=W(n?{...l,sandboxToolSchemas:Q(m)}:l,A);if(n){const o=X(m,c,e.config?.mcp),r=[{tool:{...h,title:I(o),description:x(O,_,K(e.config?.seo?.siteUrl,e.baseUrl)),schema:D(E,h),annotations:o},callback:f(R)},{tool:j(m,c),callback:G(m,c,e)}],i=t.find(a=>a.name===S);i&&!b(i.name,e.metadata)&&r.push({tool:i,callback:f(i.name)});const d=t.find(a=>a.name===C);if(d&&E&&r.push({tool:d,callback:f(d.name)}),v){const a=H(e);r.push({tool:{...a,schema:D(E,a)},callback:y(l,A)})}for(const{tool:a,callback:L}of r)p.registerTool(a.name,N(a),L)}else{const o=t.filter(i=>!J.has(i.name)),r=new Set((await g(o,l)).map(i=>i.name));for(const i of o){const d=p.registerTool(i.name,N({...i,outputSchema:void 0}),f(i.name));r.has(i.name)||d.disable()}}for(const o of u)p.registerResource(o.slug,o.uri,{title:o.name,description:o.description,mimeType:"text/markdown"},async()=>({contents:[{uri:o.uri,mimeType:"text/markdown",text:o.content}]}));return p}export{pe as createDocsMcpServer};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{McpServer as U}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as _,MCP_TOOL_WORKER_KEY as O}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as
|
|
1
|
+
import{McpServer as U}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as _,MCP_TOOL_WORKER_KEY as O}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as F}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as L,stripAuthRequiredMeta as E,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{acceptedCredentialsLink as D,buildCredentialsAcceptedHint as K,buildCredentialsToolHint as j,buildUpstreamCredentialFallback as q,buildUpstreamCredentialInputRequired as v,credentialElicitationAnswer as H,dedupeElicitation as N,isStatelessRequest as P,schemeLabelOf as $,supportsUrlElicitation as B}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as y,resolveUpstreamApiAuth as W}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as G,resolveSecretSubject as V}from"../gateway-mcp/subject.js";import{toWorkerContext as Y}from"../workers/worker-context.js";const J=6e4;function de(e,t){return new U({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function pe(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,u=P(s.mcpReq),a=i?V(e.user,n.sessionHandle):{kind:"anonymous"},o=a.kind==="resolved"?a.subject:void 0;if(a.kind==="invalid")return{content:[{type:"text",text:a.message}],isError:!0};const c=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await F.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let l;const d=async()=>{l=await c();const m={toolName:r,args:n,context:Y({...e,upstreamSecrets:l}),extra:te(s)};return await _.exec(O,[m],{timeout:J})};let p=await d();const f=L(p);if(f.length>0&&i&&!o)return E(R(p,[{type:"text",text:G}]));if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${u?"2026-07-28":"2025"} clientElicitation=${Q(t)}`);const m=await t.getKv(),h=await X(e,f),w=f.map(C=>Z(C,h)),k=z(l),g=u?await x(e,s,w,o,m,k,h,t):await ee(e,w,o,m,k,h);switch(g.kind){case"inputRequired":return g.result;case"retry":p=await d();break;case"prependText":p=R(p,[{type:"text",text:g.text},...p.content]);break;case"none":break}}return E(p)}}function R(e,t){const{structuredContent:r,...n}=e;return{...n,content:t,isError:!0}}function Q(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function X(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await W(e,n));return r}function Z(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??y};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(b({api:r,scheme:s}));return t}function I(e,t){return e.status===401&&!t.has(b(e))}function T(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?$(r.schemes,n):void 0}function M(e,t){return e.map(r=>j(r,T(r,t))).join(`
|
|
2
2
|
|
|
3
|
-
`)}function A(e,t,r,n,
|
|
3
|
+
`)}function A(e,t,r,n,s){const[i,...u]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??y,c=i.schemes&&i.schemes.length>1?i.schemes:void 0,l=c?void 0:T(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...l?{schemeLabel:l}:{},...c?{acceptedSchemes:c}:{}},auth:a?.schemes[o]??{kind:"raw"},...a?{apiAuth:a}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:u.map(d=>d.name)}}}async function x(e,t,r,n,s,i,u,a){const o=H(t.mcpReq.inputResponses);if(o==="declined")return{kind:"none"};const c=r.filter(d=>I(d,i));if(c.length===0)return{kind:"prependText",text:M(r,u)};if(o==="accepted"){const d=await D(t.mcpReq.requestState(),{kv:s,subject:n,baseUrl:e.baseUrl??"",apis:c.map(f=>f.api)}),p=d?.apiName??c[0].name;return{kind:"prependText",text:K(p,d?.url)}}const l=A(e,c,n,s,u);return B(a?.getClientCapabilities())?{kind:"inputRequired",result:await v(l)}:{kind:"prependText",text:await q(l)}}async function ee(e,t,r,n,s,i){const u=t.filter(c=>I(c,s));if(u.length===0)return{kind:"prependText",text:M(t,i)};const a=A(e,u,r,n,i);return{kind:"prependText",text:await N(`${r}:${b(u[0])}`,()=>q(a))}}function te(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function me(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,fetchCountRequest:e.fetchCountRequest,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,requestId:e.requestId,messageId:e.messageId,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,configFile:e.configFile,fs:void 0}}export{de as createMcpServer,pe as createToolDispatch,me as extractSerializableContext};
|
|
@@ -6,6 +6,7 @@ import type { McpToolSchema } from '../../types';
|
|
|
6
6
|
import type { Skill } from '../../types/plugins/skills.js';
|
|
7
7
|
import type { UpstreamSecrets } from './gateway-mcp/secret-store.js';
|
|
8
8
|
import type { SiteBranding } from './handlers/credentials-page/types.js';
|
|
9
|
+
import type { StoreConfigFile, WorkerConfig } from '../../workers/worker-config.js';
|
|
9
10
|
type ObjectValues<T> = T[keyof T];
|
|
10
11
|
export type McpServerType = ObjectValues<typeof McpServerType>;
|
|
11
12
|
export type McpErrorCodeTypes = ObjectValues<typeof McpErrorCodes>;
|
|
@@ -40,6 +41,7 @@ export type McpDocsStaticData = PageStaticData & {
|
|
|
40
41
|
tools?: McpToolSchema[];
|
|
41
42
|
skills?: Skill[];
|
|
42
43
|
skillsBaseUrl?: string;
|
|
44
|
+
configFile?: StoreConfigFile;
|
|
43
45
|
};
|
|
44
46
|
};
|
|
45
47
|
export type CredentialsPageStaticData = PageStaticData & {
|
|
@@ -117,6 +119,11 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
|
|
|
117
119
|
internalBaseUrl?: string;
|
|
118
120
|
sandboxToolSchemas?: Record<string, Record<string, unknown>>;
|
|
119
121
|
fs?: McpToolFileSystem;
|
|
122
|
+
configFile?: StoreConfigFile;
|
|
123
|
+
};
|
|
124
|
+
/** `McpToolContext` as it crosses to a worker. */
|
|
125
|
+
export type McpToolWorkerContext = Omit<McpToolContext, 'config' | 'fs' | 'configFile'> & {
|
|
126
|
+
config: WorkerConfig;
|
|
120
127
|
};
|
|
121
128
|
export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse | McpToolJsonValue>;
|
|
122
129
|
export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
|
|
@@ -130,6 +137,9 @@ export type McpToolExecutionParams = {
|
|
|
130
137
|
context: McpToolContext;
|
|
131
138
|
extra: McpToolExtra;
|
|
132
139
|
};
|
|
140
|
+
export type McpToolWorkerParams = Omit<McpToolExecutionParams, 'context'> & {
|
|
141
|
+
context: McpToolWorkerContext;
|
|
142
|
+
};
|
|
133
143
|
export type CustomMcpToolsState = {
|
|
134
144
|
registeredToolNames: string[];
|
|
135
145
|
warnedNoOutputSchemaTools: Set<string>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpToolSchema } from '../../../types';
|
|
2
|
+
import type { McpToolContext } from '../types.js';
|
|
3
|
+
/** The candidates this request may use. Asks the worker pool only when a candidate is gated. */
|
|
4
|
+
export declare function availableTools(candidates: McpToolSchema[], context: McpToolContext): Promise<McpToolSchema[]>;
|
|
5
|
+
//# sourceMappingURL=available-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as m,MCP_TOOL_AVAILABILITY_KEY as s}from"../../../workers/mcp-tool-worker-pool.js";import{toWorkerContext as f}from"../workers/worker-context.js";import{isToolDisabledByCaller as p}from"./disabled-tools.js";async function d(o,r){const a=o.filter(t=>!p(t.name,r.metadata)),e=a.filter(t=>t.hasAvailabilityGate).map(t=>t.name);if(e.length===0)return a;let i;try{i=await m.exec(s,[{toolNames:e,context:f(r)}],{timeout:1e4})}catch(t){return l(a,t instanceof Error?t.message:String(t))}return!i||typeof i!="object"?l(a,"the worker returned no availability map"):a.filter(t=>i[t.name]!==!1)}function l(o,r){const a=o.filter(e=>e.hasAvailabilityGate);return n.warn(`MCP tool availability is unknown (${r}); the tool list drops the gated tools: ${a.map(e=>e.name).join(", ")}.`),o.filter(e=>!e.hasAvailabilityGate)}export{d as availableTools};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpToolContext, McpToolWorkerContext } from '../types.js';
|
|
2
|
+
export declare function toWorkerContext({ config, configFile, fs: _fs, ...context }: McpToolContext): McpToolWorkerContext;
|
|
3
|
+
export declare function fromWorkerContext(context: McpToolWorkerContext): McpToolContext;
|
|
4
|
+
//# sourceMappingURL=worker-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readWorkerConfig as f,toWorkerConfig as t}from"../../../workers/worker-config.js";function g({config:o,configFile:r,fs:e,...n}){return{...n,config:t(o,r)}}function c(o){return{...o,config:f(o.config)}}export{c as fromWorkerContext,g as toWorkerContext};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import r from"react";import t from"styled-components";import{flexRender as g}from"@tanstack/react-table";const w=({headerGroups:e,gridTemplateColumns:i,groupHeaderTitle:
|
|
1
|
+
import r from"react";import t from"styled-components";import{flexRender as g}from"@tanstack/react-table";const w=({headerGroups:e,gridTemplateColumns:i,groupHeaderTitle:d})=>r.createElement(p,null,d&&r.createElement(u,{gridTemplateColumns:i,role:"row"},r.createElement(c,{gridColumn:"1",role:"columnheader"}),r.createElement(c,{gridColumn:"2 / -1",role:"columnheader"},r.createElement("span",null,d))),e.map((a,m)=>r.createElement(b,{key:`header-group-${m}`,gridTemplateColumns:i,role:"row"},a.headers.map((o,s)=>{const l=g(o.column.columnDef.header,o.getContext()),n=o.column.getIsSorted();return r.createElement(x,{key:o.id,gridColumn:s+1,$sortable:o.column.getCanSort(),role:"columnheader","aria-sort":n==="asc"?"ascending":n==="desc"?"descending":void 0},o.column.getCanSort()?r.createElement(h,{type:"button",onClick:o.column.getToggleSortingHandler()},l,r.createElement(f,{"aria-hidden":"true"},n?n==="desc"?"\u25BE":"\u25B4":"\u21D5")):l)})))),p=t.div`
|
|
2
2
|
border: 1px solid var(--border-color-primary);
|
|
3
3
|
min-width: 775px;
|
|
4
4
|
`,u=t.div`
|
|
@@ -37,7 +37,7 @@ import r from"react";import t from"styled-components";import{flexRender as g}fro
|
|
|
37
37
|
&:first-child {
|
|
38
38
|
justify-content: flex-start;
|
|
39
39
|
}
|
|
40
|
-
`,
|
|
40
|
+
`,h=t.button`
|
|
41
41
|
display: block;
|
|
42
42
|
width: 100%;
|
|
43
43
|
height: 100%;
|
|
@@ -50,6 +50,6 @@ import r from"react";import t from"styled-components";import{flexRender as g}fro
|
|
|
50
50
|
color: inherit;
|
|
51
51
|
text-align: inherit;
|
|
52
52
|
cursor: pointer;
|
|
53
|
-
`,
|
|
53
|
+
`,f=t.span`
|
|
54
54
|
font-family: monospace;
|
|
55
55
|
`;export{w as GridHeader};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RedoclyConfig } from '@redocly/config';
|
|
2
|
+
import type { WildcardRedirectsTree } from './types';
|
|
3
|
+
import { readEnvVariable } from './utils/envs/read-env-variable.js';
|
|
4
|
+
export type ComputedRedoclyConfig = {
|
|
5
|
+
configFilePath: string;
|
|
6
|
+
linkTags?: string;
|
|
7
|
+
headScriptTags?: string;
|
|
8
|
+
postBodyScriptTags?: string;
|
|
9
|
+
preBodyScriptTags?: string;
|
|
10
|
+
wildcardRedirectsTree: WildcardRedirectsTree;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
};
|
|
13
|
+
export type StoreConfig = WithRequired<RedoclyConfig, 'redirects'> & ComputedRedoclyConfig;
|
|
14
|
+
export declare function createDefaultStoreConfig(): StoreConfig;
|
|
15
|
+
/** Resolves the env placeholders in a copy of `entries` and normalizes `seo.siteUrl`. */
|
|
16
|
+
export declare function resolveConfigEntries(entries: Partial<RedoclyConfig>): {
|
|
17
|
+
config: Partial<RedoclyConfig>;
|
|
18
|
+
unsetEnvVars: string[];
|
|
19
|
+
replacedValues: Record<string, {
|
|
20
|
+
original: string;
|
|
21
|
+
replaced: string;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The store config of a build output: the defaults, overridden by the parsed JSON of its config
|
|
26
|
+
* file, which this changes in place. `env` holds each value that `readEnv` returned: a reader of
|
|
27
|
+
* only these values gives the same config. The partials stay JSON, never `undefined`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveStoreConfig(fileEntries: Partial<RedoclyConfig>, readEnv?: typeof readEnvVariable): {
|
|
30
|
+
config: StoreConfig;
|
|
31
|
+
env: Record<string, string>;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=store-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{removeTrailingSlash as a}from"../utils/url/remove-trailing-slash.js";import{MARKDOC_PARTIALS_DATA_KEY as c}from"./constants/common.js";import{readEnvVariable as l}from"./utils/envs/read-env-variable.js";import{replaceEnvVariablesDeep as f,replaceEnvVariablesInPlace as u}from"./utils/envs/replace-env-variables-deep.js";function d(){return{configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}}}function S(e){const{resolvedObj:r,unsetEnvVars:o,replacedValues:i}=f(e);return s(r),{config:r,unsetEnvVars:o,replacedValues:i}}function U(e,r=l){const o={};u(e,t=>{const n=r(t);return n!==void 0&&(o[t]=n),n}),s(e);const i={...d(),...e};return i[c]||={},{config:i,env:o}}function s(e){const r=e.seo?.siteUrl?.trim();r&&(e.seo={...e.seo,siteUrl:URL.canParse(r)?new URL(r).origin:a(r)})}export{d as createDefaultStoreConfig,S as resolveConfigEntries,U as resolveStoreConfig};
|
package/dist/server/store.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type Node } from '@redocly/markdoc';
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
3
|
import type { CommonError, GlobalData } from '../types/index.js';
|
|
4
|
-
import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts,
|
|
4
|
+
import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts, StaticFilePaths, RedirectOptions, McpToolRegistration, McpToolSchema, MarkdocOptions } from './types';
|
|
5
5
|
import type { Skill } from './types/plugins/skills.js';
|
|
6
6
|
import type { RedoclyConfig, RedirectConfig, CompilationError, PageStaticData } from '@redocly/config';
|
|
7
7
|
import type { SearchFacet } from '@redocly/theme/core/types';
|
|
8
8
|
import type { BundledApiDefinition } from './plugins/api-docs/loader.js';
|
|
9
9
|
import type { SearchEngine } from './plugins/search/engines/search-engine.js';
|
|
10
|
+
import type { StoreConfig } from './store-config.js';
|
|
11
|
+
import type { StoreConfigFile } from './workers/worker-config.js';
|
|
10
12
|
import { KvService } from './persistence/kv/services/kv-service.js';
|
|
11
13
|
export declare const USER_DEFINED_API_FUNCTIONS_COUNTER_KEY = "userDefinedApiFunctions";
|
|
12
14
|
type LifecycleEventType = 'global-data-updated' | 'shared-data-updated' | 'routes-updated' | 'build-updated' | 'build-started' | 'errors-updated' | 'pages-updated';
|
|
@@ -16,15 +18,6 @@ export type StoreOptions = {
|
|
|
16
18
|
serverOutDir: string;
|
|
17
19
|
serverMode?: boolean;
|
|
18
20
|
};
|
|
19
|
-
export type ComputedRedoclyConfig = {
|
|
20
|
-
configFilePath: string;
|
|
21
|
-
linkTags?: string;
|
|
22
|
-
headScriptTags?: string;
|
|
23
|
-
postBodyScriptTags?: string;
|
|
24
|
-
preBodyScriptTags?: string;
|
|
25
|
-
wildcardRedirectsTree: WildcardRedirectsTree;
|
|
26
|
-
[key: string]: unknown;
|
|
27
|
-
};
|
|
28
21
|
export declare class Store {
|
|
29
22
|
#private;
|
|
30
23
|
routesBySlug: Map<string, PageRouteDetails>;
|
|
@@ -62,7 +55,9 @@ export declare class Store {
|
|
|
62
55
|
globalData: GlobalData;
|
|
63
56
|
/** Whether `POST /authorize` mints dev sessions: set by `realm develop` (unless `--no-dev-login`) and `realm build --devLogin`. */
|
|
64
57
|
devLogin: boolean;
|
|
65
|
-
config:
|
|
58
|
+
config: StoreConfig;
|
|
59
|
+
/** Set when the store loads from a build output: the workers then read the config from this file. */
|
|
60
|
+
configFile?: StoreConfigFile;
|
|
66
61
|
serverMode: boolean;
|
|
67
62
|
serverOutDir: string;
|
|
68
63
|
outdir: string;
|
|
@@ -157,10 +152,10 @@ export declare class Store {
|
|
|
157
152
|
resolveRouteStaticData(route: RouteDetails, _context?: LifecycleContext, skipLastModified?: boolean): Promise<PageStaticData>;
|
|
158
153
|
addSsrComponents(components: JSX.Element[] | string[], position: 'head' | 'preBody' | 'postBody'): void;
|
|
159
154
|
clear: () => void;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
static
|
|
155
|
+
/** Writes the files that `fromServerFiles` reads. The config file keeps the env placeholders. */
|
|
156
|
+
writeServerFiles(): Promise<void>;
|
|
157
|
+
/** Loads the store from the files of a build output. The config resolves from the current env. */
|
|
158
|
+
static fromServerFiles(options: StoreOptions): Promise<Store>;
|
|
164
159
|
getConfigWithEnvPlaceholders(): Promise<RedoclyConfig>;
|
|
165
160
|
reportUnsetEnvVars(): Promise<void>;
|
|
166
161
|
}
|
package/dist/server/store.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import A from"@redocly/markdoc";import{parseAndResolveMarkdoc as T}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as M}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O,MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as k}from"./constants/common.js";import{GATED_MARKDOC_TAGS as R}from"./constants/entitlements.js";import{isObject as L}from"../utils/guards/is-object.js";import{mapObject as H}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as D}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as u}from"../utils/path/normalize-route-slug.js";import{isLocalLink as S}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as h}from"./tools/notifiers/logger.js";import{sha1 as F}from"./utils/crypto/sha1.js";import{envConfig as G,setEnv as _}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{SandboxContext as I}from"./utils/sandbox-context.js";import{writeSharedData as N}from"./utils/index.js";import{renderComponents as V}from"./ssr/render.js";import{readStaticData as q,writeStaticData as j}from"./utils/static-data.js";import{getMarkdocOptions as U}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as v}from"./entitlements/entitlements-provider.js";import{isRouteReserved as x}from"./plugins/get-reserved-routes.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as J}from"./utils/globs.js";import{replaceEnvVariablesDeep as W}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as $}from"./utils/redirects/find-redirect.js";import{followRedirectChain as z}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as Y}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Z}from"../cli/telemetry/helpers/trace-step.js";const E={routesBySlug:"map",staticFilePaths:"object",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},P="PLAN_GATES",Q=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],ke="userDefinedApiFunctions";class b{routesBySlug=new Map;staticFilePaths={};replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#h=Promise.resolve();#u;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:r}){this.#i=s,this.outdir=e,this.serverMode=t,this.serverOutDir=r,I.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(a=>{this.#n=a})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#a.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const r of this.listeners.get(e)||new Set)s?r(s,...t):r(...t)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#h])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#h=new Promise(e=>{this.#u=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#u?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Z("com.redocly.build.reloadMarkdocOptions",async()=>{const e=v.instance(),s=await U(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([r])=>R[r]!=null?e.canAccessFeature(R[r]):!0));this.#o={...s,tags:t}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:r})=>{const{data:{info:a,ast:i},compoundHash:l}=await T(e,this.markdocOptions,{actions:this,context:s},r);for(const o of a.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,o,o);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(o),this.sharedDataDeps.set(n,c)}}for(const o of a.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(o),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(o),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&a.partials?.length)for(const o of t.routeSlugs){const n=this.routesPartials.get(o)||[];for(const c of a.partials)n.includes(c)||n.push(c);this.routesPartials.set(o,n)}return{info:a,ast:i,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setStaticFilePaths=e=>{this.staticFilePaths=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const l of s)for(const o in this.replacedEnvVars)if(o===l||o.startsWith(`${l}:`)){const n=o.split(":"),{error:c,value:d}=y(e,n);(c||d!==this.replacedEnvVars[o].replaced)&&delete this.replacedEnvVars[o]}const{resolvedObj:t,unsetEnvVars:r,replacedValues:a}=W(e);for(const l of r)this.unsetEnvVars.add(l);Object.assign(this.replacedEnvVars,a);const i=t.seo?.siteUrl?.trim();i&&(t.seo={...t.seo,siteUrl:URL.canParse(i)?new URL(i).origin:D(i)}),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!v.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const i=u(e).toLowerCase();this.config.redirects[i]=s;const{trackOriginalSource:l=!0}=t,o=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(o)&&!o.includes(i)&&o.push(i),i.endsWith("*")&&Y(this.config.wildcardRedirectsTree,i)};getRedirect=e=>{const s=u(e).toLowerCase(),t=$(s,this.config.redirects,this.config.wildcardRedirectsTree,this.staticFilePaths);if(!t)return null;if(S(t.to)){const r=u(t.to).toLowerCase();if(!r.endsWith("*")&&z(r,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#t[e]===t)return e;const r=JSON.stringify(s),a=t??F(r);return this.#t[e]===a||(this.#t[e]=a,await N(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const r=D(e),a=this.routesSharedData.get(r)||{};a[s]=t,this.routesSharedData.set(r,a),h.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const r=this.getGlobalConfig(k)||{},a=new Set(t),i=Array.from(t);for(let o=0;o<i.length;o++){const n=i[o],c=r[n]?.partials??[];for(const d of c)a.has(d)||(a.add(d),i.push(d))}const l={};for(const o of a)s[o]&&(l[o]=s[o]);return l};addRoute=e=>{const t={...J(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),h.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const r=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const i=M(e,g,a.code,r);this.addRouteSharedData(i,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),h.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s){const r=this.mcpToolHandlers.get(t.name);r&&r.importPath!==e&&h.warn('MCP tool "%s" from %s overwrites the tool registered from %s',t.name,e,r.importPath),this.mcpToolHandlers.set(t.name,{...t,importPath:e}),h.verbose("Created MCP tool %s",t.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const s of e){const t=this.mcpToolHandlers.get(s);t&&this.mcpToolHandlers.set(s,{...t,hasAvailabilityGate:!0})}};addSkills=e=>{for(const s of e)this.skills.set(s.slug,s),h.verbose("Discovered skill %s",s.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const s of e)this.mcpToolHandlers.delete(s)};addMiddleware=e=>{this.middleware.push(e),h.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(i=>i.name.toLowerCase())),a=[...(this.config.responseHeaders[e]??[]).filter(i=>!t.has(i.name.toLowerCase())),...s];this.config.responseHeaders[e]=a};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,r=this.getRedirect(e);return t&&r?this.routesBySlug.get(u(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||x(e,this.getConfig()))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!S(s.to))return!0;const t=u(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(r=>e===g?!K(r.fsPath):r.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&j(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return q(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},a=await e.getStaticData?.(e,r)||{},i=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>i.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const o=this.getGlobalConfig("seo"),n=a?.frontmatter||{};return{...a,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(i),metadata:{...a?.props?.metadata,...e.metadata},seo:{title:O,...o,...a.props?.seo,siteUrl:o?.siteUrl},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):V(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,r]of Object.entries(E))switch(r){case"map":{const a=Array.from(this[t].entries());e.push([t,a]);break}case"object":if(t==="config"){e.push([t,await this.getConfigWithEnvPlaceholders()]);break}e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[P]=G.PLAN_GATES,s}static fromJson(e,s){const t=new b(s);for(const[a,i]of Object.entries(E))switch(i){case"map":t[a]=new Map(e[a]);break;case"object":if(a==="config"){t.setGlobalConfig(e[a]);break}t[a]=e[a];break;default:throw new Error("Invalid format")}t.config[m]=X(t.config[m]||{});const r=e[P];return r&&_("PLAN_GATES",r),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],r=s.split(":"),a=r.pop(),{error:i,value:l}=y(e,r);if(i||!L(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[a]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Q.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await w.panicOnBuildContentError(s)}}function X(C){return H(C,e=>A.Ast.fromJSON(JSON.stringify(e)))}export{b as Store,ke as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
1
|
+
import k from"@redocly/markdoc";import{writeFileSync as D}from"node:fs";import{readFile as R}from"node:fs/promises";import{join as g}from"node:path";import{parseAndResolveMarkdoc as F}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as L}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as m}from"../constants/common.js";import{DEFAULT_TITLE as H,MARKDOC_PARTIALS_DATA_KEY as y,MARKDOC_PARTIALS_DEPS_KEY as G}from"./constants/common.js";import{GATED_MARKDOC_TAGS as v}from"./constants/entitlements.js";import{isObject as _}from"../utils/guards/is-object.js";import{mapObject as N}from"../utils/object/map-object.js";import{getValueDeep as w}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as B}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as u}from"../utils/path/normalize-route-slug.js";import{isLocalLink as E}from"../utils/path/is-local-link.js";import{reporter as P}from"./tools/notifiers/reporter.js";import{logger as h}from"./tools/notifiers/logger.js";import{sha1 as I}from"./utils/crypto/sha1.js";import{envConfig as j,setEnv as V}from"./config/env-config.js";import{KvService as q}from"./persistence/kv/services/kv-service.js";import{SandboxContext as J}from"./utils/sandbox-context.js";import{isAllowedEnv as U}from"./utils/envs/get-api-route-allowed-env-variables.js";import{ensureDir as x,writeSharedData as K}from"./utils/index.js";import{renderComponents as W}from"./ssr/render.js";import{readStaticData as $,writeStaticData as z}from"./utils/static-data.js";import{getMarkdocOptions as Y}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as C}from"./entitlements/entitlements-provider.js";import{isRouteReserved as Z}from"./plugins/get-reserved-routes.js";import{isL10nPath as Q}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as X}from"./utils/globs.js";import{createDefaultStoreConfig as ee,resolveConfigEntries as te,resolveStoreConfig as se}from"./store-config.js";import{findRedirect as re}from"./utils/redirects/find-redirect.js";import{followRedirectChain as oe}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as ae}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as ie}from"../cli/telemetry/helpers/trace-step.js";const b={routesBySlug:"map",staticFilePaths:"object",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},O="store.json",A="store-config.json",T="PLAN_GATES",ne=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Ue="userDefinedApiFunctions";class S{routesBySlug=new Map;staticFilePaths={};replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#a=void 0;config=ee();configFile;#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#h=Promise.resolve();#u;#e=!1;#r=0;#f=0;#o=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:r}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=r,J.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(o=>{this.#n=o})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#o.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const r of this.listeners.get(e)||new Set)t?r(t,...s):r(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#h])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#o.values())this.runListeners(...e);this.#o.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#h=new Promise(e=>{this.#u=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#u?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await ie("com.redocly.build.reloadMarkdocOptions",async()=>{const e=C.instance(),t=await Y(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([r])=>v[r]!=null?e.canAccessFeature(v[r]):!0));this.#a={...t,tags:s}})}get markdocOptions(){return{...this.#a,partials:this.getGlobalConfig(y),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>q.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:r})=>{const{data:{info:o,ast:a},compoundHash:c}=await F(e,this.markdocOptions,{actions:this,context:t},r);for(const i of o.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const l=this.sharedDataDeps.get(n)||new Set;l.add(i),this.sharedDataDeps.set(n,l)}}for(const i of o.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const l=this.routesDynamicComponents.get(n)||new Set;l.add(i),this.routesDynamicComponents.set(n,l)}for(const n of s?.sharedDataIds||[]){const l=this.sharedDataMarkdocComponents.get(n)||new Set;l.add(i),this.sharedDataMarkdocComponents.set(n,l)}}if(s?.routeSlugs&&o.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const l of o.partials)n.includes(l)||n.push(l);this.routesPartials.set(i,n)}return{info:o,ast:a,compoundHash:c}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setStaticFilePaths=e=>{this.staticFilePaths=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const a of t)for(const c in this.replacedEnvVars)if(c===a||c.startsWith(`${a}:`)){const i=c.split(":"),{error:n,value:l}=w(e,i);(n||l!==this.replacedEnvVars[c].replaced)&&delete this.replacedEnvVars[c]}const{config:s,unsetEnvVars:r,replacedValues:o}=te(e);for(const a of r)this.unsetEnvVars.add(a);Object.assign(this.replacedEnvVars,o),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!C.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const a=u(e).toLowerCase();this.config.redirects[a]=t;const{trackOriginalSource:c=!0}=s,i=this.getGlobalConfig("originalRedirectSources");c&&Array.isArray(i)&&!i.includes(a)&&i.push(a),a.endsWith("*")&&ae(this.config.wildcardRedirectsTree,a)};getRedirect=e=>{const t=u(e).toLowerCase(),s=re(t,this.config.redirects,this.config.wildcardRedirectsTree,this.staticFilePaths);if(!s)return null;if(E(s.to)){const r=u(s.to).toLowerCase();if(!r.endsWith("*")&&oe(r,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const r=JSON.stringify(t),o=s??I(r);return this.#t[e]===o||(this.#t[e]=o,await K(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const r=B(e),o=this.routesSharedData.get(r)||{};o[t]=s,this.routesSharedData.set(r,o),h.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(y)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const r=this.getGlobalConfig(G)||{},o=new Set(s),a=Array.from(s);for(let i=0;i<a.length;i++){const n=a[i],l=r[n]?.partials??[];for(const d of l)o.has(d)||(o.add(d),a.push(d))}const c={};for(const i of o)t[i]&&(c[i]=t[i]);return c};addRoute=e=>{const s={...X(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),h.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const r=[m,...this.lifecycleContext?.fs.localeFolders||[]].map(o=>({code:o,name:o}));for(const o of r){const a=L(e,m,o.code,r);this.addRouteSharedData(a,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),h.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t){const r=this.mcpToolHandlers.get(s.name);r&&r.importPath!==e&&h.warn('MCP tool "%s" from %s overwrites the tool registered from %s',s.name,e,r.importPath);const o=s.hasAvailabilityGate??(r?.importPath===e?r.hasAvailabilityGate:void 0);this.mcpToolHandlers.set(s.name,{...s,importPath:e,hasAvailabilityGate:o}),h.verbose("Created MCP tool %s",s.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const t of e){const s=this.mcpToolHandlers.get(t);s&&this.mcpToolHandlers.set(t,{...s,hasAvailabilityGate:!0})}};addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),h.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const t of e)this.mcpToolHandlers.delete(t)};addMiddleware=e=>{this.middleware.push(e),h.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(a=>a.name.toLowerCase())),o=[...(this.config.responseHeaders[e]??[]).filter(a=>!s.has(a.name.toLowerCase())),...t];this.config.responseHeaders[e]=o};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,r=this.getRedirect(e);return s&&r?this.routesBySlug.get(u(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||Z(e,this.getConfig()))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!E(t.to))return!0;const s=u(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=m)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(r=>e===m?!Q(r.fsPath):r.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&z(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return $(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:l,context:d,resource:f})=>this.parseMarkdoc({input:l,context:d,deps:{routeSlugs:[e.slug]},resource:f})},o=await e.getStaticData?.(e,r)||{},a=new Set(this.routesDynamicComponents.get(e.slug)),c=this.routesSharedData.get(e.slug)||{};for(const l of Object.values(c)){const d=this.sharedDataMarkdocComponents.get(l);d&&d.forEach(p=>a.add(p));const f=this.sharedDataDeps.get(l);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=o?.frontmatter||{};return{...o,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...o.props,dynamicMarkdocComponents:Array.from(a),metadata:{...o?.props?.metadata,...e.metadata},seo:{title:H,...i,...o.props?.seo,siteUrl:i?.siteUrl},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):W(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};#p(){const e=[];for(const[s,r]of Object.entries(b))switch(r){case"map":{const o=Array.from(this[s].entries());e.push([s,o]);break}case"object":e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[T]=j.PLAN_GATES,t}static#g(e,t){const s=new S(t);for(const[o,a]of Object.entries(b))switch(a){case"map":s[o]=new Map(e[o]);break;case"object":s[o]=e[o];break;default:throw new Error("Invalid format")}const r=e[T];return r&&V("PLAN_GATES",r),s}async writeServerFiles(){x(this.serverOutDir),D(g(this.serverOutDir,O),JSON.stringify(this.#p())),D(g(this.serverOutDir,A),JSON.stringify(await this.getConfigWithEnvPlaceholders()))}static async fromServerFiles(e){const t=g(e.serverOutDir,A),{config:s,env:r}=se(JSON.parse(await R(t,"utf8")));s[y]=ce(s[y]);const o=JSON.parse(await R(g(e.serverOutDir,O),"utf8")),a=S.#g(o,e);a.config=s;const c=Object.fromEntries(Object.entries(r).filter(([i])=>U(i)));return a.configFile={path:t,env:c,config:{...s}},a}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],r=t.split(":"),o=r.pop(),{error:a,value:c}=w(e,r);if(a||!_(c)&&!Array.isArray(c)){await P.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}c[o]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!ne.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await P.panicOnBuildContentError(t)}}function ce(M){return N(M,e=>k.Ast.fromJSON(JSON.stringify(e)))}export{S as Store,Ue as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import*as E from"node:path";import{envConfig as R}from"../../config/env-config.js";import{maskEmail as T
|
|
2
|
-
`},y=({context:e,message:
|
|
3
|
-
`},D=e=>(e%500<100?x:e%400<100?b:A)(`status="${e}"`),j=()=>{const e=new Date().getTimezoneOffset()*6e4;return new Date(Date.now()-e).toISOString().slice(0,-1)},V=e=>
|
|
1
|
+
import*as E from"node:path";import{envConfig as R}from"../../config/env-config.js";import{maskEmail as T,maskSubject as C,removePii as w,removePiiFromUrl as $}from"../../../compiled/@redocly/pii/index.mjs";import{red as x,green as A,bold as F,blue as l,gray as r,yellow as b,cyan as v}from"./helpers/colors.js";function P(e,s){return s?e:w(e)}var n;(function(e){e.INFO="INFO",e.WARN="WARN",e.ERROR="ERROR",e.SUCCESS="SUCCESS",e.VERBOSE="VERBOSE",e.HTTP="HTTP"})(n||(n={}));const I={[n.VERBOSE]:0,[n.HTTP]:1,[n.INFO]:2,[n.SUCCESS]:2,[n.WARN]:3,[n.ERROR]:4};function J(e,s){return I[e]>=I[s]}function W(e){if(!e)return;const s=e.toUpperCase();if(s in n)return s}const H={[n.INFO]:l,[n.SUCCESS]:A,[n.WARN]:b,[n.ERROR]:x,[n.HTTP]:v,[n.VERBOSE]:r},N={"%ap":e=>l(E.resolve(e)),"%rp":e=>l(E.relative(process.cwd(),e)),"%s":e=>e?.toString(),"%c":e=>l(e)},M={format(e){return R.REDOCLY_LOG_FORMAT==="JSON"?y(e):U(e)},interpolate(e,...s){const u=Object.keys(N).map(a=>`(${a})`).join("|"),o=new RegExp(u,"g");let i,c=e;for(;(i=o.exec(e))!==null;){i.index===o.lastIndex&&o.lastIndex++;const a=s.shift();if(a===void 0)break;const t=i[0];c=c.replace(t,N[t](a))}return c}};var z=M;const U=e=>{const{level:s,message:u,duration:o,context:i,preSanitized:c}=e,a=R.isRuntimeMode,t=[H[s](F(`[${s.toLowerCase()}]`))];if(a&&t.push(r(`time="${j()}"`)),i){const{email:m,ipAddress:f,subject:d,method:S,pathname:p,statusCode:h,teams:g,apiFunction:O}=i;O&&t.push(l(`fn="${O}"`)),h&&t.push(D(h)),e.level===n.HTTP&&(S&&t.push(r(`method="${S}"`)),p&&t.push(r(`path="${$(p)}"`))),f&&t.push(r(`ip="${f}"`)),m&&t.push(r(`email="${T(m)}"`)),d&&t.push(r(`sub="${C(d)}"`)),g?.length&&t.push(r(`teams="${g.join(", ")}"`))}if(u){const m=a?`msg="${String(P(u,c)).replaceAll?.('"','\\"')}"`:String(u);t.push(m)}return e.level===n.HTTP&&i?.userAgent&&t.push(r(`agent="${i.userAgent}"`)),o&&t.push(V(o)),t.join(" ")+`
|
|
2
|
+
`},y=({context:e,message:s,preSanitized:u,...o})=>{const{method:i,pathname:c,statusCode:a,userAgent:t,subject:m,email:f,teams:d,apiFunction:S}=e||{},p={...o,email:f&&T(f),subject:m&&C(m),teams:d,apiFunction:S,...o.level===n.HTTP?{method:i,pathname:String($(c)),statusCode:a,userAgent:t}:{message:String(P(String(s??""),u))}};return R.isRuntimeMode&&(p.time=j()),JSON.stringify(p,["time","level","scope","message","duration","method","pathname","statusCode","userAgent","subject","ipAddress","email","apiFunction"])+`
|
|
3
|
+
`},D=e=>(e%500<100?x:e%400<100?b:A)(`status="${e}"`),j=()=>{const e=new Date().getTimezoneOffset()*6e4;return new Date(Date.now()-e).toISOString().slice(0,-1)},V=e=>r(`dur="${Math.round(e)}ms"`);export{n as LogLevel,z as default,W as parseLogLevel,J as shouldLog};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ApiFunctionsBasicContext } from '../../types';
|
|
2
|
+
import type { WorkerConfig } from '../../workers/worker-config.js';
|
|
2
3
|
export type ApiRoutesWorkerParams = {
|
|
3
4
|
maxResponseSizeMB?: number;
|
|
4
5
|
slug: string;
|
|
5
6
|
requestHandlerId: string;
|
|
6
|
-
ctxData: ApiFunctionsBasicContext
|
|
7
|
+
ctxData: Omit<ApiFunctionsBasicContext, 'config'> & {
|
|
8
|
+
config: WorkerConfig;
|
|
9
|
+
};
|
|
7
10
|
staticData: Record<string, unknown>;
|
|
8
11
|
serverOutDir: string;
|
|
9
12
|
req: {
|
|
@@ -3,10 +3,16 @@ import { z } from 'zod';
|
|
|
3
3
|
* Env vars that are set as the strings `"true"` or `"false"`, parsed to booleans.
|
|
4
4
|
* Any other value fails validation.
|
|
5
5
|
*/
|
|
6
|
-
export declare function envBooleanStringOptional(): z.
|
|
7
|
-
|
|
6
|
+
export declare function envBooleanStringOptional(): z.ZodPipe<z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
false: "false";
|
|
8
|
+
true: "true";
|
|
9
|
+
}>>, z.ZodTransform<boolean | undefined, "false" | "true" | undefined>>;
|
|
10
|
+
export declare function envBooleanStringDefaultFalse(): z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
11
|
+
false: "false";
|
|
12
|
+
true: "true";
|
|
13
|
+
}>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
8
14
|
/**
|
|
9
15
|
* Like {@link envBooleanStringOptional}, but also accepts `"1"` as true (common for `CI`).
|
|
10
16
|
*/
|
|
11
|
-
export declare function envCiBooleanOptional(): z.
|
|
17
|
+
export declare function envCiBooleanOptional(): z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"true">, z.ZodLiteral<"false">, z.ZodLiteral<"1">]>>, z.ZodTransform<boolean | undefined, "1" | "false" | "true" | undefined>>;
|
|
12
18
|
//# sourceMappingURL=env-boolean-string.d.ts.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare const EXCLUDED_ENV_VARS: string[];
|
|
2
|
+
/** Whether a worker may see the env variable `name`. */
|
|
3
|
+
export declare function isAllowedEnv(name: string): boolean;
|
|
2
4
|
export declare function getAllowedEnvs(): Record<string, string | undefined>;
|
|
3
5
|
//# sourceMappingURL=get-api-route-allowed-env-variables.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=["AUTH_URL","BH_API_URL","HOME","HOSTNAME","INSPECT_MODE","INTERNAL_API_USERNAME","JWT_SECRET_KEY","METRICS_API_PORT","NODE","NODE_OPTIONS","NODE_VERSION","OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","PATH","PLAN_GATES","PORTAL_ID","PWD","SERVER_EDITOR_APP_URL","SHLVL","SUBSCRIPTION_IN_TRIAL","TERM","TYPESENSE_API_URL","UV_USE_IO_URING","VAULT_TOKEN","WEB_SERVER_IDLE_TIMEOUT","YARN_VERSION","npm_config_cache","npm_config_local_prefix","npm_config_user_agent","npm_execpath","npm_node_execpath","npm_package_json","npm_package_name","npm_package_version"],n=["NOMAD_"];function T(){return Object.fromEntries(Object.entries(process.env).filter(([_])
|
|
1
|
+
const e=["AUTH_URL","BH_API_URL","HOME","HOSTNAME","INSPECT_MODE","INTERNAL_API_USERNAME","JWT_SECRET_KEY","METRICS_API_PORT","NODE","NODE_OPTIONS","NODE_VERSION","OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","PATH","PLAN_GATES","PORTAL_ID","PWD","SERVER_EDITOR_APP_URL","SHLVL","SUBSCRIPTION_IN_TRIAL","TERM","TYPESENSE_API_URL","UV_USE_IO_URING","VAULT_TOKEN","WEB_SERVER_IDLE_TIMEOUT","YARN_VERSION","npm_config_cache","npm_config_local_prefix","npm_config_user_agent","npm_execpath","npm_node_execpath","npm_package_json","npm_package_name","npm_package_version"],n=["NOMAD_"];function T(_){return!e.includes(_)&&!n.some(E=>_.startsWith(E))}function R(){return Object.fromEntries(Object.entries(process.env).filter(([_])=>T(_)))}export{e as EXCLUDED_ENV_VARS,R as getAllowedEnvs,T as isAllowedEnv};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import { readEnvVariable } from './read-env-variable.js';
|
|
2
|
+
/** False when `value` has no env variable template. Cheaper than `interpolateEnvVariables`. */
|
|
3
|
+
export declare function mayHaveEnvVariables(value: string): boolean;
|
|
1
4
|
/**
|
|
2
5
|
* Interpolates environment variables in a string using the format {{ process.env.VARIABLE_NAME }}.
|
|
3
6
|
* Supports optional quoted default values applied when the variable is not set,
|
|
4
7
|
* e.g. {{ process.env.VARIABLE_NAME || "default" }} (both `|` and `||` separators are accepted).
|
|
5
8
|
*
|
|
6
9
|
* @param value - The string containing environment variable templates to interpolate
|
|
10
|
+
* @param readEnv - Returns the value of an environment variable; reads `process.env` by default
|
|
7
11
|
* @returns An object containing:
|
|
8
12
|
* - interpolatedValue: The string with all environment variables replaced with their values
|
|
9
13
|
* - unsetVars: Array of environment variable names that were not found and had no default
|
|
10
14
|
* - interpolatedVars: Array of environment variable names that were successfully resolved
|
|
11
15
|
*/
|
|
12
|
-
export declare function interpolateEnvVariables(value: string): {
|
|
16
|
+
export declare function interpolateEnvVariables(value: string, readEnv?: typeof readEnvVariable): {
|
|
13
17
|
interpolatedValue: string;
|
|
14
18
|
unsetVars: string[];
|
|
15
19
|
interpolatedVars: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readEnvVariable as d}from"./read-env-variable.js";const
|
|
1
|
+
import{readEnvVariable as d}from"./read-env-variable.js";const f=/{{\s*process\.env\.([A-Z0-9_]+)\s*(?:\|\|?\s*(?:"([^"]*)"|'([^']*)')\s*)?}}/gi;function p(a){return a.includes("{{")}function u(a,c=d){let e=a;const s=new Set,t=new Set,i=[...a.matchAll(f)];for(const n of i){const r=n[1].toUpperCase(),o=n[2]??n[3],l=c(r);l!==void 0?(e=e.replace(n[0],l),t.add(r)):o!==void 0?(e=e.replace(n[0],o),t.add(r)):s.add(r)}return{interpolatedValue:e,unsetVars:Array.from(s),interpolatedVars:Array.from(t)}}export{u as interpolateEnvVariables,p as mayHaveEnvVariables};
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import { readEnvVariable } from './read-env-variable.js';
|
|
2
|
+
type EnvReplacement = {
|
|
3
|
+
unsetEnvVars: string[];
|
|
4
|
+
interpolatedEnvVars: string[];
|
|
5
|
+
replacedValues: Record<string, {
|
|
6
|
+
original: string;
|
|
7
|
+
replaced: string;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
1
10
|
/**
|
|
2
11
|
* Recursively traverses an object or array and interpolates environment variables in all string values.
|
|
3
12
|
* Keeps track of the path to each modified value and maintains a record of original and replaced values.
|
|
4
13
|
*
|
|
5
14
|
* @param obj - The object or array to process
|
|
6
|
-
* @param currentPath - Array of keys representing current position in object tree
|
|
7
15
|
*
|
|
8
16
|
* @returns An object containing:
|
|
9
|
-
* - resolvedObj:
|
|
17
|
+
* - resolvedObj: A copy of the plain objects and arrays, with all environment variables replaced
|
|
10
18
|
* - unsetEnvVars: Array of environment variable names that were not found
|
|
11
19
|
* - interpolatedEnvVars: Array of environment variable names that were successfully resolved
|
|
12
20
|
* - replacedValues: Record of paths where values were replaced, with original and new values
|
|
@@ -14,13 +22,13 @@
|
|
|
14
22
|
* For usage examples and test cases, see:
|
|
15
23
|
* [unit tests](./__tests__/env.test.ts)
|
|
16
24
|
*/
|
|
17
|
-
export declare function replaceEnvVariablesDeep<T extends Record<string, unknown> | Array<unknown>>(obj: T
|
|
25
|
+
export declare function replaceEnvVariablesDeep<T extends Record<string, unknown> | Array<unknown>>(obj: T): EnvReplacement & {
|
|
18
26
|
resolvedObj: T;
|
|
19
|
-
unsetEnvVars: string[];
|
|
20
|
-
interpolatedEnvVars: string[];
|
|
21
|
-
replacedValues: Record<string, {
|
|
22
|
-
original: string;
|
|
23
|
-
replaced: string;
|
|
24
|
-
}>;
|
|
25
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* `replaceEnvVariablesDeep` without the copy: changes the strings of `container` in place.
|
|
30
|
+
* `readEnv` returns the value of an environment variable; it reads `process.env` by default.
|
|
31
|
+
*/
|
|
32
|
+
export declare function replaceEnvVariablesInPlace(container: object, readEnv?: typeof readEnvVariable): EnvReplacement;
|
|
33
|
+
export {};
|
|
26
34
|
//# sourceMappingURL=replace-env-variables-deep.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject as
|
|
1
|
+
import{isObject as c}from"../../../utils/guards/is-object.js";import{interpolateEnvVariables as E,mayHaveEnvVariables as b}from"./interpolate-env-variables.js";import{readEnvVariable as v}from"./read-env-variable.js";function g(r){const n=p(r);return{resolvedObj:n,...A(n)}}function A(r,n=v){const t=new Set,f=new Set,l={},i=[],V=u=>{const o=u;for(const a in o){const e=o[a];if(typeof e=="string"){if(!b(e))continue;const{interpolatedValue:d,unsetVars:y,interpolatedVars:m}=E(e,n);y.forEach(s=>t.add(s)),m.forEach(s=>f.add(s)),m.length>0&&(o[a]=d,l[[...i,a].join(":")]={original:e,replaced:d})}else(c(e)||Array.isArray(e))&&(i.push(a),V(e),i.pop())}};return(c(r)||Array.isArray(r))&&V(r),{unsetEnvVars:Array.from(t),interpolatedEnvVars:Array.from(f),replacedValues:l}}function p(r){return Array.isArray(r)?r.map(p):c(r)?Object.fromEntries(Object.entries(r).map(([n,t])=>[n,p(t)])):r}export{g as replaceEnvVariablesDeep,A as replaceEnvVariablesInPlace};
|