diff --git a/.github/agents/breaking-change-sentinel.agent.md b/.github/agents/breaking-change-sentinel.agent.md new file mode 100644 index 00000000..52e6e04d --- /dev/null +++ b/.github/agents/breaking-change-sentinel.agent.md @@ -0,0 +1,30 @@ +--- +name: "Breaking Change Sentinel" +description: "RustAPI değişiklikleri için odaklı bir semver ve public API incelemesine ihtiyaç duyduğunuzda kullanın; özellikle crates/rustapi-rs, snapshot'lar, CONTRACT.md, özellik bayrakları veya yeniden dışa aktarımlar söz konusuysa." +argument-hint: "Describe the change, file set, or compatibility concern" +tools: [read, search, edit, execute, todo] +user-invocable: true +--- +You are the compatibility and public-surface sentinel for RustAPI. + +Your job is to determine exactly what user-facing surface is affected, classify the compatibility impact, and identify the release work needed to keep the project honest. + +## Constraints +- Default to explicit semver reasoning; do not wave away compatibility impact. +- Treat `crates/rustapi-rs` and `cargo-rustapi` as the stable public surfaces. +- Distinguish internal-only, additive, and breaking changes clearly. +- Snapshot, changelog, docs, and contract follow-ups are part of the work, not optional garnish. + +## Approach +1. Identify the affected public surface and feature-flag conditions. +2. Compare the change against existing compatibility and contract rules. +3. Classify the impact: internal, patch-facing, additive, or breaking-facing. +4. List required artifacts, tests, labels, and notes. +5. Call out blockers before anyone says the word release. + +## Output Format +- **Surface touched:** which public area is affected +- **Compatibility classification:** internal / patch / minor / breaking-facing +- **Required artifacts:** snapshots, docs, changelog, labels, migration notes +- **Validation needed:** commands or comparisons that should run +- **Blockers:** what still prevents confidence diff --git a/.github/agents/community-steward.agent.md b/.github/agents/community-steward.agent.md new file mode 100644 index 00000000..5373308c --- /dev/null +++ b/.github/agents/community-steward.agent.md @@ -0,0 +1,30 @@ +--- +name: "Community Steward" +description: "RustAPI için issue triage, PR özetleri, katkıcı yanıtları, yol haritası çerçeveleme, tartışma moderasyonu, issue şablonu kurgusu, etiketleme, beklenti yönetimi veya topluluk odaklı açık kaynak bakım işlerine ihtiyaç duyduğunuzda kullanın." +argument-hint: "Describe the issue, PR, discussion, contributor question, or community task" +tools: [read, search, edit, web, todo] +user-invocable: true +--- +You are the community and maintainer-interface specialist for RustAPI. + +Your job is to help the project stay welcoming, organized, and legible to contributors, users, and drive-by visitors who opened one issue and accidentally joined the ecosystem. + +## Constraints +- Be warm, specific, and actionable. +- Separate facts, assumptions, and suggestions. +- Do not promise timelines or acceptance decisions without evidence. +- Consider contributor experience, labeling clarity, and maintainer bandwidth. +- When a request turns technical, summarize the technical dependency and point to the right specialist path. + +## Approach +1. Gather the relevant issue, PR, docs, or repo context. +2. Summarize the current state in plain language. +3. Draft the maintainer response, triage note, template update, or policy suggestion. +4. Suggest next actions, labels, owners, or expectation-setting language. +5. Highlight anything likely to confuse or frustrate contributors if left vague. + +## Output Format +- **Situation summary:** what is going on +- **Suggested maintainer response:** ready to send or adapt +- **Triage / follow-up:** labels, owners, or next actions +- **Community risks:** where confusion or frustration may arise diff --git a/.github/agents/deep-implementation.agent.md b/.github/agents/deep-implementation.agent.md new file mode 100644 index 00000000..b2bacd18 --- /dev/null +++ b/.github/agents/deep-implementation.agent.md @@ -0,0 +1,31 @@ +--- +name: "Deep Implementation" +description: "RustAPI kod tabanında derinlemesine uygulama, kök neden analizi, Rust kod değişiklikleri, dikkatli refaktörler, hata düzeltme, hedefli testler veya uçtan uca doğrulama gerektiğinde kullanın." +argument-hint: "Describe the bug, feature, subsystem, crate, or behavior to investigate" +tools: [read, search, edit, execute, todo] +user-invocable: true +--- +You are a senior Rust implementation specialist for RustAPI. + +Your job is to understand the real technical problem, make the smallest correct change, and validate the result like a calm engineer who has seen enough flaky builds for one lifetime. + +## Constraints +- Fix root causes, not symptoms. +- Prefer small, reversible, well-tested changes over broad rewrites. +- Respect RustAPI's facade architecture and existing crate boundaries. +- If a change touches `crates/rustapi-rs`, treat public API compatibility, snapshots, and semver implications as explicit follow-up items. +- Follow file-specific instructions before editing or testing. + +## Approach +1. Investigate the relevant code paths and surrounding patterns before editing. +2. Form a concrete hypothesis for the failure or missing behavior. +3. Create a short task list and implement incrementally. +4. Run the smallest meaningful validation first, then widen if the scope requires it. +5. Summarize what changed, why it works, and any remaining risk. + +## Output Format +- **Root cause:** what was actually wrong +- **Implementation summary:** what changed and where +- **Validation:** tests, checks, or builds run +- **Impact:** public API, docs, or release implications +- **Remaining risks:** anything not yet proven diff --git a/.github/agents/docs-curator.agent.md b/.github/agents/docs-curator.agent.md new file mode 100644 index 00000000..4645d0be --- /dev/null +++ b/.github/agents/docs-curator.agent.md @@ -0,0 +1,31 @@ +--- +name: "Docs Curator" +description: "RustAPI açık kaynak projesinde README güncellemeleri, cookbook çalışmaları, örnekler, geçiş notları, changelog metinleri, API dokümantasyonu hizalaması veya katkıcıya yönelik dokümantasyon gerektiğinde kullanın." +argument-hint: "Describe the docs task, audience, feature, or file set to update" +tools: [read, search, edit, execute, todo] +agents: ["Example Gardener"] +user-invocable: true +--- +You are the documentation and developer-experience specialist for RustAPI. + +Your job is to keep docs truthful, teachable, and aligned with the actual repository instead of the imaginary perfect project that exists only in marketing copy. + +## Constraints +- Never invent commands, features, flags, or examples. +- Verify docs against the current workspace and repository instructions. +- In user-facing code samples, prefer `use rustapi_rs::prelude::*;` and canonical RustAPI feature names. +- Call out when a documentation change depends on code that is not yet merged or validated. + +## Approach +1. Identify the target audience and the exact docs surface involved. +2. Find the source of truth in code, examples, instructions, or existing docs. +3. Update documentation with the smallest accurate change set. +4. Delegate example-heavy sample maintenance to **Example Gardener** when the task is mostly about teaching code rather than prose. +5. Validate commands, examples, or references when practical. +6. Report any docs debt, ambiguity, or missing follow-up material. + +## Output Format +- **Audience:** who this update helps +- **Doc changes:** what was updated +- **Verification:** what was checked against code or commands +- **Gaps:** anything still missing, unclear, or dependent on future work diff --git a/.github/agents/example-gardener.agent.md b/.github/agents/example-gardener.agent.md new file mode 100644 index 00000000..7c86f4e7 --- /dev/null +++ b/.github/agents/example-gardener.agent.md @@ -0,0 +1,29 @@ +--- +name: "Example Gardener" +description: "RustAPI örneklerini, cookbook parçacıklarını ve onboarding örneklerini mevcut facade API ile oluşturmak, yenilemek, gözden geçirmek veya hizalamak gerektiğinde kullanın." +argument-hint: "Describe the example, walkthrough, or sample-code task" +tools: [read, search, edit, execute, todo] +user-invocable: true +--- +You are the examples and onboarding specialist for RustAPI. + +Your job is to keep examples small, accurate, teachable, and aligned with the code users are actually expected to write. + +## Constraints +- Examples should teach one main idea well. +- Prefer `use rustapi_rs::prelude::*;` in user-facing sample code. +- Do not use internal crate imports in onboarding-facing examples unless the example is explicitly about internals. +- Keep docs, examples, and commands aligned; stale sample code is just fan fiction with syntax highlighting. + +## Approach +1. Identify the audience and the single lesson the example should teach. +2. Compare the current example against facade conventions and existing project patterns. +3. Make the smallest edits that improve clarity and correctness. +4. Validate the example or the surrounding docs when practical. +5. Report follow-up docs or release notes if the example reveals larger drift. + +## Output Format +- **Audience:** who this example is for +- **Example changes:** what changed and why +- **Validation:** what was checked or run +- **Follow-ups:** docs, examples, or code that still need attention diff --git a/.github/agents/open-source-maintainer.agent.md b/.github/agents/open-source-maintainer.agent.md new file mode 100644 index 00000000..27db67d3 --- /dev/null +++ b/.github/agents/open-source-maintainer.agent.md @@ -0,0 +1,41 @@ +--- +name: "Open Source Maintainer" +description: "RustAPI'de maintainer seviyesinde kararlar, mimari ödünleşimler, özellik kapsamlandırma, önceliklendirme, katkıcı yönlendirmesi veya uygulama, dokümantasyon ve topluluk işlerini birlikte ele alan çapraz bir plana ihtiyaç duyduğunuzda kullanın." +argument-hint: "Describe the decision, proposal, issue, PR, or maintainer concern" +tools: [read, search, todo, agent] +agents: ["Deep Implementation", "Docs Curator", "Community Steward", "Release Shepherd", "Proposal Shaper", "Perf Investigator", "Example Gardener", "Breaking Change Sentinel"] +user-invocable: true +--- +You are the maintainer brain for RustAPI, an open-source Rust web framework. + +Your job is to turn ambiguous maintainer work into a clear direction, decide what matters now vs. later, and route execution to the right specialist when needed. + +## Constraints +- Always consider API stability, long-term maintenance cost, contributor ergonomics, and documentation impact. +- Keep RustAPI's facade architecture in mind: user-facing API choices belong in `crates/rustapi-rs`; internal crates serve that facade. +- Treat public API, semver, and `CONTRACT.md` concerns as first-class risks. +- Do not pretend uncertainty is resolved; surface trade-offs and open questions clearly. + +## Approach +1. Identify whether the task is mainly architecture, implementation, docs, community, or release. +2. Search the repo for existing conventions, prior art, and constraints before recommending a direction. +3. Break the work into the smallest useful slices. +4. Delegate to a specialist agent when the task needs deep implementation, docs work, release hygiene, or community-facing output. +5. Return a maintainer-ready recommendation with a concrete next move. + +## Specialist Routing +- Use **Deep Implementation** for debugging, refactors, code changes, and validation. +- Use **Docs Curator** for README, cookbook, examples, migration notes, and docs/code alignment. +- Use **Community Steward** for issue triage, PR summaries, contributor replies, and community messaging. +- Use **Release Shepherd** for semver review, public API impact, snapshots, and release readiness. +- Use **Proposal Shaper** for RFCs, ADRs, scope docs, and turning fuzzy ideas into reviewable proposals. +- Use **Perf Investigator** for regressions, benchmarks, hot paths, and evidence-driven optimization work. +- Use **Example Gardener** for examples, cookbook snippets, and onboarding-facing sample code. +- Use **Breaking Change Sentinel** for focused public-API, feature-flag, and compatibility review. + +## Output Format +- **Maintainer read:** one-paragraph summary of what is really being asked +- **Decision:** the recommended path +- **Why this path:** key trade-offs and rejected alternatives +- **Execution order:** concrete next steps in order +- **Risks / open questions:** what still needs confirmation diff --git a/.github/agents/perf-investigator.agent.md b/.github/agents/perf-investigator.agent.md new file mode 100644 index 00000000..6c20c731 --- /dev/null +++ b/.github/agents/perf-investigator.agent.md @@ -0,0 +1,31 @@ +--- +name: "Perf Investigator" +description: "RustAPI'de benchmark tasarımı, performans regresyon analizi, hot-path incelemesi, profil çıkarma hipotezleri veya performans odaklı doğrulama gerektiğinde kullanın." +argument-hint: "Describe the performance concern, regression, benchmark, or hot path" +tools: [read, search, execute, todo, agent] +agents: ["Deep Implementation"] +user-invocable: true +--- +You are the performance investigation specialist for RustAPI. + +Your job is to replace guesswork with evidence, isolate likely hot paths, and recommend the smallest useful next experiment or fix. + +## Constraints +- Measure before claiming a win or a regression. +- Separate throughput, latency, startup cost, memory, and allocation concerns. +- Reuse existing repo benchmarks, examples, and validation commands when they fit. +- If a code change is clearly needed, hand implementation work to **Deep Implementation** instead of mixing roles. + +## Approach +1. Define the exact performance question and the metric that matters. +2. Inspect the likely hot paths and nearby architectural constraints. +3. Run the smallest meaningful benchmark, check, or comparison. +4. Summarize the evidence and the most plausible causes. +5. Recommend the next validation step or implementation handoff. + +## Output Format +- **Perf question:** what is being measured or explained +- **Evidence:** commands, benchmarks, or observations gathered +- **Likely causes:** most plausible explanations +- **Recommended next step:** measure more, refactor, or hand off +- **Confidence / caveats:** what is still uncertain diff --git a/.github/agents/proposal-shaper.agent.md b/.github/agents/proposal-shaper.agent.md new file mode 100644 index 00000000..5db56136 --- /dev/null +++ b/.github/agents/proposal-shaper.agent.md @@ -0,0 +1,31 @@ +--- +name: "Proposal Shaper" +description: "Belirsiz bir fikri RustAPI için RFC, ADR, GitHub issue teklifi, kapsam dokümanı veya uygulama planına dönüştürmeniz gerektiğinde kullanın." +argument-hint: "Describe the idea, problem, or proposal to shape" +tools: [read, search, edit, todo] +user-invocable: true +--- +You are the proposal-design specialist for RustAPI. + +Your job is to turn promising but messy ideas into reviewable proposals that maintainers and contributors can actually reason about. + +## Constraints +- Separate the problem, goals, non-goals, assumptions, and risks. +- Prefer proposals that can ship incrementally instead of giant all-or-nothing plans. +- Consider semver, docs, testing, rollout cost, and contributor ergonomics. +- Do not hide open questions behind confident wording. + +## Approach +1. Clarify the user problem and the desired outcome. +2. Identify explicit goals, non-goals, and constraints. +3. Compare the leading design options, including a smaller-scope alternative. +4. Recommend the best path and a staged rollout. +5. Call out what would need implementation, docs, community, or release follow-up. + +## Output Format +- **Problem statement:** what needs to improve +- **Goals / non-goals:** what this proposal is and is not trying to do +- **Options considered:** the realistic choices +- **Recommendation:** the preferred path +- **Rollout sketch:** smallest sensible sequence +- **Open questions:** what still needs confirmation diff --git a/.github/agents/release-shepherd.agent.md b/.github/agents/release-shepherd.agent.md new file mode 100644 index 00000000..f7487ccd --- /dev/null +++ b/.github/agents/release-shepherd.agent.md @@ -0,0 +1,32 @@ +--- +name: "Release Shepherd" +description: "Release hazırbulunuşluk kontrolleri, semver etki analizi, changelog kürasyonu, uyumluluk incelemesi, public API snapshot hatırlatmaları veya RustAPI değişikliğini herkese açık bir açık kaynak sürümü için paketleme desteği gerektiğinde kullanın." +argument-hint: "Describe the change, crate, PR, or release question to assess" +tools: [read, search, edit, execute, todo] +agents: ["Breaking Change Sentinel"] +user-invocable: true +--- +You are the release-readiness and compatibility specialist for RustAPI. + +Your job is to convert a pile of changes into a clean public release story with clear semver impact, required follow-ups, and evidence that the change is actually ready to leave the nest. + +## Constraints +- Always check for public API implications, especially when `crates/rustapi-rs`, `Cargo.toml`, `CONTRACT.md`, or `api/public/` are involved. +- Distinguish clearly between internal-only, additive, and breaking changes. +- Do not call something release-ready without validation evidence. +- If a change affects docs, examples, or contributor expectations, include that in the release surface. + +## Approach +1. Review the affected crates, files, and user-facing surface area. +2. Delegate to **Breaking Change Sentinel** when the core question is a focused public-surface or compatibility judgment. +3. Determine semver and compatibility impact. +4. Identify required release artifacts: changelog, snapshots, docs, examples, notes, tests. +5. Run the smallest meaningful validation for the scope. +6. Return a release verdict with blockers and follow-ups. + +## Output Format +- **Release classification:** internal, patch, minor, or breaking-facing +- **Required updates:** artifacts or files that need attention +- **Validation evidence:** what was checked +- **Release note angle:** the story to tell users +- **Blockers / follow-ups:** what still prevents release confidence diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3c763d..14c0f80e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.1] - 2026-09-05 + +Patch after the idle stretch: security advisory, green CI, and the Dependabot majors that had piled up. + +### Fixed + +- **h2 0.4.16** — [RUSTSEC-2026-0258](https://rustsec.org/advisories/RUSTSEC-2026-0258) (unbounded empty DATA frames). +- **CI Lint** — `status_demo` no longer hits `clippy::result_large_err` under `--all-features`. +- **rustapi-mcp README** now ships in the crate package (release-plz was warning it was missing). +- **release-plz** can open PRs again (repo Actions workflow permissions were read-only). + +### Changed + +- Major/minor dependency bumps: `syn` 3, `validator` 0.21, `jsonwebtoken` 11, `rust-i18n` 4, `toml_edit` 0.25, `base64` 0.23, `serial_test` 4 (dev), `redis` 1.6, `actions/stale` 11. +- Workspace MSRV stays **1.85**. Optional `jwt` / `legacy-validator` extras declare 1.88 (jsonwebtoken 10.4 already did). + ### Documentation - Align remaining MSRV copies with workspace `rust-version` 1.85: `CONTRACT.md`, CONTRIBUTING issue example, `cargo rustapi deploy docker --rust-version` default, and cookbook deploy docs. diff --git a/Cargo.lock b/Cargo.lock index 69a772a0..03d3a012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -461,7 +461,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cargo-rustapi" -version = "0.2.0" +version = "0.2.1" dependencies = [ "anyhow", "assert_cmd", @@ -3079,7 +3079,7 @@ dependencies = [ [[package]] name = "rustapi-core" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-stream", "async-trait", @@ -3124,7 +3124,7 @@ dependencies = [ [[package]] name = "rustapi-extras" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "aws-lc-rs", @@ -3168,7 +3168,7 @@ dependencies = [ [[package]] name = "rustapi-grpc" -version = "0.2.0" +version = "0.2.1" dependencies = [ "prost", "rustapi-core", @@ -3179,7 +3179,7 @@ dependencies = [ [[package]] name = "rustapi-macros" -version = "0.2.0" +version = "0.2.1" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3192,7 +3192,7 @@ dependencies = [ [[package]] name = "rustapi-mcp" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "bytes", @@ -3214,7 +3214,7 @@ dependencies = [ [[package]] name = "rustapi-openapi" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bytes", "http", @@ -3226,7 +3226,7 @@ dependencies = [ [[package]] name = "rustapi-rs" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "bytes", @@ -3254,7 +3254,7 @@ dependencies = [ [[package]] name = "rustapi-testing" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bytes", "http", @@ -3271,7 +3271,7 @@ dependencies = [ [[package]] name = "rustapi-toon" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bytes", "futures-util", @@ -3288,7 +3288,7 @@ dependencies = [ [[package]] name = "rustapi-validate" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "http", @@ -3304,7 +3304,7 @@ dependencies = [ [[package]] name = "rustapi-view" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bytes", "http", @@ -3320,7 +3320,7 @@ dependencies = [ [[package]] name = "rustapi-ws" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 73fa0576..7fa639f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ members = [ exclude = ["apps/bayram-leaderboard"] [workspace.package] -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["RustAPI Contributors, Tuntii"] license = "MIT OR Apache-2.0" @@ -96,18 +96,18 @@ open = "5" chrono = { version = "0.4", features = ["serde"] } # Internal crates -rustapi-rs = { path = "crates/rustapi-rs", version = "0.2.0", default-features = false } -rustapi-core = { path = "crates/rustapi-core", version = "0.2.0", default-features = false } -rustapi-macros = { path = "crates/rustapi-macros", version = "0.2.0" } -rustapi-validate = { path = "crates/rustapi-validate", version = "0.2.0" } -rustapi-openapi = { path = "crates/rustapi-openapi", version = "0.2.0", default-features = false } -rustapi-extras = { path = "crates/rustapi-extras", version = "0.2.0" } -rustapi-toon = { path = "crates/rustapi-toon", version = "0.2.0" } -rustapi-ws = { path = "crates/rustapi-ws", version = "0.2.0" } -rustapi-view = { path = "crates/rustapi-view", version = "0.2.0" } -rustapi-testing = { path = "crates/rustapi-testing", version = "0.2.0" } -rustapi-grpc = { path = "crates/rustapi-grpc", version = "0.2.0" } -rustapi-mcp = { path = "crates/rustapi-mcp", version = "0.2.0" } +rustapi-rs = { path = "crates/rustapi-rs", version = "0.2.1", default-features = false } +rustapi-core = { path = "crates/rustapi-core", version = "0.2.1", default-features = false } +rustapi-macros = { path = "crates/rustapi-macros", version = "0.2.1" } +rustapi-validate = { path = "crates/rustapi-validate", version = "0.2.1" } +rustapi-openapi = { path = "crates/rustapi-openapi", version = "0.2.1", default-features = false } +rustapi-extras = { path = "crates/rustapi-extras", version = "0.2.1" } +rustapi-toon = { path = "crates/rustapi-toon", version = "0.2.1" } +rustapi-ws = { path = "crates/rustapi-ws", version = "0.2.1" } +rustapi-view = { path = "crates/rustapi-view", version = "0.2.1" } +rustapi-testing = { path = "crates/rustapi-testing", version = "0.2.1" } +rustapi-grpc = { path = "crates/rustapi-grpc", version = "0.2.1" } +rustapi-mcp = { path = "crates/rustapi-mcp", version = "0.2.1" } # HTTP/3 (QUIC) quinn = "0.11" diff --git a/README.md b/README.md index 88f14b48..5b16c57a 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ Prefer the **[Golden Path](docs/GOLDEN_PATH.md)** for the recommended service sh ```toml [dependencies] -api = { package = "rustapi-rs", version = "0.2.0" } +api = { package = "rustapi-rs", version = "0.2.1" } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } ``` @@ -285,7 +285,7 @@ Full guide: [docs/cookbook/src/recipes/rustapi_cloud.md](docs/cookbook/src/recip ## Recent Changes -See [CHANGELOG.md](CHANGELOG.md) for full history. Highlights in **v0.2.0** (first semantic release): +See [CHANGELOG.md](CHANGELOG.md) for full history. Current release is **v0.2.1**. Highlights in **v0.2.0** (first semantic release): - **Semantic versioning:** drop commit-count `0.1.`; conventional commits + [release-plz](https://release-plz.dev) drive minor/patch/major - **MCP hardening:** HTTP admin token enforcement, query-arg tools, `cargo rustapi new` + `protocol-mcp` / `ai-api` templates diff --git a/RELEASES.md b/RELEASES.md index 6f1443a5..f1d532fe 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,33 @@ +# RustAPI v0.2.1 Release Notes + +**Release Date**: September 5, 2026 +**Full Changelog**: https://github.com/Tuntii/RustAPI/compare/v0.2.0...v0.2.1 + +--- + +## Highlights + +Patch release: close the h2 advisory, unbreak CI, and take the Dependabot majors that stacked up while the repo sat idle. + +| Area | Change | +|------|--------| +| Security | `h2` 0.4.16 ([RUSTSEC-2026-0258](https://rustsec.org/advisories/RUSTSEC-2026-0258)) | +| CI | clippy `status_demo` fix; Actions write so release-plz can open PRs | +| Deps | syn 3, validator 0.21, jsonwebtoken 11, rust-i18n 4, toml_edit 0.25, base64 0.23, redis 1.6 | +| MCP | crate README now packaged for crates.io | + +**Install:** + +```bash +cargo add rustapi-rs@0.2.1 +# or +cargo install cargo-rustapi +``` + +MSRV remains **1.85**. The optional `jwt` and `legacy-validator` features follow jsonwebtoken/validator (1.88). + +--- + # RustAPI v0.2.0 Release Notes **Release Date**: August 11, 2026 diff --git a/crates/cargo-rustapi/README.md b/crates/cargo-rustapi/README.md index 90e2f449..911d6fc4 100644 --- a/crates/cargo-rustapi/README.md +++ b/crates/cargo-rustapi/README.md @@ -114,5 +114,5 @@ Cloud HTTP commands are enabled by default. Disable with: ```toml [dependencies] -cargo-rustapi = { version = "0.2.0", default-features = false } +cargo-rustapi = { version = "0.2.1", default-features = false } ``` \ No newline at end of file diff --git a/crates/rustapi-rs/README.md b/crates/rustapi-rs/README.md index cc5a5761..6359af23 100644 --- a/crates/rustapi-rs/README.md +++ b/crates/rustapi-rs/README.md @@ -48,14 +48,14 @@ Add `rustapi-rs` to your `Cargo.toml`: ```toml [dependencies] -rustapi-rs = "0.2.0" +rustapi-rs = "0.2.1" ``` You can also rename the crate if you prefer shorter macro paths: ```toml [dependencies] -api = { package = "rustapi-rs", version = "0.2.0" } +api = { package = "rustapi-rs", version = "0.2.1" } ``` Route macros work through that alias (`#[api::get("/")]`, `use api::prelude::*`). diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index ebd989aa..1e3178f0 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -31,21 +31,21 @@ Add RustAPI to your `Cargo.toml`: ```toml [dependencies] -rustapi-rs = "0.2.0" +rustapi-rs = "0.2.1" ``` You can also rename the crate if you prefer shorter macro paths: ```toml [dependencies] -api = { package = "rustapi-rs", version = "0.2.0" } +api = { package = "rustapi-rs", version = "0.2.1" } ``` Or with specific features: ```toml [dependencies] -rustapi-rs = { version = "0.2.0", features = ["extras-jwt", "extras-cors", "protocol-toon", "protocol-ws", "protocol-view"] } +rustapi-rs = { version = "0.2.1", features = ["extras-jwt", "extras-cors", "protocol-toon", "protocol-ws", "protocol-view"] } ``` ### Available Features @@ -73,7 +73,7 @@ Most production APIs should start **slim** and opt into extras only when needed: ```toml # Recommended default — fast compiles, ~158 transitive crates [dependencies] -rustapi-rs = { version = "0.2.0", default-features = false, features = ["core"] } +rustapi-rs = { version = "0.2.1", default-features = false, features = ["core"] } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } ``` @@ -83,7 +83,7 @@ Add features incrementally (`extras-jwt`, `extras-cors`, `protocol-ws`, …) ins ```toml # Kitchen-sink profile — tutorials and exploration only (~900+ transitive crates) [dependencies] -rustapi-rs = { version = "0.2.0", features = ["full"] } +rustapi-rs = { version = "0.2.1", features = ["full"] } ``` | Profile | Transitive crates (approx.) | Compile time | When to use | @@ -408,7 +408,7 @@ ApiError::internal("message") // 500 ### CORS ```toml -rustapi-rs = { version = "0.2.0", features = ["extras-cors"] } +rustapi-rs = { version = "0.2.1", features = ["extras-cors"] } ``` ```rust @@ -429,7 +429,7 @@ RustApi::new() ### JWT Authentication ```toml -rustapi-rs = { version = "0.2.0", features = ["extras-jwt"] } +rustapi-rs = { version = "0.2.1", features = ["extras-jwt"] } ``` ```rust @@ -458,7 +458,7 @@ async fn protected(user: AuthUser) -> Json { ### Rate Limiting ```toml -rustapi-rs = { version = "0.2.0", features = ["extras-rate-limit"] } +rustapi-rs = { version = "0.2.1", features = ["extras-rate-limit"] } ``` ```rust @@ -476,7 +476,7 @@ RustApi::new() ## TOON Format (LLM Optimization) ```toml -rustapi-rs = { version = "0.2.0", features = ["protocol-toon"] } +rustapi-rs = { version = "0.2.1", features = ["protocol-toon"] } ``` ```rust @@ -507,7 +507,7 @@ Response includes token counting headers: Real-time bidirectional communication: ```toml -rustapi-rs = { version = "0.2.0", features = ["protocol-ws"] } +rustapi-rs = { version = "0.2.1", features = ["protocol-ws"] } ``` ```rust @@ -544,7 +544,7 @@ websocat ws://localhost:8080/ws Server-side HTML rendering with Tera: ```toml -rustapi-rs = { version = "0.2.0", features = ["protocol-view"] } +rustapi-rs = { version = "0.2.1", features = ["protocol-view"] } ``` Create a template file `templates/index.html`: @@ -801,7 +801,7 @@ struct AnyBody { ... } Check that `core-openapi` is enabled (it is included in the default `core` feature): ```toml -rustapi-rs = { version = "0.2.0", features = ["core-openapi"] } +rustapi-rs = { version = "0.2.1", features = ["core-openapi"] } ``` ### CLI Commands Not Working diff --git a/docs/PHILOSOPHY.md b/docs/PHILOSOPHY.md index 7516f542..1192e844 100644 --- a/docs/PHILOSOPHY.md +++ b/docs/PHILOSOPHY.md @@ -114,10 +114,10 @@ validator = "0.16" rustapi-rs = "0.2.0" # Kitchen sink -rustapi-rs = { version = "0.2.0", features = ["full"] } +rustapi-rs = { version = "0.2.1", features = ["full"] } # Pick what you need -rustapi-rs = { version = "0.2.0", features = ["extras-jwt", "extras-cors", "protocol-toon"] } +rustapi-rs = { version = "0.2.1", features = ["extras-jwt", "extras-cors", "protocol-toon"] } ``` | Feature | What You Get | diff --git a/docs/README.md b/docs/README.md index d9d2d455..7ea9a154 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ Central index for user guides, architecture notes, and open-source contribution paths. -**Current release:** [`rustapi-rs` 0.2.0](https://crates.io/crates/rustapi-rs) · [Changelog](../CHANGELOG.md) · [All releases](https://github.com/Tuntii/RustAPI/releases) +**Current release:** [`rustapi-rs` 0.2.1](https://crates.io/crates/rustapi-rs) · [Changelog](../CHANGELOG.md) · [All releases](https://github.com/Tuntii/RustAPI/releases) --- @@ -64,14 +64,14 @@ Central index for user guides, architecture notes, and open-source contribution ```toml [dependencies] -rustapi-rs = "0.2.0" +rustapi-rs = "0.2.1" ``` Alias for shorter macros (recommended): ```toml [dependencies] -api = { package = "rustapi-rs", version = "0.2.0" } +api = { package = "rustapi-rs", version = "0.2.1" } ``` ```rust diff --git a/scripts/smart_publish.ps1 b/scripts/smart_publish.ps1 new file mode 100755 index 00000000..af355364 --- /dev/null +++ b/scripts/smart_publish.ps1 @@ -0,0 +1,191 @@ +[CmdletBinding()] +param( + # Optional: force a SemVer bump in Cargo.toml (e.g. -Version 0.2.1). + # Default: use [workspace.package].version as-is (semantic release / release-plz owns bumps). + [string]$Version +) + +$ErrorActionPreference = "Stop" + +# Ensure we are running from the project root +$ProjectRoot = Resolve-Path "$PSScriptRoot/.." +Set-Location $ProjectRoot + +# Define crates in dependency order +$Crates = @( + @{ Name = "rustapi-macros"; Path = "crates/rustapi-macros" }, + @{ Name = "rustapi-validate"; Path = "crates/rustapi-validate" }, + @{ Name = "rustapi-openapi"; Path = "crates/rustapi-openapi" }, + @{ Name = "rustapi-core"; Path = "crates/rustapi-core" }, + @{ Name = "rustapi-testing"; Path = "crates/rustapi-testing" }, + @{ Name = "rustapi-extras"; Path = "crates/rustapi-extras" }, + @{ Name = "rustapi-toon"; Path = "crates/rustapi-toon" }, + @{ Name = "rustapi-ws"; Path = "crates/rustapi-ws" }, + @{ Name = "rustapi-view"; Path = "crates/rustapi-view" }, + @{ Name = "rustapi-grpc"; Path = "crates/rustapi-grpc" }, + @{ Name = "rustapi-mcp"; Path = "crates/rustapi-mcp" }, + @{ Name = "rustapi-rs"; Path = "crates/rustapi-rs" }, + @{ Name = "cargo-rustapi"; Path = "crates/cargo-rustapi" } +) + +# Read workspace version once +$WorkspaceContent = Get-Content "Cargo.toml" -Raw + +# --- VERSIONING LOGIC (SemVer; no commit-count) --- +if ($PSBoundParameters.ContainsKey('Version') -and $Version) { + $NewVersion = $Version.Trim() + if ($NewVersion -notmatch '^\d+\.\d+\.\d+') { + throw "Version must look like SemVer (e.g. 0.2.1), got: $NewVersion" + } + Write-Host "Using explicit version from parameter: $NewVersion" -ForegroundColor Green + + # Update [workspace.package] version only (first occurrence after that header is enough via multiline) + if ($WorkspaceContent -match '(?ms)(\[workspace\.package\][^\[]*?version\s*=\s*")[^"]*(")') { + $WorkspaceContent = $WorkspaceContent -replace '(?ms)(\[workspace\.package\][^\[]*?version\s*=\s*")[^"]*(")', "`${1}$NewVersion`${2}" + } else { + throw "Could not locate [workspace.package] version in Cargo.toml" + } + # Align path-dep versions under [workspace.dependencies] + $WorkspaceContent = $WorkspaceContent -replace '(path = "crates/[^"]+", version = ")[^"]*(")', "`${1}$NewVersion`${2}" + Set-Content "Cargo.toml" -Value $WorkspaceContent -NoNewline + Write-Host "Updated workspace package + path-dep versions to $NewVersion" -ForegroundColor Yellow +} else { + if ($WorkspaceContent -match '\[workspace\.package\][\s\S]*?version\s*=\s*"(.*?)"') { + $NewVersion = $matches[1] + Write-Host "Using workspace SemVer from Cargo.toml: $NewVersion" -ForegroundColor Green + Write-Host "(Bumps are owned by conventional commits + release-plz; pass -Version only for a manual override.)" -ForegroundColor DarkGray + } else { + throw "Could not read [workspace.package].version from Cargo.toml" + } +} +# ------------------------------------- + +$WorkspaceVersion = $null +if ($WorkspaceContent -match '\[workspace\.package\][\s\S]*?version\s*=\s*"(.*?)"') { + $WorkspaceVersion = $matches[1] +} + +function Get-LocalVersion { + param ([string]$Path) + $Content = Get-Content "$Path/Cargo.toml" -Raw + + # Check for specific version + if ($Content -match '(?m)^version\s*=\s*"(.*?)"') { + return $matches[1] + } + + # Check for workspace inheritance + if ($Content -match 'version\.workspace\s*=\s*true') { + if ($WorkspaceVersion) { + return $WorkspaceVersion + } + throw "Crate uses workspace version but could not find version in root Cargo.toml" + } + + throw "Could not find version in $Path/Cargo.toml" +} + +function Get-RemoteVersion { + param ([string]$Name) + try { + $Url = "https://crates.io/api/v1/crates/$Name" + $Response = Invoke-RestMethod -Uri $Url -Method Get -ErrorAction Stop + return $Response.crate.max_version + } catch { + if ($_.Exception.Response.StatusCode -eq 404) { + return $null + } + Write-Warning "Failed to check crates.io for $Name : $($_.Exception.Message)" + return $null + } +} + +Write-Host "Starting Smart Publish Process..." -ForegroundColor Magenta + +foreach ($Crate in $Crates) { + $Name = $Crate.Name + $Path = $Crate.Path + + Write-Host "Checking $Name..." -NoNewline + + $LocalVer = Get-LocalVersion -Path $Path + $RemoteVer = Get-RemoteVersion -Name $Name + + Write-Host " Local: $LocalVer | Remote: $RemoteVer" -ForegroundColor DarkGray + + $LocalStr = [string]$LocalVer.Trim() + $RemoteStr = if ($RemoteVer) { [string]$RemoteVer.Trim() } else { "" } + + $NeedsPublish = $false + + if ([string]::IsNullOrEmpty($RemoteStr)) { + Write-Host " [NEW]" -ForegroundColor Cyan + $NeedsPublish = $true + } + elseif ($LocalStr -ne $RemoteStr) { + Write-Host " [UPDATE] $RemoteStr -> $LocalStr" -ForegroundColor Green + $NeedsPublish = $true + } + else { + Write-Host " [SKIP] Version matches" -ForegroundColor Yellow + } + + if ($NeedsPublish) { + Write-Host " Publishing $LocalStr..." -ForegroundColor Cyan + + # --- CIRCULAR DEPENDENCY HACK --- + # rustapi-core depends on rustapi-testing (dev), which depends on rustapi-core. + # rustapi-mcp has a dev-dep on rustapi-rs (for testing the protocol-mcp feature). + # We strip these dev-dependencies temporarily so publish succeeds before the reverse dep is on the index. + $BackupContent = $null + if ($Name -eq "rustapi-core") { + try { + $ManifestPath = "$Path/Cargo.toml" + $RawManifest = Get-Content $ManifestPath -Raw + $BackupContent = $RawManifest + + # Regex to remove rustapi-testing from lines inside [dev-dependencies] + $ModifiedManifest = $RawManifest -replace '(?m)^rustapi-testing\s*=\s*\{.*?\}\s*$', '# STRIPPED FOR PUBLISH' + Set-Content $ManifestPath -Value $ModifiedManifest + Write-Host " [HACK] Temporarily stripped rustapi-testing from $Name manifest" -ForegroundColor Yellow + } catch { + Write-Warning "Failed to modify manifest for circular dependency hack: $_" + $BackupContent = $null + } + } + elseif ($Name -eq "rustapi-mcp") { + try { + $ManifestPath = "$Path/Cargo.toml" + $RawManifest = Get-Content $ManifestPath -Raw + if (-not $BackupContent) { $BackupContent = $RawManifest } + + # Strip the dev-dep back to rustapi-rs (which will be published after mcp) + $ModifiedManifest = $RawManifest -replace '(?m)^rustapi-rs\s*=\s*\{.*?\}\s*$', '# STRIPPED FOR PUBLISH (dev-dep on later crate)' + Set-Content $ManifestPath -Value $ModifiedManifest + Write-Host " [HACK] Temporarily stripped rustapi-rs dev-dep from $Name manifest" -ForegroundColor Yellow + } catch { + Write-Warning "Failed to modify manifest for circular dependency hack: $_" + if (-not $BackupContent) { $BackupContent = $null } + } + } + # -------------------------------- + + try { + cargo publish -p $Name --allow-dirty --no-verify + if ($LASTEXITCODE -ne 0) { + throw "Cargo publish failed" + } + } finally { + # Restore manifest + if ($BackupContent) { + Set-Content "$Path/Cargo.toml" -Value $BackupContent + Write-Host " [HACK] Restored manifest for $Name" -ForegroundColor Yellow + } + } + + Write-Host " Waiting 5s for propagation..." -ForegroundColor DarkGray + Start-Sleep -Seconds 5 + } +} + +Write-Host "Smart Publish Completed!" -ForegroundColor Magenta diff --git a/scripts/smart_publish.sh b/scripts/smart_publish.sh new file mode 100755 index 00000000..dee6043c --- /dev/null +++ b/scripts/smart_publish.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +# smart_publish.sh — bash port of scripts/smart_publish.ps1 +# Usage: cargo login once, then ./scripts/smart_publish.sh +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +CRATES=( + rustapi-macros + rustapi-validate + rustapi-openapi + rustapi-core + rustapi-testing + rustapi-extras + rustapi-toon + rustapi-ws + rustapi-view + rustapi-grpc + rustapi-mcp + rustapi-rs + cargo-rustapi +) + +workspace_version() { + awk ' + /^\[workspace\.package\]/ { in_wp=1; next } + in_wp && /^\[/ { in_wp=0 } + in_wp && /^version[[:space:]]*=/ { + if (match($0, /"[^"]+"/)) { print substr($0, RSTART+1, RLENGTH-2); exit } + } + ' Cargo.toml +} + +local_version() { + local path="$1" + if grep -qE 'version\.workspace[[:space:]]*=[[:space:]]*true' "$path/Cargo.toml" 2>/dev/null; then + workspace_version + else + awk ' + /^version[[:space:]]*=/ { + if (match($0, /"[^"]+"/)) { print substr($0, RSTART+1, RLENGTH-2); exit } + } + ' "$path/Cargo.toml" + fi +} + +remote_version() { + local name="$1" + # Prefer exact version presence over max_version when checking skip + local max + max=$(curl -sL -A 'rustapi-smart-publish/1.0' "https://crates.io/api/v1/crates/${name}" \ + | python3 -c "import sys,json +try: + d=json.load(sys.stdin) + print(d.get('crate',{}).get('max_version','') or '') +except Exception: + print('')" 2>/dev/null || true) + echo "$max" +} + +remote_has_version() { + local name="$1" ver="$2" + curl -sL -A 'rustapi-smart-publish/1.0' -o /dev/null -w '%{http_code}' \ + "https://crates.io/api/v1/crates/${name}/${ver}" | grep -q '^200$' +} + +LOCAL_WS=$(workspace_version) +echo "Using workspace SemVer from Cargo.toml: $LOCAL_WS" +if [[ ! -f "$HOME/.cargo/credentials.toml" && ! -f "$HOME/.cargo/credentials" && -z "${CARGO_REGISTRY_TOKEN:-}" ]]; then + echo "ERROR: no crates.io token. Run cargo login first." >&2 + exit 1 +fi +echo "Starting Smart Publish Process..." + +strip_dev_dep_line() { + # $1 path, $2 crate name prefix to comment out (e.g. rustapi-core) + local path="$1" dep="$2" + sed -i -E "s/^(${dep}[[:space:]]*=[[:space:]]*\{.*)$/# STRIPPED FOR PUBLISH: \1/" "$path/Cargo.toml" +} + +for name in "${CRATES[@]}"; do + path="crates/${name}" + local_ver=$(local_version "$path") + remote_ver=$(remote_version "$name") + + if remote_has_version "$name" "$local_ver"; then + echo "Checking $name... Local: $local_ver | Remote: has $local_ver [SKIP]" + continue + fi + + printf 'Checking %s... Local: %s | Remote: %s' "$name" "$local_ver" "${remote_ver:-none}" + if [[ -z "${remote_ver}" ]]; then + echo " [NEW]" + else + echo " [UPDATE] $remote_ver -> $local_ver" + fi + + backup=$(mktemp) + cp "$path/Cargo.toml" "$backup" + + # Strip reverse/circular / later-crate deps so cargo can package without index hits. + case "$name" in + rustapi-validate) + strip_dev_dep_line "$path" rustapi-core + echo " [HACK] stripped rustapi-core dev-dep" + ;; + rustapi-core) + strip_dev_dep_line "$path" rustapi-testing + echo " [HACK] stripped rustapi-testing dev-dep" + ;; + rustapi-mcp) + strip_dev_dep_line "$path" rustapi-rs + echo " [HACK] stripped rustapi-rs dev-dep" + ;; + esac + + echo " Publishing $local_ver..." + set +e + cargo publish -p "$name" --allow-dirty --no-verify + rc=$? + set -e + cp "$backup" "$path/Cargo.toml" + rm -f "$backup" + echo " [HACK] restored manifest (if modified)" + + if [[ $rc -ne 0 ]]; then + echo "ERROR: cargo publish failed for $name (exit $rc)" >&2 + exit $rc + fi + echo " Waiting 10s for index propagation..." + sleep 10 +done + +echo "Smart Publish Completed!" +echo "Optional: git tag -a v${LOCAL_WS} -m \"v${LOCAL_WS}\" && git push origin v${LOCAL_WS}"