- schema-driven bracket-notation parser for query and form data
- fix changelog
- parse bracket array-of-objects notation in form data
- ci: tolerate transient artifact upload failures in SDK test jobs
- support array-of-objects query params with dots/brackets format
- ci: retry artifact downloads in SDK test report job
- use essence matching for wildcard content types across the codebase
- accept any Content-Type when spec declares
*/*wildcard
- Fix grammatical error in README description
- tests: add missing validator format flags for sink and groq SDK tests
- exclude member-scoped examples when merging allOf for response generation
- coerce query param values through allOf/anyOf/oneOf composition
- compare SDK test results against latest release instead of latest main run
- skip type-mismatched examples in response generation
- use application/json schema in fuzz walker
- wire form format options and schema coercion for multipart requests
- respect explicit array fields for file placeholders in form parser
- make getBodySchema content-type-aware
- Steady is now prod ready
- never crash on invalid media types, emit diagnostics instead
- handle query-disambiguated paths in fuzz baseline and mutators
- filter ambiguous path templates from fuzz operations
- improve router specificity sorting for mixed segments
- use unix sockets and port 0 to prevent ephemeral port exhaustion in fuzz tests
- add @steady/media-type package with branded types
- remove MatchError, use GenerationError for missing response
- unify routing into single Router class
- skip body mutations on GET/HEAD in fuzz tests
- resolve $ref in parameter and body schemas
- E1020 warns that GET/HEAD bodies are stripped and suggests QUERY method
- downgrade E1003 missing spec field from error to warning
- skip paths with URI fragments in fuzz spec walker
- E1021 startup diagnostic for URI fragments in paths
- default --reject-on-sdk-error to true
- fuzz test expects readOnly fields to be accepted in requests
- move E3005 empty-body check from body parser to diagnostic engine
- add @steady/fuzz package and fix $ref example resolution
- use node:http for GET/HEAD body mutations in fuzz tests
- suppress per-request logging in fuzz tests
- validate request body on all methods and fix fuzz false positives
- extend null-body handling to 101/205 and add E1019 no-success-response
- handle 204/304 null-body responses and rename X-Steady-Valid
- handle wildcard response codes (2XX, 3XX) in getResponseObject
- resolve $ref in Location header for 3xx responses
- resolve JSR publish errors for cross-package imports and slow types
- simplify fuzz tests to only run openapi-directory in CI
- unify spec ownership and clean up naming
- split server.ts into src/server/ modules
- clean up @steady/fuzz package and $ref resolution quality
- fuzz all 11 SDK specs for false positives
- ci: add fuzz job, gate openapi-directory test behind STEADY_FUZZ
- respect Location example/default in 3xx responses
- verify every diagnostic code has a complete explanation
- add HTTP QUERY method support
- inject Location header for 3xx redirects, warn on missing spec header
- recognize all NDJSON content type variants for streaming
- move engine contract tests out of packages
- rewrite OpenAPI directory tests to run full validation pipeline
- ci: merge test jobs, init submodules in test job
- ci: always init submodules for OpenAPI directory tests
- ci: skip cloudflare-python in CI (~20min too slow)
- ci: move SDK tests to separate workflow file
- ci: add GH_PAT for cloning private SDK repos, add boundary check to lint
- remove pls workflows, will use pls-hosted instead
- cleanup
- ci: run SDK tests in parallel via dynamic matrix
- ci: fix SDK test CI workflow and improve PR reporting
- include headers in JsonLogger at details+ level
- eliminate as casts and ! assertions, consolidate isSchema
- unify SchemaObject and Schema into single canonical type
- add pointer types, consolidate utilities, begin eliminating as casts
- clean up logging architecture
- E1012 allOf enum/type intersection, discriminator valid values, E3009 confidence
- E1012 spec patterns, CI logger module, and test improvements
- format-aware query parameter parsing and dead code cleanup
- per-request minimal response warning and populated expected fields
- complete diagnostics system - parser leniency, new E-codes, coverage tracking
- improve startup diagnostics UX from real-world SDK testing
- close diagnostics spec gaps, add explain command
- align diagnostics output with spec, remove legacy Attribution type
- compiler-style diagnostic output
- add startup spec analyzer with E1xxx diagnostics
- add E3010 array item type detection and E3006 Content-Type validation
- add path parameter value validation to engine
- replace strict/relaxed mode with --reject-on-sdk-error
- wire diagnostic engine into server
- diagnostic engine with full pipeline integration
- diagnostics quality audit (12 fixes)
- recursively flatten nested allOf chains in response generator
- quality pass on diagnostics system
- startup summary severity labels, blank expected, absolute paths
- merge RefGraph into DocIndex, add FragmentPointer type, single-walk startup
- replace ScaleAwareRefResolver with SchemaRegistry in processor
- unify validation and resolution architecture
- remove legacy validation classes, complete diagnostics migration
- remove decorative emojis and delete legacy scripts
- remove legacy diagnostics pipeline and dead code
- clean up collector and types
- reorganize integration tests into tests/integration/
- remove redundant detectDoubleQuestionMark from server
- add diagnostics implementation plan (first principles design)
- add E1011 invalid component name and impossible schema open question
- add design-review skill
- expand diagnostics spec with design review findings
- add more work to do
- format test files
- formatting
- formatting
- More spec work
- More spec work
- Diagnostic spec
- diagnostics engine core interpretation pipeline
- implementation plan
- implementation plan and design
- implementation plan
- add runtime diagnostic for double-? URL construction bug on 404
- add startup diagnostics for question marks in query params and paths
- resolve query param type coercion through anyOf/oneOf/allOf schemas
Details
getNestedPropertySchema() was only checking direct .properties on the schema, so bracket/dot-style object params like created[gt]=0 with an anyOf-wrapped object schema would fail to find the property schema and skip type coercion, leaving values as strings instead of integers.
- document --validator-form-array-format (#92)
- test: configure stripe brackets format
- test: add stripe python and typescript tests
- tests: add openai typescript (#90)
- logo (#88)
- More fixes (#86)
Details
- fix: return {} for void responses when client accepts JSON
Previously returned Content-Type: application/json with empty body, causing JSON parse errors. Now returns {} when client accepts JSON, or no body when they don't. Skips for 204/304 per HTTP spec. - fix: skip readOnly properties in required validation
Per OpenAPI spec, readOnly properties are server-provided and should not be required in request bodies. - fix: handle empty JSON body gracefully instead of crashing
- ci: add Node.js and pnpm for TypeScript SDK tests
- chore: formatting
- fix: return {} for void responses when client accepts JSON
- skip pytest's skip markers in api_resources tests (#78)
Details
Inject a conftest.py hook that removes @pytest.mark.skip and @pytest.mark.skipif markers at collection time for tests in tests/api_resources. This ensures all SDK tests run against the mock server, even tests that would normally be skipped.
Based on: pytest-dev/pytest#13311
Co-authored-by: Claude <noreply@anthropic.com>
- correctly resolve ref for validation context (#85)
Details
- fix: correctly resolve for validation context
- test: make missing responses and duplicate param tests fail properly
- add cursed spec for missing responses (failing test) (#84)
Details
- test: add cursed spec for missing responses (failing test)
Add test fixture and failing test for endpoints with no responses object. Per OAS 3.1.0 Section 4.8.16: "The Responses Object MUST contain at least one response code."
* Empty responses `{}` correctly rejected at parse time * Missing responses field incorrectly accepted (BUG)
Test will pass once parser validates required responses field.
https://claude.ai/code/session_01BAstPdGCPN9Un7dwsDmFvS
- test: add cursed spec for duplicate path parameter names
Add `/users/{id}/posts/{id}` - same param name twice in path. OAS 3.1.0 Section 4.8.9.1: "Each parameter MUST have a unique name within the path template."
Currently: Steady silently accepts (BUG) Expected: Should reject or warn
https://claude.ai/code/session_01BAstPdGCPN9Un7dwsDmFvS
- chore: format CHANGELOG.md
https://claude.ai/code/session_01BAstPdGCPN9Un7dwsDmFvS
---------
Co-authored-by: Claude <noreply@anthropic.com>
- add SDK test regression reporting to CI
Details
- Add JSON output mode to test-sdks.ts with --json and --output flags
- Upload SDK test results as artifacts (retained for 90 days)
- Download baseline from main branch on PRs for comparison
- Post PR comment showing regressions, improvements, and new SDKs
- Fail CI if any SDK regresses from passing to failing
- Show vs main diff in summary table
The PR comment includes: - Summary table with total/passed/failed counts
- Regressions section (passing on main, now failing)
- Improvements section (failing on main, now passing)
- New SDKs section (not in baseline)
- Full results in collapsible details
- only generate required properties in response generator
Details
Remove random inclusion of optional properties (previously 50% chance). This ensures consistent, minimal responses and avoids flaky SDK tests where pagination responses would randomly omit `items` arrays.
Added TODO comment to revisit optional property generation strategy. Updated tests that relied on optional properties being generated.
- support paths with same pattern but different methods
Details
When an OpenAPI spec defines multiple paths with the same URL structure but different parameter names and HTTP methods (e.g., DELETE on /secrets/{secret_id} and POST on /secrets/{secret_key}), Steady now:
1. Matches requests correctly at runtime by continuing to search through pattern routes when a path structure matches but the method doesn't exist on that particular path definition.
2. Emits a warning at startup that these paths violate OpenAPI 3.0.3 ("Templated paths with the same hierarchy but different templated names MUST NOT exist as they are identical").
The warning is informational - both paths remain fully functional for their respective methods. This ensures accurate error attribution: the spec has a validity issue, but Steady handles it gracefully.
Implementation details: - PathAnalyzer detects duplicate patterns using normalized base paths - Handles Steady's query-param routing extension (/path?key=val) - Runtime matching tracks first path match for "method not allowed" errors - All paths remain separate in data structures for correct diagnostics
- add ArcadeAI SDK to integration tests
Details
ArcadeAI (arcade-py) is a Stainless-generated Python SDK with the same structure as OpenAI, Anthropic, etc. Their spec triggered the duplicate-path-patterns issue that led to this branch's fix.
- add cursed-specs collection for invalid OAS patterns
Details
Move the duplicate-path-patterns spec to test-fixtures/cursed-specs/ with documentation explaining: - What violation it demonstrates - Real-world source (ArcadeAI) - How different tools handle it - Why Steady supports it gracefully
This starts a collection for testing Steady against real-world invalid specs that other tools struggle with.
- format code
- handle SIGTERM/SIGHUP for graceful server shutdown
Details
- Server handles common shutdown signals (SIGINT, SIGTERM, SIGHUP, SIGQUIT) - npm wrapper forwards all signals to child (transparent wrapper) - Added bash test script for process cleanup (tests both deno and npm)
- log request body with --log-bodies flag
Details
The validator now returns the parsed request body in ValidationResult, which is then passed to the logger for display when --log-bodies is set.
Changes:- Add requestBody field to ValidationResult in validator.ts
- Return parsed body from validateRequestBodyFromRequest
- Pass request body through logRequestEvent to the event
- pass response body to logger for --log-bodies to work
Details
The previous fix added the logBodies option to loggers but the response body was never passed to logRequestEvent. This change:
- Updates generateResponse to return { response, body } - Passes responseBody to logRequestEvent - Adds body to the RequestEvent for logging
- add --version flag to CLI
Details
Print version number and exit when --version is passed.
- --log-bodies flag now correctly shows request/response bodies
Details
The logBodies option was defined in config but never passed to loggers.
Changes: - Add logBodies to LoggerOptions interface - Add shouldShowBodies() helper to BaseLogger - Pass logBodies from ServerConfig to all logger constructors - Update TextLogger, TuiLogger, JsonLogger to use shouldShowBodies() - Add tests for logBodies behavior in summary mode
- add comprehensive tests for file extension paths
Details
Verify path matching works correctly with file extensions: - Literal paths (/openapi.json) - Parameterized paths with extension suffix (/{filename}.json) - Multi-segment paths (/files/{name}.json) - Multiple dots (/{name}.min.js) - Dots in prefixes (/api.v{version}/users) - Extension mismatches and edge cases
- add descriptive server startup message
Details
Display "Steady server listening on <url> (<mode> mode)" on startup for clearer feedback when the server begins accepting connections.
Version changed from 0.10.0-alpha.0 to 0.10.0
Version changed from 0.9.0 to 0.10.0-alpha.0
- add undocumented 'debug' as alias for 'full' log level
- add undocumented -v and --verbose CLI flags as aliases for --log-level
- Log fatal error message before shutdown
Details
Print something simple to parse
- support query strings in OpenAPI path definitions
Details
Some APIs (like Anthropic) define paths with embedded query strings (e.g., /files?beta=true) to distinguish between different API versions.
- Parse query strings from paths during route compilation - Match routes based on both path and required query params - Pass consumed query params to validator to avoid false "unknown param" errors - Add tests for query string in path matching
- add form data format options and fix allOf schema merging
Details
- Add CLI flags for form data array/object formats (--validator-form-array-format, --validator-form-object-format) matching existing query param format options - Extract shared param-format.ts module for array/object serialization logic - Fix form data double-wrapping bug where arrays like `include: [["logprobs"]]` were generated instead of `include: ["logprobs"]` - Fix allOf schema merging in response generator - now properly merges schemas before generating, instead of generating from each subschema separately - Add tests for allOf with nullable, form data formats, and bracket notation
- add --host CLI flag to fix IPv4/IPv6 binding issue
Details
The server was binding to "localhost" which on macOS resolves to IPv6 only, causing connection refused errors when SDKs connect to 127.0.0.1.
- Add --host flag to specify bind address (default: localhost) - Update test script to use --host 0.0.0.0 for dual-stack support - Fix test script to actually start mock server before running tests
- extract types from anyOf/oneOf/allOf for query param parsing
Details
When a query parameter schema uses anyOf/oneOf (e.g., `anyOf: [{type: "integer"}, {type: "null"}]`), the validator wasn't recognizing the types and defaulted to string. This caused values like `limit=0` to fail validation because "0" was kept as a string instead of being parsed as an integer.
- Add `getSchemaTypes()` helper to extract types from composition schemas - Update `isArraySchema()` and `parseParamValue()` to use the helper - Update `addNestedPropertyKeys()` to use `getObjectSchemaFromComposition()` - Add diagnostic when schema types cannot be determined
- add rye to CI for SDK tests
- remove maxDepth limit from response generator
Details
The maxDepth limit was causing null values to be generated for deeply nested schemas (like OpenAI's Response schema with 11+ levels). The cycle detection via the visited set is sufficient - maxDepth was redundant and harmful for legitimate deep schemas.
Changes: - Remove maxDepth field and parameter from RegistryResponseGenerator - Remove depth parameter from generateFromSchema, generateArray, generateObject - Update all call sites to remove depth argument - Add test for deeply nested anyOf in array items
- merge SDK test scripts into single TypeScript implementation
Details
- Combine test-stainless-sdks.sh and test-sdks.ts into one unified script - Add light wrapper ./scripts/test-sdks for convenience - Use exit codes instead of parsing output text for pass/fail detection - Update CI to run all SDK tests (Go + Python) instead of just Go - Add Python 3.12 and uv setup to CI workflow
- update OpenAPI fixtures and test-suite submodule
- Potential fix for code scanning alert no. 7: Incomplete string escaping or
encoding
Details
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
- add CLI flags for streaming defaults
Details
Add --stream-count and --stream-interval CLI flags to set server-wide defaults for streaming responses. Headers still override per-request.
- Add StreamingConfig interface to types.ts
- Add --stream-count=<n> (default: 5, max: 1000)
- Add --stream-interval=<n> (default: 100ms, max: 10000ms)
- Add getEffectiveStreamingOptions() to merge config with headers
- Document in CLI help under "Streaming Options"
- add warn function to logging and use for invalid NDJSON examples
Details
- Add warn() function to logging/mod.ts for general warnings - Use warn() in streaming.ts when NDJSON example is invalid - Warning includes yellow color and [Steady] prefix
- add NDJSON example support for multiline strings and arrays
Details
Add support for spec examples in JSONL/NDJSON streaming responses: - Array of objects: each object is streamed as a JSON line - Multiline string: each line is parsed as JSON and streamed
Unlike schema-generated NDJSON, example-based responses do not include _stream metadata, preserving the exact example content.
New exports: - isNDJSONExample(): detects valid NDJSON examples - parseNDJSONExample(): parses multiline strings or arrays
- redesign logging system with unified event model
Details
- Replace old loggers with Logger interface and implementations (TextLogger, JsonLogger, TuiLogger) - Add complete validation context: path, specPointer, keyword, expected, actual, attribution, suggestion - Schema analyzer now reports per-schema complexity/nesting with specific pointers instead of useless global metrics - Add --log-format flag for text/json output selection - Fix SIGINT handling: server owns shutdown in all modes - Exclude test-fixtures/openapi-directory from deno commands
- add streaming headers to CLI help output
Details
Document X-Steady-Stream-Count and X-Steady-Stream-Interval-Ms headers in the CLI help for consistency with other per-request override headers.
- add streaming support for NDJSON and SSE responses
Details
Adds streaming response support for: - NDJSON formats: application/x-ndjson, application/jsonl, application/json-seq - Server-Sent Events: text/event-stream
Features: - Schema-based streaming generates items from JSON Schema - Example-based SSE supports event sequences with different event types - OpenAI-style SSE pattern (data-only events like [DONE]) - Configurable stream count and interval via headers - Auto-appends done event for SSE stream completion - Deterministic streaming with seeded RNG
Headers: - X-Steady-Stream-Count: Number of items (default: 5, max: 1000) - X-Steady-Stream-Interval-Ms: Delay between items (default: 100ms)
- remove non-standard $id basename matching
- address issues found in codebase review
- clarify red-green testing applies to all fixes, not just bugs
- add tests for RNG determinism and $id lookup behavior
- Add form data parsing for request body validation
- Support full OpenAPI query parameter serialization matrix
- Add investigation standards to CLAUDE.md
- Add parameter suite for comprehensive edge case testing
- Add TypeScript SDK integration test runner
- remove bin field from platform-specific npm packages
- update repository URL to dgellow/steady for npm provenance
- add deno run example to installation
- update installation section with npx usage
- revert npm publish to OIDC auth with provenance
- switch npm publish to token auth (temporary)
- update npm to latest in publish workflow
- add version file for pls sync
- Add npm publishing with platform-specific packages
- disable Deno caching for release workflows
- always use latest pls version in CI workflows
- update CI workflows and manifest for new pls