feat: add remote URL support for input specifications with optional auth#363
Merged
jonaslagoni merged 2 commits intomainfrom Apr 26, 2026
Merged
feat: add remote URL support for input specifications with optional auth#363jonaslagoni merged 2 commits intomainfrom
jonaslagoni merged 2 commits intomainfrom
Conversation
inputPath now accepts http(s):// URLs across AsyncAPI, OpenAPI, and JSON Schema
inputs, with an optional auth field (bearer / apiKey / custom headers) that flows
through to every fetch (root document and external $ref targets).
- Cross-spec $ref auth is supported for AsyncAPI (via @asyncapi/parser
__unstable.resolver) and OpenAPI (via @apidevtools/json-schema-ref-parser
custom http resolver).
- URL detection bypasses path.resolve at the configuration chokepoint.
- Watch mode skips chokidar for URL inputs and warns; --watchPath still works.
- Status-specific error help text (401/403/404/429/timeout/network).
- Cross-host info-level warning emitted once per distinct cross-host destination
to surface potential token-leak vectors.
- Documentation: canonical 'Auth scope and security considerations' section in
docs/configurations.md with the compromised-spec example and deferred-mitigations
list; short callouts in docs/inputs/{asyncapi,openapi,jsonschema}.md.
- Browser bundle rebuilt; the new auth schema field surfaces in the playground's
Monaco autocomplete with the security warning in markdownDescription.
Closes #359
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
✅ Deploy Preview for the-codegen-project canceled.
|
Contributor
Author
|
🎉 This PR is included in version 0.72.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for loading AsyncAPI, OpenAPI, and JSON Schema specs from
http(s)://URLs ininputPath, with optional authentication (bearer/apiKey/ custom headers). Cross-spec$refs on the same and different hosts are resolved through the same auth-aware HTTP path. Closes #359.Type of Change
Related Issues
Closes #359 — prerequisite for the EventCatalog integration that needs to fetch authenticated specs.
Changes Made
New source files
src/utils/inputSource.ts—isRemoteUrl/getInputSourceType(canonical URL-detection helper; telemetry now re-exports from here).src/utils/remoteFetch.ts—fetchRemoteDocument(url, auth?, options?)using Node 22's globalfetch, withAbortController-based timeout, redirect-follow, and typed errors.src/utils/refResolvers.ts—createOpenapiRefParserResolver(auth, ctx)andcreateAsyncapiResolvers(auth, ctx)so cross-spec$refs flow through the same auth + debug-log + cross-host-warning pipeline.Modified source
src/codegen/types.ts— addszodInputAuth(discriminated union spread into all three input branches),InputAuthConfig, andRunGeneratorContext.inputAuth.src/codegen/configurations.ts— URL passthrough (bypasspath.resolvefor http(s)://) and threadscontext.inputAuthfrom config.src/codegen/errors.ts—createRemoteFetchErrorwith status-specific help (401/403 → auth, 404 → URL, 429 → rate-limit, network → connectivity, timeout → timeout).createInputDocumentErrorno longer suggests "valid JSON file" for URL paths.src/codegen/inputs/asyncapi/parser.ts— URL fetch + per-callParserwith__unstable.resolverresolvers when auth is present (singleton preserved for the no-auth/local-file path).src/codegen/inputs/openapi/parser.ts— URL fetch + Content-Type-driven parse +$RefParser.dereferencewith our auth-aware http resolver.safeUrlResolver: falseso internal/loopback hosts work.src/codegen/inputs/jsonschema/parser.ts— URL fetch with Content-Type → URL extension → JSON-then-YAML fallback.loadJsonSchemaandloadJsonSchemaDocumentdeduplicated.src/commands/generate.ts— watch mode skips chokidar for URL inputs and logs a one-shot warning;--watchPathstill works.src/telemetry/anonymize.ts— re-exportsgetInputSourceTypefrom the canonical helper (no telemetry semantics change).Tests (TDD: written first, verified failing, then passing)
test/utils/inputSource.spec.ts— URL-detection truth table.test/utils/remoteFetch.spec.ts— auth headers (bearer / apiKey / custom), status codes, AbortError → timeout help, network failures, redirect-follow.test/utils/refResolvers.spec.ts— both factories, debug log, cross-host info-level warning emitted exactly once per distinct cross-host destination.test/codegen/configurations.spec.ts— URL passthrough (nopath.resolve),inputAuththreaded onto context, Zod accepts eachauthshape, rejects invalid shapes.test/codegen/inputs/asyncapi.spec.ts— new file: URL load + auth + 401 propagation.test/codegen/inputs/openapi.spec.ts— extended with URL load + auth + Content-Type-driven JSON/YAML + extension fallback + 404.test/codegen/inputs/jsonschema.test.ts— extended with URL load + auth + Content-Type/YAML + ambiguous-content-type fallback.test/codegen/inputs/__helpers__/httpServer.ts— real localhttp.createServertest helper with header-checking middleware.test/codegen/inputs/remote-url.e2e.spec.ts— 7-case end-to-end suite against real HTTP servers, including same-host$refauth, cross-host warning, and 401 on root.Documentation
docs/configurations.md— new "Remote URL inputs" section with examples for the three auth shapes, plus the canonical "Auth scope and security considerations" section (compromised-spec example, debug/info log behavior, deferred mitigations list).docs/inputs/asyncapi.md,docs/inputs/openapi.md,docs/inputs/jsonschema.md— short callouts linking to the canonical security section.markdownDescriptionand surfaces in IDE tooltips and the playground's Monaco autocomplete.Dependencies
@types/nodebumped to^22(matchesengines.node).@apidevtools/json-schema-ref-parserpromoted from transitive (via@readme/openapi-parser) to direct dependency at^14.2.0.fetch).Key Implementation Details
Auth scope (D8) — same headers go to every fetched URL
When
authis configured, the headers are sent to every URL the loader fetches — root + every$reftarget, regardless of host. This is the right default for typical internal-SSO setups but means a compromised spec can exfiltrate the token via an external$ref. Mitigations shipped today:[remote-fetch] GET <url>).$refhost differs from the root host:[remote-fetch] auth headers sent to '<host>' while resolving $ref from '<root-host>'.zodInputAuth.describe(...)so it shows in IDE tooltips.Per-host auth maps and an auth-host allowlist are deferred to follow-up issues; documented inline.
Browser & playground
The browser path passes spec content directly with a virtual
inputPathand never invokesfetchRemoteDocument, so URL fetching is correctly Node-only. Esbuild tree-shakes out the URL helpers from the bundle (verified:grep -c fetchRemoteDocumentreturns 0). The newzodInputAuthschema is bundled so the playground accepts theauthfield, with the security warning surfacing in Monaco autocomplete viamarkdownDescription.Testing
npm run prepare:prAll steps green: build, format, lint:fix, test:update, runtime:typescript:generate.
Unit + integration tests
Browser tests (
test/browser/)Browser bundle smoke test
Loaded
dist/browser/codegen.browser.mjsin Node with browser-globals shims;generate()produced a TypeScript payload from an AsyncAPI 2.6 spec;parseConfig()round-tripped a config withauth: {type: 'bearer'}.Docusaurus website build
SUCCESS(pre-existing broken-link warnings on the website are unrelated to this PR).Runtime generate (local-path regression)
All four runtime configs regenerated successfully — regular: 19 files, request-reply: 16, openapi: 18, payload-types: 60.
Documentation
docs/configurations.md— Remote URLs + Auth scope + watch-mode notes.docs/inputs/{asyncapi,openapi,jsonschema}.md— short callouts.schemas/configuration-schema-0-with-docs.json).Breaking Changes
None. Every existing test using a local
inputPathstill passes unchanged. The newauthfield is optional and ignored for local file paths.Performance Impact
Parsersingleton is reused; OpenAPI keeps the existing@readme/openapi-parser.dereferenceflow for local files).$ref; default 30 s timeout; redirect-follow.Checklist
prepare:pr, browser, runtime generate sanity)--max-warnings 0)npm run prepare:prgreenExamples
Bearer token
API key in a custom header
Arbitrary headers
Follow-ups (deferred per plan, not blocking)
auth: { 'api.acme.com': {...}, 'schemas.acme.com': {...} }.authHosts: [...]to scope headers to listed hosts only.$refresolution entirely.