enya-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +20 -0
- package/.github/workflows/ci.yml +70 -0
- package/.github/workflows/publish.yml +250 -0
- package/.gitmodules +3 -0
- package/Cargo.lock +3584 -0
- package/Cargo.toml +97 -0
- package/crates/enact/Cargo.toml +27 -0
- package/crates/enact/src/lib.rs +60 -0
- package/crates/enact-a2a/Cargo.toml +25 -0
- package/crates/enact-a2a/src/lib.rs +411 -0
- package/crates/enact-channels/Cargo.toml +64 -0
- package/crates/enact-channels/examples/README.md +80 -0
- package/crates/enact-channels/examples/channel_bot.rs +169 -0
- package/crates/enact-channels/examples/telegram-echo.rs +34 -0
- package/crates/enact-channels/examples/whatsapp-echo.rs +142 -0
- package/crates/enact-channels/src/config.rs +213 -0
- package/crates/enact-channels/src/lib.rs +25 -0
- package/crates/enact-channels/src/runtime.rs +237 -0
- package/crates/enact-channels/src/security/mod.rs +5 -0
- package/crates/enact-channels/src/security/pairing.rs +205 -0
- package/crates/enact-channels/src/teams.rs +601 -0
- package/crates/enact-channels/src/telegram.rs +2833 -0
- package/crates/enact-channels/src/traits.rs +200 -0
- package/crates/enact-channels/src/webhook.rs +262 -0
- package/crates/enact-channels/src/whatsapp.rs +310 -0
- package/crates/enact-cli/Cargo.toml +40 -0
- package/crates/enact-cli/src/commands/doctor.rs +62 -0
- package/crates/enact-cli/src/commands/mod.rs +3 -0
- package/crates/enact-cli/src/commands/run.rs +69 -0
- package/crates/enact-cli/src/commands/serve.rs +81 -0
- package/crates/enact-cli/src/config.rs +2 -0
- package/crates/enact-cli/src/main.rs +79 -0
- package/crates/enact-config/Cargo.toml +36 -0
- package/crates/enact-config/ENV_VAR_MAPPING.md +135 -0
- package/crates/enact-config/QUICK_REFERENCE.md +92 -0
- package/crates/enact-config/README.md +107 -0
- package/crates/enact-config/TESTING.md +161 -0
- package/crates/enact-config/examples/test-env-vars.rs +100 -0
- package/crates/enact-config/src/config.rs +399 -0
- package/crates/enact-config/src/encrypted_store.rs +211 -0
- package/crates/enact-config/src/lib.rs +298 -0
- package/crates/enact-config/src/secrets.rs +149 -0
- package/crates/enact-config/src/sync.rs +260 -0
- package/crates/enact-config/test-env-vars.sh +34 -0
- package/crates/enact-config/tests/README.md +99 -0
- package/crates/enact-config/tests/config_integration_test.rs +202 -0
- package/crates/enact-config/tests/security_test.rs +140 -0
- package/crates/enact-context/Cargo.toml +41 -0
- package/crates/enact-context/src/budget.rs +314 -0
- package/crates/enact-context/src/calibrator.rs +535 -0
- package/crates/enact-context/src/compactor.rs +392 -0
- package/crates/enact-context/src/condenser.rs +826 -0
- package/crates/enact-context/src/lib.rs +94 -0
- package/crates/enact-context/src/segment.rs +238 -0
- package/crates/enact-context/src/step_context.rs +645 -0
- package/crates/enact-context/src/token_counter.rs +148 -0
- package/crates/enact-context/src/window.rs +372 -0
- package/crates/enact-core/Cargo.toml +42 -0
- package/crates/enact-core/README.md +98 -0
- package/crates/enact-core/src/background/executor.rs +524 -0
- package/crates/enact-core/src/background/mod.rs +48 -0
- package/crates/enact-core/src/background/target_binding.rs +390 -0
- package/crates/enact-core/src/background/trigger.rs +511 -0
- package/crates/enact-core/src/callable/callable.rs +152 -0
- package/crates/enact-core/src/callable/composite.rs +817 -0
- package/crates/enact-core/src/callable/graph.rs +104 -0
- package/crates/enact-core/src/callable/llm.rs +211 -0
- package/crates/enact-core/src/callable/mod.rs +64 -0
- package/crates/enact-core/src/callable/registry.rs +206 -0
- package/crates/enact-core/src/context/execution_context.rs +757 -0
- package/crates/enact-core/src/context/invocation.rs +99 -0
- package/crates/enact-core/src/context/mod.rs +50 -0
- package/crates/enact-core/src/context/tenant.rs +175 -0
- package/crates/enact-core/src/context/trace.rs +127 -0
- package/crates/enact-core/src/flow/conditional.rs +293 -0
- package/crates/enact-core/src/flow/mod.rs +43 -0
- package/crates/enact-core/src/flow/parallel.rs +437 -0
- package/crates/enact-core/src/flow/repeat.rs +534 -0
- package/crates/enact-core/src/flow/sequential.rs +248 -0
- package/crates/enact-core/src/graph/checkpoint.rs +79 -0
- package/crates/enact-core/src/graph/checkpoint_store.rs +76 -0
- package/crates/enact-core/src/graph/compiled.rs +189 -0
- package/crates/enact-core/src/graph/edge.rs +59 -0
- package/crates/enact-core/src/graph/graph_schema.rs +218 -0
- package/crates/enact-core/src/graph/loader.rs +155 -0
- package/crates/enact-core/src/graph/mod.rs +18 -0
- package/crates/enact-core/src/graph/node/function.rs +49 -0
- package/crates/enact-core/src/graph/node/mod.rs +48 -0
- package/crates/enact-core/src/graph/schema.rs +62 -0
- package/crates/enact-core/src/inbox/message.rs +405 -0
- package/crates/enact-core/src/inbox/mod.rs +31 -0
- package/crates/enact-core/src/inbox/store.rs +355 -0
- package/crates/enact-core/src/kernel/artifact/filesystem.rs +546 -0
- package/crates/enact-core/src/kernel/artifact/metadata.rs +283 -0
- package/crates/enact-core/src/kernel/artifact/mod.rs +27 -0
- package/crates/enact-core/src/kernel/artifact/store.rs +427 -0
- package/crates/enact-core/src/kernel/enforcement.rs +1315 -0
- package/crates/enact-core/src/kernel/error.rs +1200 -0
- package/crates/enact-core/src/kernel/event.rs +1394 -0
- package/crates/enact-core/src/kernel/execution_model.rs +831 -0
- package/crates/enact-core/src/kernel/execution_state.rs +189 -0
- package/crates/enact-core/src/kernel/execution_strategy.rs +117 -0
- package/crates/enact-core/src/kernel/ids.rs +2086 -0
- package/crates/enact-core/src/kernel/interrupt.rs +125 -0
- package/crates/enact-core/src/kernel/kernel.rs +1283 -0
- package/crates/enact-core/src/kernel/mod.rs +205 -0
- package/crates/enact-core/src/kernel/persistence/event_store.rs +270 -0
- package/crates/enact-core/src/kernel/persistence/message_store.rs +908 -0
- package/crates/enact-core/src/kernel/persistence/mod.rs +102 -0
- package/crates/enact-core/src/kernel/persistence/state_store.rs +228 -0
- package/crates/enact-core/src/kernel/persistence/vector_store.rs +299 -0
- package/crates/enact-core/src/kernel/reducer.rs +808 -0
- package/crates/enact-core/src/kernel/replay.rs +153 -0
- package/crates/enact-core/src/lib.rs +413 -0
- package/crates/enact-core/src/memory/episodic.rs +0 -0
- package/crates/enact-core/src/memory/mod.rs +6 -0
- package/crates/enact-core/src/memory/semantic.rs +0 -0
- package/crates/enact-core/src/memory/trait.rs +0 -0
- package/crates/enact-core/src/memory/vector_db.rs +0 -0
- package/crates/enact-core/src/memory/working.rs +0 -0
- package/crates/enact-core/src/policy/execution_policy.rs +292 -0
- package/crates/enact-core/src/policy/filters.rs +458 -0
- package/crates/enact-core/src/policy/input_processor.rs +407 -0
- package/crates/enact-core/src/policy/long_running.rs +134 -0
- package/crates/enact-core/src/policy/mod.rs +193 -0
- package/crates/enact-core/src/policy/pii_input.rs +274 -0
- package/crates/enact-core/src/policy/tenant_policy.rs +453 -0
- package/crates/enact-core/src/policy/tool_policy.rs +407 -0
- package/crates/enact-core/src/providers/mod.rs +63 -0
- package/crates/enact-core/src/providers/trait.rs +292 -0
- package/crates/enact-core/src/runner/callbacks.rs +6 -0
- package/crates/enact-core/src/runner/execution_runner.rs +476 -0
- package/crates/enact-core/src/runner/loop.rs +117 -0
- package/crates/enact-core/src/runner/mod.rs +58 -0
- package/crates/enact-core/src/runner/protected_runner.rs +280 -0
- package/crates/enact-core/src/signal/inmemory.rs +231 -0
- package/crates/enact-core/src/signal/mod.rs +108 -0
- package/crates/enact-core/src/streaming/event_logger.rs +195 -0
- package/crates/enact-core/src/streaming/event_stream.rs +1423 -0
- package/crates/enact-core/src/streaming/mod.rs +108 -0
- package/crates/enact-core/src/streaming/pause_cancel.rs +0 -0
- package/crates/enact-core/src/streaming/protected_emitter.rs +173 -0
- package/crates/enact-core/src/streaming/protection/context.rs +136 -0
- package/crates/enact-core/src/streaming/protection/encryption.rs +289 -0
- package/crates/enact-core/src/streaming/protection/mod.rs +43 -0
- package/crates/enact-core/src/streaming/protection/pii_protection.rs +243 -0
- package/crates/enact-core/src/streaming/protection/processor.rs +166 -0
- package/crates/enact-core/src/streaming/sse.rs +0 -0
- package/crates/enact-core/src/telemetry/exporter.rs +0 -0
- package/crates/enact-core/src/telemetry/init.rs +0 -0
- package/crates/enact-core/src/telemetry/mod.rs +49 -0
- package/crates/enact-core/src/telemetry/spans.rs +245 -0
- package/crates/enact-core/src/tool/agent_tool.rs +177 -0
- package/crates/enact-core/src/tool/browser/mod.rs +0 -0
- package/crates/enact-core/src/tool/browser/webdriver.rs +0 -0
- package/crates/enact-core/src/tool/cost.rs +247 -0
- package/crates/enact-core/src/tool/discovery.rs +0 -0
- package/crates/enact-core/src/tool/dispatcher.rs +347 -0
- package/crates/enact-core/src/tool/filesystem.rs +231 -0
- package/crates/enact-core/src/tool/function.rs +99 -0
- package/crates/enact-core/src/tool/git.rs +162 -0
- package/crates/enact-core/src/tool/http.rs +214 -0
- package/crates/enact-core/src/tool/mcp/client.rs +0 -0
- package/crates/enact-core/src/tool/mcp/mod.rs +0 -0
- package/crates/enact-core/src/tool/mod.rs +51 -0
- package/crates/enact-core/src/tool/reasoning/debugging.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mcts.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mod.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/sequential.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/dagger.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/mod.rs +0 -0
- package/crates/enact-core/src/tool/shell.rs +147 -0
- package/crates/enact-core/src/tool/trait.rs +33 -0
- package/crates/enact-core/src/tool/web_search.rs +277 -0
- package/crates/enact-core/src/util/config.rs +0 -0
- package/crates/enact-core/src/util/errors.rs +0 -0
- package/crates/enact-core/src/util/mod.rs +6 -0
- package/crates/enact-core/tests/airgapped_e2e_test.rs +291 -0
- package/crates/enact-core/tests/e2e_agentic_loop.rs +119 -0
- package/crates/enact-core/tests/e2e_test.rs +259 -0
- package/crates/enact-core/tests/graph_test.rs +130 -0
- package/crates/enact-core/tests/stream_event_id_validation.rs +435 -0
- package/crates/enact-cron/Cargo.toml +28 -0
- package/crates/enact-cron/src/lib.rs +44 -0
- package/crates/enact-cron/src/schedule.rs +156 -0
- package/crates/enact-cron/src/store.rs +589 -0
- package/crates/enact-cron/src/types.rs +148 -0
- package/crates/enact-gateway/Cargo.toml +31 -0
- package/crates/enact-gateway/README.md +30 -0
- package/crates/enact-gateway/examples/whatsapp-gateway-runner-mock.rs +59 -0
- package/crates/enact-gateway/examples/whatsapp-gateway.rs +42 -0
- package/crates/enact-gateway/src/lib.rs +582 -0
- package/crates/enact-mcp/Cargo.toml +24 -0
- package/crates/enact-mcp/src/lib.rs +178 -0
- package/crates/enact-memory/Cargo.toml +25 -0
- package/crates/enact-memory/src/backend.rs +20 -0
- package/crates/enact-memory/src/chunker.rs +230 -0
- package/crates/enact-memory/src/embeddings.rs +221 -0
- package/crates/enact-memory/src/lib.rs +67 -0
- package/crates/enact-memory/src/markdown.rs +127 -0
- package/crates/enact-memory/src/none.rs +61 -0
- package/crates/enact-memory/src/sqlite.rs +276 -0
- package/crates/enact-memory/src/traits.rs +65 -0
- package/crates/enact-memory/src/vector.rs +198 -0
- package/crates/enact-oauth/Cargo.toml +27 -0
- package/crates/enact-oauth/src/lib.rs +584 -0
- package/crates/enact-observability/Cargo.toml +22 -0
- package/crates/enact-observability/src/lib.rs +197 -0
- package/crates/enact-providers/Cargo.toml +33 -0
- package/crates/enact-providers/examples/hello-agent.rs +33 -0
- package/crates/enact-providers/src/anthropic.rs +182 -0
- package/crates/enact-providers/src/azure.rs +96 -0
- package/crates/enact-providers/src/bridge.rs +221 -0
- package/crates/enact-providers/src/gemini.rs +227 -0
- package/crates/enact-providers/src/http.rs +78 -0
- package/crates/enact-providers/src/lib.rs +53 -0
- package/crates/enact-providers/src/openai_compatible.rs +167 -0
- package/crates/enact-providers/src/openrouter.rs +33 -0
- package/crates/enact-runner/Cargo.toml +24 -0
- package/crates/enact-runner/README.md +76 -0
- package/crates/enact-runner/src/compaction.rs +225 -0
- package/crates/enact-runner/src/config.rs +118 -0
- package/crates/enact-runner/src/lib.rs +63 -0
- package/crates/enact-runner/src/loop_driver.rs +414 -0
- package/crates/enact-runner/src/parser.rs +421 -0
- package/crates/enact-runner/src/retry.rs +262 -0
- package/crates/enact-runner/tests/integration.rs +278 -0
- package/crates/enact-security/Cargo.toml +22 -0
- package/crates/enact-security/src/audit.rs +375 -0
- package/crates/enact-security/src/lib.rs +37 -0
- package/crates/enact-security/src/policy.rs +406 -0
- package/crates/enact-skills/Cargo.toml +25 -0
- package/crates/enact-skills/src/lib.rs +506 -0
- package/crates/enact-tools/Cargo.toml +22 -0
- package/crates/enact-tools/src/file_read.rs +166 -0
- package/crates/enact-tools/src/file_write.rs +216 -0
- package/crates/enact-tools/src/git_operations.rs +513 -0
- package/crates/enact-tools/src/http_request.rs +417 -0
- package/crates/enact-tools/src/lib.rs +104 -0
- package/crates/enact-tools/src/security.rs +227 -0
- package/crates/enact-tools/src/shell.rs +191 -0
- package/crates/enact-tools/src/traits.rs +159 -0
- package/docs/Makefile +74 -0
- package/docs/config.toml +62 -0
- package/docs/content/_index.md +174 -0
- package/docs/content/a2a/_index.md +431 -0
- package/docs/content/api/_index.md +323 -0
- package/docs/content/channels/_index.md +160 -0
- package/docs/content/channels/teams.md +205 -0
- package/docs/content/channels/telegram.md +182 -0
- package/docs/content/channels/webhook.md +423 -0
- package/docs/content/channels/whatsapp.md +240 -0
- package/docs/content/cli/_index.md +261 -0
- package/docs/content/concepts/_index.md +273 -0
- package/docs/content/configuration/_index.md +241 -0
- package/docs/content/cron/_index.md +248 -0
- package/docs/content/developers/_index.md +278 -0
- package/docs/content/getting-started/_index.md +180 -0
- package/docs/content/installation/_index.md +186 -0
- package/docs/content/installation/uninstall.md +101 -0
- package/docs/content/installation/updating.md +120 -0
- package/docs/content/mcp/_index.md +215 -0
- package/docs/content/memory/_index.md +163 -0
- package/docs/content/oauth/_index.md +515 -0
- package/docs/content/providers/_index.md +206 -0
- package/docs/content/roadmap/_index.md +199 -0
- package/docs/content/security/_index.md +219 -0
- package/docs/content/skills/_index.md +228 -0
- package/docs/content/tools/_index.md +485 -0
- package/docs/content/troubleshooting/_index.md +259 -0
- package/docs/content/yaml-schema/_index.md +294 -0
- package/docs/static/giallo-dark.css +91 -0
- package/docs/static/giallo-light.css +91 -0
- package/docs/themes/tanuki/.github/workflows/deploy.yml +44 -0
- package/docs/themes/tanuki/LICENSE +21 -0
- package/docs/themes/tanuki/README.md +166 -0
- package/docs/themes/tanuki/examples/blog/config.toml +58 -0
- package/docs/themes/tanuki/examples/blog/content/_index.md +4 -0
- package/docs/themes/tanuki/examples/blog/content/about.md +33 -0
- package/docs/themes/tanuki/examples/blog/content/blog/_index.md +7 -0
- package/docs/themes/tanuki/examples/blog/content/blog/api-design-best-practices.md +245 -0
- package/docs/themes/tanuki/examples/blog/content/blog/building-accessible-websites.md +147 -0
- package/docs/themes/tanuki/examples/blog/content/blog/css-grid-vs-flexbox.md +165 -0
- package/docs/themes/tanuki/examples/blog/content/blog/customizing-catppuccin-colors.md +137 -0
- package/docs/themes/tanuki/examples/blog/content/blog/dark-mode-best-practices.md +82 -0
- package/docs/themes/tanuki/examples/blog/content/blog/docker-essentials.md +301 -0
- package/docs/themes/tanuki/examples/blog/content/blog/getting-started-with-zola.md +129 -0
- package/docs/themes/tanuki/examples/blog/content/blog/git-workflow-for-content.md +112 -0
- package/docs/themes/tanuki/examples/blog/content/blog/introduction-to-webassembly.md +183 -0
- package/docs/themes/tanuki/examples/blog/content/blog/modern-javascript-features.md +234 -0
- package/docs/themes/tanuki/examples/blog/content/blog/testing-strategies.md +311 -0
- package/docs/themes/tanuki/examples/blog/content/blog/typography-for-developers.md +104 -0
- package/docs/themes/tanuki/examples/blog/content/blog/welcome-to-tanuki.md +67 -0
- package/docs/themes/tanuki/examples/blog/content/blog/why-static-sites.md +85 -0
- package/docs/themes/tanuki/examples/blog/content/projects.md +64 -0
- package/docs/themes/tanuki/examples/book/config.toml +17 -0
- package/docs/themes/tanuki/examples/book/content/_index.md +12 -0
- package/docs/themes/tanuki/examples/book/content/chapter-1.md +90 -0
- package/docs/themes/tanuki/examples/book/content/chapter-2.md +143 -0
- package/docs/themes/tanuki/examples/book/content/chapter-3.md +217 -0
- package/docs/themes/tanuki/examples/book/content/chapter-4.md +224 -0
- package/docs/themes/tanuki/examples/book/content/chapter-5.md +297 -0
- package/docs/themes/tanuki/examples/book/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/config.toml +28 -0
- package/docs/themes/tanuki/examples/docs/content/_index.md +20 -0
- package/docs/themes/tanuki/examples/docs/content/components.md +156 -0
- package/docs/themes/tanuki/examples/docs/content/configuration.md +94 -0
- package/docs/themes/tanuki/examples/docs/content/customization.md +202 -0
- package/docs/themes/tanuki/examples/docs/content/deployment.md +204 -0
- package/docs/themes/tanuki/examples/docs/content/installation.md +59 -0
- package/docs/themes/tanuki/examples/docs/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/examples/index.html +2104 -0
- package/docs/themes/tanuki/mise.toml +108 -0
- package/docs/themes/tanuki/sass/base/_catppuccin.scss +164 -0
- package/docs/themes/tanuki/sass/base/_fonts.scss +64 -0
- package/docs/themes/tanuki/sass/base/_reset.scss +152 -0
- package/docs/themes/tanuki/sass/base/_typography.scss +523 -0
- package/docs/themes/tanuki/sass/components/_buttons.scss +209 -0
- package/docs/themes/tanuki/sass/components/_code.scss +457 -0
- package/docs/themes/tanuki/sass/components/_landing.scss +633 -0
- package/docs/themes/tanuki/sass/components/_layout.scss +294 -0
- package/docs/themes/tanuki/sass/components/_navigation.scss +1200 -0
- package/docs/themes/tanuki/sass/components/_print.scss +237 -0
- package/docs/themes/tanuki/sass/components/_search.scss +224 -0
- package/docs/themes/tanuki/sass/components/_sidebar.scss +473 -0
- package/docs/themes/tanuki/sass/components/_theme-toggle.scss +186 -0
- package/docs/themes/tanuki/sass/modes/_blog.scss +366 -0
- package/docs/themes/tanuki/sass/modes/_product.scss +875 -0
- package/docs/themes/tanuki/sass/modes/_raskell.scss +1696 -0
- package/docs/themes/tanuki/sass/patterns/_buttons.scss +183 -0
- package/docs/themes/tanuki/sass/patterns/_cards.scss +144 -0
- package/docs/themes/tanuki/sass/patterns/_index.scss +9 -0
- package/docs/themes/tanuki/sass/patterns/_lists.scss +259 -0
- package/docs/themes/tanuki/sass/patterns/_sections.scss +243 -0
- package/docs/themes/tanuki/sass/style.scss +47 -0
- package/docs/themes/tanuki/sass/tokens/_colors.scss +139 -0
- package/docs/themes/tanuki/sass/tokens/_spacing.scss +100 -0
- package/docs/themes/tanuki/sass/tokens/_typography.scss +186 -0
- package/docs/themes/tanuki/screenshot.png +0 -0
- package/docs/themes/tanuki/sentinel.kdl +59 -0
- package/docs/themes/tanuki/static/elasticlunr.min.js +10 -0
- package/docs/themes/tanuki/static/fonts/GEIST-LICENSE.txt +92 -0
- package/docs/themes/tanuki/static/fonts/Geist-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/fonts/GeistMono-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.png +0 -0
- package/docs/themes/tanuki/static/js/anchors.js +18 -0
- package/docs/themes/tanuki/static/js/app.js +274 -0
- package/docs/themes/tanuki/static/js/code.js +394 -0
- package/docs/themes/tanuki/static/js/navigation.js +778 -0
- package/docs/themes/tanuki/static/js/scroll-to-top.js +33 -0
- package/docs/themes/tanuki/static/js/search-raskell.js +240 -0
- package/docs/themes/tanuki/static/js/search.js +215 -0
- package/docs/themes/tanuki/static/js/theme.js +169 -0
- package/docs/themes/tanuki/static/syntax-dark.css +151 -0
- package/docs/themes/tanuki/static/syntax-light.css +151 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm.js +486 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm_bg.wasm +0 -0
- package/docs/themes/tanuki/templates/404.html +52 -0
- package/docs/themes/tanuki/templates/base.html +428 -0
- package/docs/themes/tanuki/templates/blog.html +66 -0
- package/docs/themes/tanuki/templates/home.html +108 -0
- package/docs/themes/tanuki/templates/index.html +178 -0
- package/docs/themes/tanuki/templates/landing.html +168 -0
- package/docs/themes/tanuki/templates/macros/nav.html +128 -0
- package/docs/themes/tanuki/templates/macros/posts.html +101 -0
- package/docs/themes/tanuki/templates/macros/ui.html +159 -0
- package/docs/themes/tanuki/templates/page.html +135 -0
- package/docs/themes/tanuki/templates/partials/footer.html +38 -0
- package/docs/themes/tanuki/templates/partials/header.html +366 -0
- package/docs/themes/tanuki/templates/partials/nav-buttons.html +55 -0
- package/docs/themes/tanuki/templates/partials/nav-overlay.html +81 -0
- package/docs/themes/tanuki/templates/partials/page-toc-panel.html +43 -0
- package/docs/themes/tanuki/templates/partials/search.html +52 -0
- package/docs/themes/tanuki/templates/partials/sidebar.html +107 -0
- package/docs/themes/tanuki/templates/partials/theme-toggle.html +35 -0
- package/docs/themes/tanuki/templates/partials/toc-overlay.html +146 -0
- package/docs/themes/tanuki/templates/partials/version-picker.html +38 -0
- package/docs/themes/tanuki/templates/print.html +244 -0
- package/docs/themes/tanuki/templates/section.html +186 -0
- package/docs/themes/tanuki/templates/taxonomy_list.html +18 -0
- package/docs/themes/tanuki/templates/taxonomy_single.html +31 -0
- package/docs/themes/tanuki/theme.toml +58 -0
- package/examples/hello-agent.rs +55 -0
- package/package.json +36 -0
- package/proto/config.proto +60 -0
- package/proto/events.proto +0 -0
- package/proto/runtime.proto +215 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* theme "github-light" generated by giallo
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.z-code {
|
|
6
|
+
color: #24292E;
|
|
7
|
+
background-color: #FFFFFF;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.z-hl {
|
|
11
|
+
background-color: #F6F8FA;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.giallo-ln {
|
|
15
|
+
color: #1B1F234D;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.z-comment { color: #6A737D; }
|
|
19
|
+
.z-constant { color: #005CC5; }
|
|
20
|
+
.z-entity { color: #6F42C1; }
|
|
21
|
+
.z-keyword { color: #D73A49; }
|
|
22
|
+
.z-storage { color: #D73A49; }
|
|
23
|
+
.z-string { color: #032F62; }
|
|
24
|
+
.z-support { color: #005CC5; }
|
|
25
|
+
.z-variable { color: #E36209; }
|
|
26
|
+
.z-carriage-return { color: #FAFBFC; background-color: #D73A49; font-style: italic;text-decoration: underline; }
|
|
27
|
+
.z-variable { color: #005CC5; }
|
|
28
|
+
.z-source { color: #032F62; }
|
|
29
|
+
.z-string.z-comment { color: #6A737D; }
|
|
30
|
+
.z-variable.z-language { color: #005CC5; }
|
|
31
|
+
.z-entity.z-name { color: #6F42C1; }
|
|
32
|
+
.z-storage.z-type { color: #D73A49; }
|
|
33
|
+
.z-meta.z-property-name { color: #005CC5; }
|
|
34
|
+
.z-variable.z-other { color: #24292E; }
|
|
35
|
+
.z-invalid.z-broken { color: #B31D28; font-style: italic; }
|
|
36
|
+
.z-invalid.z-deprecated { color: #B31D28; font-style: italic; }
|
|
37
|
+
.z-invalid.z-illegal { color: #B31D28; font-style: italic; }
|
|
38
|
+
.z-invalid.z-unimplemented { color: #B31D28; font-style: italic; }
|
|
39
|
+
.z-message.z-error { color: #B31D28; }
|
|
40
|
+
.z-source.z-regexp { color: #032F62; }
|
|
41
|
+
.z-string.z-regexp { color: #032F62; }
|
|
42
|
+
.z-support.z-constant { color: #005CC5; }
|
|
43
|
+
.z-support.z-variable { color: #005CC5; }
|
|
44
|
+
.z-meta.z-module-reference { color: #005CC5; }
|
|
45
|
+
.z-markup.z-heading { color: #005CC5; font-weight: bold; }
|
|
46
|
+
.z-markup.z-quote { color: #22863A; }
|
|
47
|
+
.z-markup.z-italic { color: #24292E; font-style: italic; }
|
|
48
|
+
.z-markup.z-bold { color: #24292E; font-weight: bold; }
|
|
49
|
+
.z-markup.z-underline { text-decoration: underline; }
|
|
50
|
+
.z-markup.z-strikethrough { text-decoration: line-through; }
|
|
51
|
+
.z-markup.z-deleted { color: #B31D28; background-color: #FFEEF0; }
|
|
52
|
+
.z-markup.z-inserted { color: #22863A; background-color: #F0FFF4; }
|
|
53
|
+
.z-markup.z-changed { color: #E36209; background-color: #FFEBDA; }
|
|
54
|
+
.z-markup.z-ignored { color: #F6F8FA; background-color: #005CC5; }
|
|
55
|
+
.z-markup.z-untracked { color: #F6F8FA; background-color: #005CC5; }
|
|
56
|
+
.z-meta.z-separator { color: #005CC5; font-weight: bold; }
|
|
57
|
+
.z-meta.z-output { color: #005CC5; }
|
|
58
|
+
.z-brackethighlighter.z-tag { color: #586069; }
|
|
59
|
+
.z-brackethighlighter.z-curly { color: #586069; }
|
|
60
|
+
.z-brackethighlighter.z-round { color: #586069; }
|
|
61
|
+
.z-brackethighlighter.z-square { color: #586069; }
|
|
62
|
+
.z-brackethighlighter.z-angle { color: #586069; }
|
|
63
|
+
.z-brackethighlighter.z-quote { color: #586069; }
|
|
64
|
+
.z-brackethighlighter.z-unmatched { color: #B31D28; }
|
|
65
|
+
.z-entity.z-name { color: #005CC5; font-weight: bold; }
|
|
66
|
+
.z-punctuation.z-definition.z-comment { color: #6A737D; }
|
|
67
|
+
.z-entity.z-name.z-constant { color: #005CC5; }
|
|
68
|
+
.z-variable.z-other.z-constant { color: #005CC5; }
|
|
69
|
+
.z-variable.z-other.z-enummember { color: #005CC5; }
|
|
70
|
+
.z-variable.z-parameter.z-function { color: #24292E; }
|
|
71
|
+
.z-entity.z-name.z-tag { color: #22863A; }
|
|
72
|
+
.z-storage.z-modifier.z-package { color: #24292E; }
|
|
73
|
+
.z-storage.z-modifier.z-import { color: #24292E; }
|
|
74
|
+
.z-storage.z-type.z-java { color: #24292E; }
|
|
75
|
+
.z-punctuation.z-definition.z-string { color: #032F62; }
|
|
76
|
+
.z-string.z-regexp.z-character-class { color: #032F62; }
|
|
77
|
+
.z-markup.z-inline.z-raw { color: #005CC5; }
|
|
78
|
+
.z-punctuation.z-definition.z-deleted { color: #B31D28; background-color: #FFEEF0; }
|
|
79
|
+
.z-punctuation.z-definition.z-inserted { color: #22863A; background-color: #F0FFF4; }
|
|
80
|
+
.z-punctuation.z-definition.z-changed { color: #E36209; background-color: #FFEBDA; }
|
|
81
|
+
.z-meta.z-diff.z-range { color: #6F42C1; font-weight: bold; }
|
|
82
|
+
.z-meta.z-diff.z-header { color: #005CC5; }
|
|
83
|
+
.z-string.z-other.z-link { color: #032F62; text-decoration: underline; }
|
|
84
|
+
.z-constant.z-character.z-escape { color: #032F62; }
|
|
85
|
+
.z-source.z-ruby.z-embedded { color: #032F62; }
|
|
86
|
+
.z-string.z-regexp.z-arbitrary-repitition { color: #032F62; }
|
|
87
|
+
.z-constant.z-character.z-escape { color: #22863A; font-weight: bold; }
|
|
88
|
+
.z-meta.z-diff.z-header.z-from-file { color: #B31D28; background-color: #FFEEF0; }
|
|
89
|
+
.z-meta.z-diff.z-header.z-to-file { color: #22863A; background-color: #F0FFF4; }
|
|
90
|
+
.z-constant.z-other.z-reference.z-link { color: #032F62; text-decoration: underline; }
|
|
91
|
+
.z-punctuation.z-definition.z-list.z-begin.z-markdown { color: #E36209; }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Deploy to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: "pages"
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Install mise
|
|
25
|
+
uses: jdx/mise-action@v2
|
|
26
|
+
|
|
27
|
+
- name: Build all examples
|
|
28
|
+
run: mise run build
|
|
29
|
+
|
|
30
|
+
- name: Upload artifact
|
|
31
|
+
uses: actions/upload-pages-artifact@v3
|
|
32
|
+
with:
|
|
33
|
+
path: ./public
|
|
34
|
+
|
|
35
|
+
deploy:
|
|
36
|
+
environment:
|
|
37
|
+
name: github-pages
|
|
38
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
needs: build
|
|
41
|
+
steps:
|
|
42
|
+
- name: Deploy to GitHub Pages
|
|
43
|
+
id: deployment
|
|
44
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Raffael Schneider / raskell.io
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<h1 align="center">
|
|
4
|
+
<img src="static/img/tanuki-icon.png" alt="tanuki mascot" width="96" />
|
|
5
|
+
<br>
|
|
6
|
+
Tanuki
|
|
7
|
+
</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<em>An opinionated Zola theme for documentation, books, and blogs.</em><br>
|
|
11
|
+
<em>Beautiful, accessible, and thoughtfully designed.</em>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://www.getzola.org/">
|
|
16
|
+
<img alt="Zola" src="https://img.shields.io/badge/Zola-0.19+-000000?logo=zola&logoColor=white&style=for-the-badge">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://catppuccin.com/">
|
|
19
|
+
<img alt="Catppuccin" src="https://img.shields.io/badge/Catppuccin-cba6f7?style=for-the-badge">
|
|
20
|
+
</a>
|
|
21
|
+
<a href="LICENSE">
|
|
22
|
+
<img alt="License" src="https://img.shields.io/badge/License-MIT-a6e3a1?style=for-the-badge">
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<a href="https://tanuki.raskell.io">Live Demo</a> ā¢
|
|
28
|
+
<a href="https://tanuki.raskell.io/docs/">Documentation</a> ā¢
|
|
29
|
+
<a href="https://tanuki.raskell.io/book/">Book Example</a> ā¢
|
|
30
|
+
<a href="https://tanuki.raskell.io/blog/">Blog Example</a>
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
<hr />
|
|
34
|
+
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **Three Modes** ā Documentation (with versioning), Book, and Blog layouts
|
|
42
|
+
- **Catppuccin Colors** ā Soothing Mocha (dark) and Latte (light) palettes
|
|
43
|
+
- **Geist Typography** ā Clean, readable variable fonts
|
|
44
|
+
- **Lucide Icons** ā Crisp, consistent iconography
|
|
45
|
+
- **Resizable Sidebar** ā Drag to resize, persists across sessions
|
|
46
|
+
- **Full-text Search** ā Elasticlunr-powered instant search
|
|
47
|
+
- **Dark/Light Toggle** ā Three-way toggle with system preference detection
|
|
48
|
+
- **Print Support** ā Print all pages as a single document (docs/book modes)
|
|
49
|
+
- **Keyboard Navigation** ā Arrow keys for prev/next, `/` for search
|
|
50
|
+
- **SEO & Accessibility** ā JSON-LD structured data, ARIA landmarks, semantic HTML
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cd your-zola-site
|
|
56
|
+
git clone https://github.com/raskell-io/tanuki themes/tanuki
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or as a git submodule:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git submodule add https://github.com/raskell-io/tanuki themes/tanuki
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
### Documentation Mode
|
|
68
|
+
|
|
69
|
+
```toml
|
|
70
|
+
base_url = "https://docs.example.com"
|
|
71
|
+
title = "My Project Docs"
|
|
72
|
+
theme = "tanuki"
|
|
73
|
+
build_search_index = true
|
|
74
|
+
|
|
75
|
+
[markdown]
|
|
76
|
+
highlight_code = true
|
|
77
|
+
highlight_theme = "css"
|
|
78
|
+
|
|
79
|
+
[extra]
|
|
80
|
+
mode = "docs"
|
|
81
|
+
github = "https://github.com/you/project"
|
|
82
|
+
|
|
83
|
+
# Optional: version picker
|
|
84
|
+
[extra.versions]
|
|
85
|
+
current = "2.0.0"
|
|
86
|
+
list = [
|
|
87
|
+
{ version = "2.0.0", url = "/", label = "latest" },
|
|
88
|
+
{ version = "1.0.0", url = "/v1/" },
|
|
89
|
+
]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Book Mode
|
|
93
|
+
|
|
94
|
+
```toml
|
|
95
|
+
base_url = "https://book.example.com"
|
|
96
|
+
title = "The Complete Guide"
|
|
97
|
+
theme = "tanuki"
|
|
98
|
+
build_search_index = true
|
|
99
|
+
|
|
100
|
+
[markdown]
|
|
101
|
+
highlight_code = true
|
|
102
|
+
highlight_theme = "css"
|
|
103
|
+
|
|
104
|
+
[extra]
|
|
105
|
+
mode = "book"
|
|
106
|
+
github = "https://github.com/you/book"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Blog Mode
|
|
110
|
+
|
|
111
|
+
```toml
|
|
112
|
+
base_url = "https://blog.example.com"
|
|
113
|
+
title = "My Blog"
|
|
114
|
+
theme = "tanuki"
|
|
115
|
+
generate_feeds = true
|
|
116
|
+
|
|
117
|
+
taxonomies = [
|
|
118
|
+
{ name = "tags", feed = true },
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
[markdown]
|
|
122
|
+
highlight_code = true
|
|
123
|
+
highlight_theme = "css"
|
|
124
|
+
|
|
125
|
+
[extra]
|
|
126
|
+
mode = "blog"
|
|
127
|
+
|
|
128
|
+
[extra.hero]
|
|
129
|
+
title = "Welcome to my blog"
|
|
130
|
+
subtitle = "Thoughts on code and craft"
|
|
131
|
+
|
|
132
|
+
[[extra.nav]]
|
|
133
|
+
name = "Blog"
|
|
134
|
+
url = "/blog/"
|
|
135
|
+
|
|
136
|
+
[[extra.nav]]
|
|
137
|
+
name = "About"
|
|
138
|
+
url = "/about/"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Keyboard Shortcuts
|
|
142
|
+
|
|
143
|
+
| Key | Action |
|
|
144
|
+
|-----|--------|
|
|
145
|
+
| `ā` / `ā` | Previous / Next page |
|
|
146
|
+
| `/` | Open search |
|
|
147
|
+
| `Esc` | Close overlays |
|
|
148
|
+
|
|
149
|
+
## Browser Support
|
|
150
|
+
|
|
151
|
+
Modern browsers (Chrome 88+, Firefox 78+, Safari 14+, Edge 88+)
|
|
152
|
+
|
|
153
|
+
## Credits
|
|
154
|
+
|
|
155
|
+
- [Catppuccin](https://catppuccin.com) ā Color palette
|
|
156
|
+
- [Geist](https://vercel.com/font) ā Typography
|
|
157
|
+
- [Lucide](https://lucide.dev) ā Icons
|
|
158
|
+
- [Zola](https://www.getzola.org) ā Static site generator
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
[MIT](LICENSE)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
<p align="center">Made with care by <a href="https://raskell.io">raskell.io</a></p>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Tanuki Theme - Blog/Personal Site Example
|
|
2
|
+
base_url = "/tanuki/blog"
|
|
3
|
+
title = "Alex Chen"
|
|
4
|
+
description = "Software developer writing about web technologies, design, and the craft of building things."
|
|
5
|
+
theme = "tanuki"
|
|
6
|
+
compile_sass = true
|
|
7
|
+
build_search_index = true
|
|
8
|
+
generate_feeds = true
|
|
9
|
+
feed_filenames = ["rss.xml"]
|
|
10
|
+
|
|
11
|
+
taxonomies = [
|
|
12
|
+
{ name = "tags", feed = true },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[markdown]
|
|
16
|
+
highlight_code = true
|
|
17
|
+
highlight_theme = "base16-ocean-dark"
|
|
18
|
+
|
|
19
|
+
[extra]
|
|
20
|
+
mode = "blog"
|
|
21
|
+
show_theme_toggle = true
|
|
22
|
+
show_about_section = true
|
|
23
|
+
|
|
24
|
+
# Author info
|
|
25
|
+
[extra.author]
|
|
26
|
+
name = "Alex Chen"
|
|
27
|
+
bio = "Software developer and open source enthusiast."
|
|
28
|
+
# avatar = "images/avatar.jpg"
|
|
29
|
+
|
|
30
|
+
# Hero section
|
|
31
|
+
[extra.hero]
|
|
32
|
+
title = "Hey, I'm Alex"
|
|
33
|
+
subtitle = "I build things for the web and write about what I learn along the way."
|
|
34
|
+
[extra.hero.cta]
|
|
35
|
+
text = "Read the blog"
|
|
36
|
+
url = "/tanuki/blog/blog/"
|
|
37
|
+
|
|
38
|
+
# About preview on homepage
|
|
39
|
+
[extra.about]
|
|
40
|
+
summary = "I'm a software developer passionate about web technologies, developer experience, and building tools that make other developers' lives easier."
|
|
41
|
+
|
|
42
|
+
# Social links
|
|
43
|
+
[extra.social]
|
|
44
|
+
github = "https://github.com/username"
|
|
45
|
+
twitter = "https://twitter.com/username"
|
|
46
|
+
|
|
47
|
+
# Navigation
|
|
48
|
+
[[extra.nav]]
|
|
49
|
+
name = "Blog"
|
|
50
|
+
url = "/tanuki/blog/blog/"
|
|
51
|
+
|
|
52
|
+
[[extra.nav]]
|
|
53
|
+
name = "Projects"
|
|
54
|
+
url = "/tanuki/blog/projects/"
|
|
55
|
+
|
|
56
|
+
[[extra.nav]]
|
|
57
|
+
name = "About"
|
|
58
|
+
url = "/tanuki/blog/about/"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "About"
|
|
3
|
+
description = "A little bit about me and what I do."
|
|
4
|
+
template = "page.html"
|
|
5
|
+
path = "about"
|
|
6
|
+
+++
|
|
7
|
+
|
|
8
|
+
# About Me
|
|
9
|
+
|
|
10
|
+
Hey there! I'm a software developer passionate about building things for the web. I spend most of my time writing code, learning new technologies, and occasionally writing about what I've learned.
|
|
11
|
+
|
|
12
|
+
## What I Do
|
|
13
|
+
|
|
14
|
+
By day, I work on web applicationsāeverything from frontend interfaces to backend APIs. I particularly enjoy:
|
|
15
|
+
|
|
16
|
+
- **Frontend Development**: React, Vue, and modern CSS
|
|
17
|
+
- **Backend Systems**: Node.js, Rust, and databases
|
|
18
|
+
- **Developer Experience**: Tooling, automation, and workflows
|
|
19
|
+
- **Open Source**: Contributing to and maintaining projects
|
|
20
|
+
|
|
21
|
+
## This Site
|
|
22
|
+
|
|
23
|
+
This site is built with [Zola](https://www.getzola.org/) and the Tanuki theme. It's where I share articles about web development, design patterns, and lessons learned along the way.
|
|
24
|
+
|
|
25
|
+
The source code is available on [GitHub](https://github.com/example/blog) if you're curious about how it's built.
|
|
26
|
+
|
|
27
|
+
## Get in Touch
|
|
28
|
+
|
|
29
|
+
- **GitHub**: [@username](https://github.com/username)
|
|
30
|
+
- **Twitter**: [@username](https://twitter.com/username)
|
|
31
|
+
- **Email**: hello@example.com
|
|
32
|
+
|
|
33
|
+
Feel free to reach out if you want to chat about tech, have questions about my articles, or just want to say hi.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "REST API Design Best Practices"
|
|
3
|
+
description = "Good API design makes the difference between a joy to use and a nightmare to integrate. Here's how to get it right."
|
|
4
|
+
date = 2024-12-22
|
|
5
|
+
[taxonomies]
|
|
6
|
+
tags = ["api", "rest", "backend"]
|
|
7
|
+
+++
|
|
8
|
+
|
|
9
|
+
# REST API Design Best Practices
|
|
10
|
+
|
|
11
|
+
Your API is a contract. Make it one developers actually want to sign.
|
|
12
|
+
|
|
13
|
+
## Use Nouns, Not Verbs
|
|
14
|
+
|
|
15
|
+
The HTTP method is the verb. The URL is the noun.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
# Bad
|
|
19
|
+
GET /getUsers
|
|
20
|
+
POST /createUser
|
|
21
|
+
DELETE /deleteUser/123
|
|
22
|
+
|
|
23
|
+
# Good
|
|
24
|
+
GET /users
|
|
25
|
+
POST /users
|
|
26
|
+
DELETE /users/123
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Use Plural Resource Names
|
|
30
|
+
|
|
31
|
+
Consistency matters more than grammar debates:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
GET /users # List users
|
|
35
|
+
GET /users/123 # Get one user
|
|
36
|
+
POST /users # Create user
|
|
37
|
+
PUT /users/123 # Update user
|
|
38
|
+
DELETE /users/123 # Delete user
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Nest Related Resources
|
|
42
|
+
|
|
43
|
+
Show relationships through URL structure:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
GET /users/123/posts # Posts by user 123
|
|
47
|
+
GET /posts/456/comments # Comments on post 456
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
But don't nest too deeply:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
# Too deep
|
|
54
|
+
GET /users/123/posts/456/comments/789/likes
|
|
55
|
+
|
|
56
|
+
# Better: use query params or separate endpoint
|
|
57
|
+
GET /likes?comment=789
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## HTTP Status Codes
|
|
61
|
+
|
|
62
|
+
Use them correctly:
|
|
63
|
+
|
|
64
|
+
| Code | Meaning | When to Use |
|
|
65
|
+
|------|---------|-------------|
|
|
66
|
+
| 200 | OK | Successful GET, PUT, PATCH |
|
|
67
|
+
| 201 | Created | Successful POST |
|
|
68
|
+
| 204 | No Content | Successful DELETE |
|
|
69
|
+
| 400 | Bad Request | Invalid syntax, validation errors |
|
|
70
|
+
| 401 | Unauthorized | Missing/invalid authentication |
|
|
71
|
+
| 403 | Forbidden | Authenticated but not allowed |
|
|
72
|
+
| 404 | Not Found | Resource doesn't exist |
|
|
73
|
+
| 409 | Conflict | Duplicate resource, version conflict |
|
|
74
|
+
| 422 | Unprocessable | Valid syntax but semantic errors |
|
|
75
|
+
| 429 | Too Many Requests | Rate limit exceeded |
|
|
76
|
+
| 500 | Server Error | Something broke |
|
|
77
|
+
|
|
78
|
+
## Consistent Error Format
|
|
79
|
+
|
|
80
|
+
Always return errors in the same shape:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"error": {
|
|
85
|
+
"code": "VALIDATION_ERROR",
|
|
86
|
+
"message": "Invalid input data",
|
|
87
|
+
"details": [
|
|
88
|
+
{
|
|
89
|
+
"field": "email",
|
|
90
|
+
"message": "Must be a valid email address"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"field": "age",
|
|
94
|
+
"message": "Must be at least 18"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Pagination
|
|
102
|
+
|
|
103
|
+
For any list endpoint, support pagination:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
GET /posts?page=2&limit=20
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Return pagination metadata:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"data": [...],
|
|
114
|
+
"pagination": {
|
|
115
|
+
"page": 2,
|
|
116
|
+
"limit": 20,
|
|
117
|
+
"total": 156,
|
|
118
|
+
"pages": 8
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or use cursor-based pagination for large datasets:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
GET /posts?cursor=eyJpZCI6MTAwfQ&limit=20
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Filtering and Sorting
|
|
130
|
+
|
|
131
|
+
Use query parameters:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
GET /posts?status=published&author=123
|
|
135
|
+
GET /posts?sort=-created_at,title
|
|
136
|
+
GET /posts?created_after=2024-01-01
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The `-` prefix indicates descending order.
|
|
140
|
+
|
|
141
|
+
## Partial Responses
|
|
142
|
+
|
|
143
|
+
Let clients request only what they need:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
GET /users/123?fields=id,name,email
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Response:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"id": 123,
|
|
154
|
+
"name": "Jane Doe",
|
|
155
|
+
"email": "jane@example.com"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Versioning
|
|
160
|
+
|
|
161
|
+
Version your API from day one:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
# URL path (most common)
|
|
165
|
+
GET /v1/users
|
|
166
|
+
|
|
167
|
+
# Header
|
|
168
|
+
GET /users
|
|
169
|
+
Accept: application/vnd.api+json;version=1
|
|
170
|
+
|
|
171
|
+
# Query param (least preferred)
|
|
172
|
+
GET /users?version=1
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Rate Limiting Headers
|
|
176
|
+
|
|
177
|
+
Tell clients their limits:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
X-RateLimit-Limit: 1000
|
|
181
|
+
X-RateLimit-Remaining: 999
|
|
182
|
+
X-RateLimit-Reset: 1640995200
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## HATEOAS (Hypermedia)
|
|
186
|
+
|
|
187
|
+
Include links for discoverability:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"id": 123,
|
|
192
|
+
"title": "API Design",
|
|
193
|
+
"links": {
|
|
194
|
+
"self": "/posts/123",
|
|
195
|
+
"author": "/users/456",
|
|
196
|
+
"comments": "/posts/123/comments"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Idempotency
|
|
202
|
+
|
|
203
|
+
Make operations safe to retry:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
# Idempotent (safe to retry)
|
|
207
|
+
GET /users/123
|
|
208
|
+
PUT /users/123 # Full replacement
|
|
209
|
+
DELETE /users/123
|
|
210
|
+
|
|
211
|
+
# Not idempotent
|
|
212
|
+
POST /users # Creates new each time
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
For non-idempotent operations, accept an idempotency key:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
POST /payments
|
|
219
|
+
Idempotency-Key: abc123
|
|
220
|
+
|
|
221
|
+
# Retrying with same key returns cached response
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Documentation
|
|
225
|
+
|
|
226
|
+
Good APIs have good docs:
|
|
227
|
+
|
|
228
|
+
- **OpenAPI/Swagger**: Machine-readable spec
|
|
229
|
+
- **Examples**: Show request/response pairs
|
|
230
|
+
- **Authentication**: Clear setup instructions
|
|
231
|
+
- **Errors**: Document all error codes
|
|
232
|
+
- **Changelog**: Track breaking changes
|
|
233
|
+
|
|
234
|
+
## Quick Checklist
|
|
235
|
+
|
|
236
|
+
- [ ] Consistent naming conventions
|
|
237
|
+
- [ ] Proper HTTP status codes
|
|
238
|
+
- [ ] Structured error responses
|
|
239
|
+
- [ ] Pagination for lists
|
|
240
|
+
- [ ] Rate limiting
|
|
241
|
+
- [ ] API versioning
|
|
242
|
+
- [ ] Authentication documented
|
|
243
|
+
- [ ] OpenAPI specification
|
|
244
|
+
|
|
245
|
+
Good API design is invisibleādevelopers just get things working without friction.
|