Skip to content

fix(bridge): round-7 audit fixes - #302

Open
owjs3901 wants to merge 4 commits into
mainfrom
fix/bridge-round7
Open

owjs3901 wants to merge 4 commits into
mainfrom
fix/bridge-round7

Conversation

@owjs3901

Copy link
Copy Markdown
Contributor

Round-7 audit of libs/vespera-bridge, libs/vespera-bridge-gradle-plugin, examples/rust-jni-demo/java (+ one comment in crates/vespera_jni).

Behaviour fixes (each with a test that fails on the old code)

  • C-1 VesperaRequest streamed body: when Rust closes the request source after the response drained, a read parked on another thread fails because of that close. That failure no longer turns a finished send into a VesperaClientException. ReadTracking.close() now sets a closed flag before it delegates. Test: VesperaClientTest.aParkedReadFailingBecauseTheNativeSideClosedTheSourceIsNotATransportFailure.
  • A-1 A DIRECT request that is downgraded to SYNC (unsafe method) or re-routed through STREAMING (oversize-policy rejection, or the stash-less retry) now reports that mode in DispatchEvent.mode, the Micrometer tag and logs (ProxyExchange.servedAs).
  • A-2 An unknown-app 404 now reports DispatchEvent.path, because the path is computed before the app is resolved.
  • B1 VesperaBridge.isInitialized() is published only after VesperaNativeConfig.applyAfterLoad() runs. A separate nativeLoaded flag drives init re-entry, configure* and shutdown.
  • B2 The public dispatchDirectPooled overloads' heap fallback now parks on a virtual thread (ParkingDispatch) instead of pinning the carrier in dispatchBytes.
  • E-2 Gradle plugin: setting extraNativeLibs without cargoRoot / targetDir now bundles only the prebuilt libraries. The build fails if that folder holds none.
  • E-4 The bridge JaCoCo report also merges demo-app isolatedJvmTest.exec. CI now also uploads that task's test results.

Docs

  • B3: the VesperaVersions docs now say an unknown bridge version is skipped silently.
  • B4 / E-1: the DIRECT overflow docs now describe the stash. The handler runs once, and only the stash-less fallback re-runs it. This covers DirectOverflowMemory, DirectModeDispatcher, VesperaBridgeProperties (which feeds the metadata descriptions) and VesperaBridgeAutoConfiguration.
  • B5: jni_impl_async.rs now lists the real ASYNC callers (comment only).
  • E-3: the README no longer says configureStreaming clamps values (it throws on out-of-range ones).
  • C-2: the docs now say the streamed request body is closed by the native side.

Changepack: all 7 packages at Patch.

🤖 Generated with Claude Code

- VesperaRequest: a read that fails because the native side closed the
  request source after the response drained no longer fails the send
- proxy: DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request
  is downgraded or re-routed; an unknown-app 404 reports its path
- VesperaBridge: isInitialized() is published only after the pending
  configure* values were applied
- dispatchDirectPooled: the heap fallback parks on a virtual thread
- gradle plugin: extraNativeLibs without cargoRoot/targetDir bundles only
  the prebuilt libraries (fails when none)
- jacoco merges demo-app isolatedJvmTest.exec
- docs: DIRECT overflow stash (handler runs once), version check,
  configureStreaming ranges, request stream close, ASYNC callers

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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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: a VesperaRequest InputStream read that fails because the native side closed the source after the response drained no longer fails the send; DispatchEvent.mode reports SYNC / STREAMING when a DIRECT request is downgraded or re-routed, and an unknown-app 404 reports its path; isInitialized() is published only after pending configure* values were applied; the public dispatchDirectPooled heap fallback parks on a virtual thread instead of pinning the carrier; Gradle plugin: extraNativeLibs without cargoRoot / targetDir bundles only the prebuilt libraries; docs on DIRECT overflow, version check, configureStreaming ranges and JaCoCo merge of isolatedJvmTest 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
  • 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