Skip to content

fix(macro): round-7 schema/macro audit fixes - #305

Open
owjs3901 wants to merge 26 commits into
mainfrom
fix/macro-rest-round7
Open

owjs3901 wants to merge 26 commits into
mainfrom
fix/macro-rest-round7

Conversation

@owjs3901

Copy link
Copy Markdown
Contributor

Summary

Round-7 audit fixes for vespera_macro (outside parser/**), the axum example and one bench script. Every fix comes with a test that failed before it.

High / medium

  • H1 schema_type! from a SeaORM DateTimeLocal column with a SQL-function default (NOW()) emitted #[schema(default = ...)] with no usable value and did not compile. It now emits a bare #[schema(default)] marker. E2E: ClockDto in axum-example (POST /uuid-items/clock).

  • M1 Same-named types in sibling inline modules of one file resolved to the first module (schema!, schema_type!, default fns). They are now picked by span line (item_module_chain_in_file). E2E: crates/vespera/tests/schema_repeated_inline_names.rs.

  • schema_type! now carries serde default values into the derived component.

  • Multipart derives on generic types add the Default bounds their defaults need.

  • Stale route / cron registrations are dropped only inside rust-analyzer.

  • Two export_app! with the same name in one crate are a compile error (trybuild export_app_duplicate_name).

  • Derived garde validation:

    • skips serde-skipped fields
    • does not nest flattened fields
    • peels nested Option
    • keeps integer bounds beyond 2^53 exact. The runtime check is loosened to the documented f64 bound, so validation and the OpenAPI spec agree.
    • rejects non-finite bounds

    E2E: derive_garde_wire.rs.

  • M5 A default on a $ref property is documented as a sibling of the $ref.

  • More literal defaults resolve: negative numbers, to_owned / into / to_string, String::new / Vec::new, and JSON array / object strings.

Low

  • A renamed type that references itself resolves to its own component.
  • Rename suggestions for invalid file names are valid identifiers.
  • OAuth2 flows reject URL fields they do not take.
  • Fixed in module resolution: mod r#type; cfgs, Path<()>, inline modules in the IDE, and use x::{self} aliases for merge.
  • Merge route conflicts are checked before any spec file is written.
  • A sidecar spec without a fingerprint falls back to its content hash.
  • L-O2 For overlap checks, {{x}} and %7Bx%7D are now the same route shape.
  • L-K1 The cron module-tree scan runs only with the cron feature, and it ignores a bare #[cron] when the module imports cron from another crate.
  • L-E1 The example formats negative money correctly (-0.05, was 0.-5).
  • L-S1 jni-bench-interleaved.sh picks the bridge JAR of the tree's own version.
  • L-D1 The error.rs docs no longer list helpers that do not exist.
  • L-T1..T5 Tests that could not fail now assert something real. The sidecar tests use find_target_dir instead of a hard-coded target/vespera, a stale #[serial] comment is gone, and the limit = "unlimited" test exercises the keyword.

Snapshot and openapi.json changes, all reviewed and intended:

  • ClockDto / ClockDtoInput
  • /health/live
  • the MemoStatus default as a $ref sibling
  • the OAuth2 diagnostics
  • the multipart generic bounds
  • the exact 2^53 garde bound

Test plan

  • cargo test -p vespera_macro (default features, and --features validation,cron)
  • cargo test -p vespera, cargo test -p axum-example, cargo check -p rust-jni-demo
  • clippy -D warnings on vespera_macro + vespera (all targets, all features / no default features) + axum-example; cargo fmt --all --check
  • CI

🤖 Generated with Claude Code

owjs3901 and others added 24 commits November 15, 2026 09:59
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d bounds

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng specs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eature

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 15, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

vespera@0.8.0 - Cargo.toml

Maybe you forgot to write the following files to the latest version

vespera@0.8.0 → 0.8.1 - crates/vespera/Cargo.toml

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera_core@0.8.0 → 0.8.1 - crates/vespera_core/Cargo.toml

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera_inprocess@0.8.0 → 0.8.1 - crates/vespera_inprocess/Cargo.toml

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera_jni@0.8.0 → 0.8.1 - crates/vespera_jni/Cargo.toml

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera_macro@0.8.0 → 0.8.1 - crates/vespera_macro/Cargo.toml

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera-bridge@0.8.0 → 0.8.1 - libs/vespera-bridge/build.gradle.kts

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

vespera-bridge-gradle-plugin@0.8.0 → 0.8.1 - libs/vespera-bridge-gradle-plugin/build.gradle.kts

Patch

  • vespera-bridge audit fixes: a non-web Spring Boot app without spring-web starts again (the core autoconfiguration no longer loads PathPatternParser); on virtual threads SmartDispatchModeResolver streams the response of safe requests (like DIRECT's overflow stash on platform threads) instead of buffering it, so large downloads and Accept-less event streams work (opt back into parking SYNC with new SmartDispatchModeResolver(direct, sync, true)); 1xx / 204 / 304 responses no longer carry Content-Length: 0; unpaired UTF-16 surrogates in wire header strings are encoded as U+FFFD instead of a \uD800 escape the Rust parser rejects; a prefix-mapped DispatcherServlet path is stripped from the forwarded path by decoded segments (%61pi, //, dot segments, %2F); an ASYNC dispatch that hits Spring's async timeout answers the proxy's plain-text 503 with the request id instead of the /error page; the springdoc group-mode document endpoint is mapped from the normalized docs-path (trailing slash, blank) and a root or pattern docs-path fails the startup clearly; dispatchDirectPooled / BufferTooSmallException / DispatchMode / VesperaClient docs describe the overflow stash and poll-first parking.
  • vespera-bridge: multipart uploads through the servlet proxy now reach Rust byte-for-byte. The multipartResolver bean is wrapped in VesperaProxyMultipartResolver so DispatcherServlet no longer parses (drains) proxied multipart requests and Spring's multipart size limits no longer apply to them; Spring controllers keep normal multipart handling (opt out: vespera.bridge.multipart-passthrough=false). A multipart body consumed before the proxy is answered 500 with a clear message instead of being forwarded empty.
  • vespera-bridge round-5 fixes: the async response executor bean no longer suppresses Boot's applicationTaskExecutor; POMs and JARs declare/ship the Apache-2.0 license; WebFlux streams bodyless GETs with a wildcard Accept (event streams no longer buffer forever); ASYNC bodies are written byte for byte (no Content-Disposition, no Spring 304/412); malformed Content-Type reaches Rust; loader, platform detection, config parsing, streaming executor, validation errors, DIRECT stash, client stream/header hardening; workflow template supports a Gradle build in a subdirectory
  • vespera-bridge: a VesperaRequest InputStream body whose read fails is a VesperaClientException; the proxy honours a SmartDispatchModeResolver subclass; oversize-policy=throw streams the request once instead of a 500 or a false overflow; ASYNC HEAD has no body object; async CORS dedupe and reset keep the filter headers; explicitly configured native knobs count after init; shutdown(Duration) no longer overflows; springdoc spec-paths keys with underscores bind, merged components rename consistently, public Rust operations do not inherit the host's security, and native images register the docs mapping hint; docs and weak tests fixed
  • vespera-bridge: the WebFlux proxy strips ;path parameters like the servlet proxy; WebFlux cors=spring applies WebFluxConfigurer#addCorsMappings to proxied paths (preflights answered by Spring); vespera.native.dir works with a missing or read-only java.io.tmpdir; ASYNC responses without a Rust Content-Type no longer get one from Accept, and ASYNC proxy errors echo the request id
  • OpenApi::merge pushes a merged document's top-level security / servers down onto its own operations instead of adopting them for every operation; a nullable schema whose oneOf / allOf / not / anyOf rejects null is wrapped in anyOf [schema, null] even when it has a type; JNI async dispatch symbols moved to their own module (no behaviour change)
  • vespera_core: OpenApi::merge no longer lets the receiver's top-level security govern a merged operation that was unauthenticated (it gets an explicit empty security list), keeps each side's path-level parameters and servers on its own operations when two apps share a path, and pushes only security (not servers) onto merged webhooks; a nullable $ref with a sibling allOf/oneOf/not is wrapped in anyOf [schema, null] so it really accepts null. vespera_jni: a null InputStream/OutputStream answers 400 on the header-first streaming symbols too, like dispatchStreaming/dispatchFullStreaming, instead of 500 JNI streaming setup failed. Weak tests tightened
  • Docs: the JNI demo build steps publish the bridge and the Gradle plugin to mavenLocal (as CI does); extractor tables document Form on GET/HEAD as query parameters and TypedHeader names derived from T; naive date/time and unit return mappings corrected; the landing site gains 0.7 / 0.8 migration notes, WebFlux / forwarded principal / reactive-streaming / max-request-producers / springdoc UI exclude docs and a C ABI page; SKILL.md covers serve_listener. No API change.
  • C ABI: vespera_dispatch_async releases its async in-flight slot before invoking the callback (as JNI dispatchAsync does), so a callback that dispatches again is no longer answered 503 at the cap
  • schema_type!/schema! audit: field types, serde function paths and relation paths resolve in the source module; sources found in crate roots, inline and #[path] modules; storage hits must match the requested module; relation loads select by the target FK column and fail loudly when unresolvable; adapter wrappers implement Clone/Deserialize and convert in from_model; field schema/garde/deprecated/cfg attributes are carried; type-correct NOW() defaults; primary_key with auto_increment = false is not a default; raw identifiers and non-identifier names no longer panic; split rename_all is kept; tuple/unit sources are rejected; generic sources take the macro's type arguments; schema! validates pick/omit names and filters flattened structs; relation_adapters, rename and partial entries are validated with diagnostics at the offending literal
  • schema_type!: module-aware SeaORM relations, cycles and lookups (crate roots, tests/examples/bin targets, call-site imports), generic sources resolve call-site arguments and defaults correctly, shared relation adapters with serde container conversions, cfg_attr serde / deprecated / raw names carried, naming a dropped field is a compile error, typed SeaORM defaults
  • Gradle plugin: a native-jar consumer (crateName + bundleNative = false, no cargoRoot / targetDir) no longer fails tasks --all, IDE sync or tasks.withType<Sync>().configureEach {} with "Cannot query the value": bundleNativeLib / verifyNativeLibs resolve the cdylib location lazily and verifyNativeLibs names the missing setting only when it runs. cargoProfile "test" bundles from target/debug and "bench" from target/release, where Cargo writes them.
  • vespera-bridge-gradle-plugin: a build with no cdylib (and no extraNativeLibs) now fails in the new verifyNativeLibs task instead of silently producing a jar without a native library; a host platform key mapped to a musl triple keeps the host build in native//
  • vespera_inprocess: a bidirectional request body that outlives its dispatch (moved into a detached task) no longer reads the host source after the dispatch returned; a stopped response sink is traced as a client disconnect (status 499, DEBUG) inside the dispatch span instead of an ERROR 500; app names are trimmed with ASCII-only whitespace everywhere (matching the compile-time checks); vespera.h and API docs corrected
  • C ABI: vespera_dispatch_into answers an out buffer below VESPERA_MIN_OUT_BYTES (1024, NULL/0 size probe included) with VESPERA_OVERFLOW and *written = 1024 without running the handler, so a panic/timeout/shutdown error never forces a re-run; an oversized request_len is a 400 wire regardless of buffer addresses; bench header ladder respects MAX_REQUEST_HEADERS; stronger streaming/inline-pull tests and refreshed docs
  • JNI: panic fallbacks of the void symbols actually run (panic wire / completed future instead of a swallowed panic); dispatchFullStreaming no longer flushes the caller's stream on flush hints; a panic after body bytes in the non-header streaming symbols throws VesperaStreamAbortedException(panicked); a DirectStash fetch panic answers a 500 panic wire instead of looking expired; dispatchAsync releases its in-flight permit before completing a future on the calling thread
  • vespera! / export_app! build files: the library, a binary, the cargo test harness and rust-analyzer get separate cache and sidecar files, so one build no longer prunes the include_str! file another still reads; the target directory is read off rustc's --out-dir (dependencies and a relative CARGO_TARGET_DIR agree with the parent; VESPERA_TARGET_DIR overrides it); openapi.json and exported specs never describe #[cfg(test)]-only routes or schemas, so every build writes the same file; one path spelled with different parameter names (/{id} vs /{user_id}) and docs_url / redoc_url / spec_url colliding with an app or merged route are compile errors; undeclared security schemes are checked without a generated document; an ambiguous merge path lists the exporting crates; stale rust-analyzer route / cron entries of renamed handlers are ignored; sibling symlinked route directories are scanned; cron jobs outside src/ get real module paths or a clear error; two #[derive(Multipart)] fields reading one multipart field are a compile error.
  • Schema validation: portable usize bounds (32-bit targets), minimum/maximum checked against the integer field type (compile error instead of a wrapping cast; fractional bounds round inward), and 422 error paths use the serde deserialize name. Multipart derive: every form_data / try_from_multipart key is read in any order, an invalid or overflowing limit is a compile error, serde(skip) / skip_deserializing fields default instead of being required, and generic structs are supported.
  • OpenAPI request/response accuracy: OptionalQuery, WithRejection and Cached extractors are documented; Option<Path> types path params; Query/Path structs follow serde from/try_from and Option fields with a custom deserializer are required; Path maps/sequences type each segment; empty query structs no longer emit a fake parameter; response parts (CookieJar, HeaderMap, header arrays, AppendHeaders, TypedHeader, Extension) carry no body; Json<(A, B)> is a JSON array; error tuples document their payload; Box/Cow are text/plain, Cow<[u8]>/[u8; N] octet-stream; NoContent is 204 and Redirect 3XX; unresolved types inside Result are description-only; the Schema check no longer flags foreign paths like serde_json::Value and now checks Path; alias defaults may reference earlier parameters.
  • Fix round-5 macro parser findings: serde default/skip/flatten detection after other keys and in literals, schema(default) lookup, transparent structs per serde side, Result and HasMany schemas, enum deny_unknown_fields, flattened maps and Option in request views, Cached<Validated<..>> 422, generic Query/Path structs, Path pairs/alias/flatten, raw identifiers, module-qualified renamed types, serde_repr enum matching by position, codec/value_type internally tagged newtypes, Option<Path> checks and the route dir mod.rs module path
  • Fix round-6 macro parser findings: request-view parameters, transparent and from/try_from query/path extractors, value_type internally tagged newtypes, serde_repr and serde(other) request schemas, annotation-only garde rules, recursive generic definitions and colliding instance names, deny_unknown_fields with map-bearing flatten, flattened unit structs and unit variants, Result error status keys and Infallible errors, nested response tuples, scoped Result alias resolution, fast-path extractor checks, declared 4xx/2xx statuses and 205 bodies, wide integer examples, decorated block docs, schema(ref) with nullable or value_type, BelongsTo relations, user schemas named Json, and generic parameters inside value_type/into/from
  • Fix round-7 macro parser findings: serde(transparent) Query/Path structs follow serde's transparent-field rule (PhantomData and serde(default) fields excluded) and tuple structs, generic value_type substitution keeps commas inside angle brackets (HashMap<String, T>), request-view recursive generic instances use a .Input suffix that never collides with a type named *Input, two flattened maps write anyOf (not allOf) in the response view, a NoContent error side is labelled as a successful 204, a bare argument of unknown type keeps the string path placeholder, and doc and test assertion fixes
  • OpenAPI request extraction fixes: Result<Extractor, Rejection> arguments are documented like the bare extractor (required body / query / path / header params; Result<Validated<..>> still asserts garde::Validate); Option<Form> and Result<Form, _> on GET become query parameters; a Path<(..)> tuple longer than the route's own params (nest prefix) is aligned from the end; a parameter after a static prefix (/report-{year}) is documented, text after a parameter (/img/{name}.png, which axum cannot route) is a compile error, and escaped literal braces {{x}} are no longer a parameter (documented as %7Bx%7D).
  • Multipart missing fields follow serde: a container #[serde(default)] / default = "fn" fills them from the container value (the struct now needs Default, as with serde), a field default = "fn" also applies to Option / Vec fields; schema_type!(..., multipart) keeps the source's serde default / skip keys, container default and #[try_from_multipart(strict)]; serde default functions resolve from the struct's inline module and through crate:: paths; route param vs catch-all conflicts and segments after a catch-all are compile errors; generic #[route] responses types are rejected; export namespace renames no longer swap schemas; garde integer bounds are exact; schema!/schema_type! find a source by its Rust name and inside inline modules; collection / wide-integer / Date serde defaults are documented; DateTimeLocal NOW() no longer documents a fixed default
  • vespera_macro fixes: schema_type! of a SeaORM Local column with a SQL-function default (NOW()) compiles again; same-named types in sibling inline modules of one file resolve to the right module for schema! / schema_type! / default functions; schema_type! carries serde default values into the derived component; Multipart derives on generic types add the Default bounds their defaults need; a stale route or cron registration is dropped only inside rust-analyzer; two export_app! of one crate with the same name are a compile error; derived garde validation skips serde-skipped fields, does not nest flattened field paths, peels nested Option, keeps bounds beyond 2^53 exact (and loosened to the documented f64 so runtime and OpenAPI agree) and rejects non-finite bounds; a default on a $ref property is documented as a sibling; more literal defaults are resolved (negative numbers, to_owned / into / to_string, String::new / Vec::new, JSON array / object strings); a renamed self-referencing type resolves to its own component; invalid route file name suggestions are valid identifiers; OAuth2 flows reject URL fields they do not take; raw-identifier modules, Path<()> and inline modules in rust-analyzer resolve; use x::{self} aliases resolve for merge; merge route conflicts are checked before any spec file is written; a sidecar spec without a fingerprint falls back to its content hash; escaped braces and percent escapes are one route shape for overlap checks; the cron module-tree scan runs only with the cron feature and ignores a cron attribute imported from another crate.
  • Router codegen and build cache: duplicate (method, path) routes and routes overlapping a merged child app are compile errors (with or without a spec); export_app specs are crate-scoped, merge resolves use aliases and checks the merged app at compile time; include_str sidecars are content-addressed and written atomically; route(path = "/") maps to the file path without a trailing slash; unknown route keys list the valid ones; duplicate tags / security_schemes are errors and declared tags keep their order; dir must be a module folder under src/ (nested "api/v1" supported); symlinked route files are followed; src/.rs edits and inline-module handlers are tracked; cron jobs in src/bin crates get their real module path.
  • Schema fidelity: a struct #[serde(tag)] is documented as a required tag property in the response view (left out of the {Name}Input request view, since serde never reads it); Option of a type-less inline schema (oneOf / allOf) keeps null via anyOf, and Option of an inline string enum lists null; multipart field names use form_data(field_name) before serde rename in the request view, and the Multipart derive reads the deserialize-side serde rename / rename_all
  • Runtime/core fixes: shutdown_runtime(Duration::MAX) no longer panics after closing the gate (the runtime is shut down and cleanup runs); a whole-number constraint of exactly 2^63 is emitted as a float instead of saturating to i64::MAX; Schema deserializes JSON Schema boolean schemas (true -> {}, false -> {"not":{}}) in components.schemas and $defs, and the OpenAPI 3.0 boolean exclusiveMinimum / exclusiveMaximum (true moves minimum / maximum into the 3.1 exclusive bound); OpenAPI 3.1 fields no longer dropped on deserialize: Components pathItems / links / callbacks, Response links, Header required / deprecated / style / explode / example / examples / content, Parameter deprecated / allowEmptyValue / allowReserved / examples / content, Example externalValue, and x-* extensions on OpenApi / Info / Operation / PathItem (new public fields; Parameter / Response / Header / Example / OpenApi now implement Default, use ..Default::default() in struct literals); JNI dispatchDirect0 answers an out buffer below MIN_DIRECT_OUT_BYTES (1 KiB) with -(1024) without dispatching, so a panic / timeout wire always fits and a retry never re-runs a failing handler; the cancel registry hasher spreads sequential tokens (Fibonacci multiply); doc fixes (streaming dispatch_timeout scope, Validated 422 builder, envelope API limits).
  • Generated schemas now match what serde writes and reads: flattened maps, closed, unit and Option structs merge into one object; alias and other are accepted in request schemas; tuple fields honour codecs and one-sided skips; time crate types, sets, Duration, schema(any), generic defaults and instance names are fixed.
  • CI/release hardening: release-artifacts.sh isolates every per-package step (a failed SBOM no longer drops all attestations) and verifies each published crate was packaged from the released commit; Gradle wrapper validation + distributionSha256Sum; tarpaulin image pinned by digest; bench gates fail when nothing was measured and trigger on toolchain/lockfile changes.
  • Cron jobs sleep in slices of at most 60 s and re-read the wall clock, so a suspend or forward clock step no longer delays a run by the remaining monotonic time; cron::shutdown_and_wait needs no Tokio time driver (returns at once when idle); a cron expression with no occurrence left now logs a warning. vespera_core: nullable enums list null, a nullable schema without type or $ref whose oneOf/allOf/not/anyOf rejects null serializes as anyOf [schema, null], Operation.callbacks is callback name -> runtime expression -> PathItem (new Callback alias), SchemaRef deserializes boolean schemas (true as {}, false as {"not":{}}), OpenApiVersion adds 3.0.4, 3.1.1 and 3.1.2. Multipart errors echo part names bounded to 64 chars with control characters escaped; the DefaultBodyLimit docs now match axum (the extractor applies it on every transport, 2 MB by default).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant