@xonovex/skills 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/.claude-plugin/plugin.json +21 -0
- package/commands/code-align.md +108 -0
- package/commands/code-harden.md +74 -0
- package/commands/code-simplify.md +145 -0
- package/commands/git-commit.md +146 -0
- package/commands/insights-extract.md +109 -0
- package/commands/insights-integrate.md +100 -0
- package/commands/plan-continue.md +167 -0
- package/commands/plan-create.md +107 -0
- package/commands/plan-research.md +113 -0
- package/commands/plan-subplans-create.md +111 -0
- package/commands/plan-tdd-create.md +128 -0
- package/commands/plan-update.md +99 -0
- package/commands/plan-validate.md +100 -0
- package/commands/plan-worktree-abandon.md +104 -0
- package/commands/plan-worktree-create.md +92 -0
- package/commands/plan-worktree-merge.md +132 -0
- package/package.json +44 -0
- package/skills/astro-guidelines/SKILL.md +23 -0
- package/skills/astro-guidelines/reference/accessibility.md +31 -0
- package/skills/astro-guidelines/reference/components.md +42 -0
- package/skills/astro-guidelines/reference/content-collections.md +32 -0
- package/skills/astro-guidelines/reference/islands-architecture.md +26 -0
- package/skills/astro-guidelines/reference/project-structure.md +32 -0
- package/skills/c99-game-opinionated-guidelines/SKILL.md +43 -0
- package/skills/c99-game-opinionated-guidelines/reference/builder-pattern.md +29 -0
- package/skills/c99-game-opinionated-guidelines/reference/coordinate-system.md +27 -0
- package/skills/c99-game-opinionated-guidelines/reference/geometry-pipeline.md +29 -0
- package/skills/c99-game-opinionated-guidelines/reference/math-types.md +31 -0
- package/skills/c99-game-opinionated-guidelines/reference/mesh-types.md +32 -0
- package/skills/c99-game-opinionated-guidelines/reference/physics-patterns.md +28 -0
- package/skills/c99-game-opinionated-guidelines/reference/spatial-structures.md +26 -0
- package/skills/c99-game-opinionated-guidelines/reference/tagged-unions.md +40 -0
- package/skills/c99-game-opinionated-guidelines/reference/vertex-packing.md +38 -0
- package/skills/c99-guidelines/SKILL.md +29 -0
- package/skills/c99-guidelines/reference/compound-literals.md +33 -0
- package/skills/c99-guidelines/reference/const-correctness.md +32 -0
- package/skills/c99-guidelines/reference/designated-initializers.md +32 -0
- package/skills/c99-guidelines/reference/error-handling.md +49 -0
- package/skills/c99-guidelines/reference/inline-functions.md +37 -0
- package/skills/c99-guidelines/reference/memory-management.md +35 -0
- package/skills/c99-opinionated-guidelines/SKILL.md +44 -0
- package/skills/c99-opinionated-guidelines/reference/alignment.md +50 -0
- package/skills/c99-opinionated-guidelines/reference/caller-owns-memory.md +38 -0
- package/skills/c99-opinionated-guidelines/reference/compound-literals.md +33 -0
- package/skills/c99-opinionated-guidelines/reference/const-correctness.md +32 -0
- package/skills/c99-opinionated-guidelines/reference/data-oriented-design.md +42 -0
- package/skills/c99-opinionated-guidelines/reference/designated-initializers.md +32 -0
- package/skills/c99-opinionated-guidelines/reference/error-handling.md +49 -0
- package/skills/c99-opinionated-guidelines/reference/file-naming.md +33 -0
- package/skills/c99-opinionated-guidelines/reference/implementation-variants.md +35 -0
- package/skills/c99-opinionated-guidelines/reference/inline-functions.md +37 -0
- package/skills/c99-opinionated-guidelines/reference/memory-management.md +35 -0
- package/skills/c99-opinionated-guidelines/reference/safety-validations.md +32 -0
- package/skills/c99-opinionated-guidelines/reference/testing-patterns.md +39 -0
- package/skills/cmake-guidelines/SKILL.md +31 -0
- package/skills/cmake-guidelines/reference/compile-options.md +34 -0
- package/skills/cmake-guidelines/reference/fetchcontent.md +32 -0
- package/skills/cmake-guidelines/reference/find-package.md +29 -0
- package/skills/cmake-guidelines/reference/generator-expressions.md +34 -0
- package/skills/cmake-guidelines/reference/installation.md +38 -0
- package/skills/cmake-guidelines/reference/project-structure.md +40 -0
- package/skills/cmake-guidelines/reference/target-types.md +37 -0
- package/skills/cmake-guidelines/reference/testing.md +30 -0
- package/skills/cmake-guidelines/reference/visibility-specifiers.md +32 -0
- package/skills/content-guidelines/SKILL.md +36 -0
- package/skills/content-guidelines/reference/humanize.md +30 -0
- package/skills/content-guidelines/reference/news.md +28 -0
- package/skills/content-guidelines/reference/travelguide.md +31 -0
- package/skills/docker-guidelines/SKILL.md +23 -0
- package/skills/docker-guidelines/reference/docker-compose.md +40 -0
- package/skills/docker-guidelines/reference/layer-caching.md +25 -0
- package/skills/docker-guidelines/reference/multi-stage-builds.md +37 -0
- package/skills/docker-guidelines/reference/production-config.md +32 -0
- package/skills/docker-guidelines/reference/security.md +27 -0
- package/skills/express.js-guidelines/SKILL.md +32 -0
- package/skills/express.js-guidelines/reference/app-setup.md +39 -0
- package/skills/express.js-guidelines/reference/authentication.md +39 -0
- package/skills/express.js-guidelines/reference/controllers.md +49 -0
- package/skills/express.js-guidelines/reference/error-handling.md +54 -0
- package/skills/express.js-guidelines/reference/project-structure.md +29 -0
- package/skills/express.js-guidelines/reference/responses.md +30 -0
- package/skills/express.js-guidelines/reference/routes.md +29 -0
- package/skills/express.js-guidelines/reference/testing.md +39 -0
- package/skills/express.js-guidelines/reference/validation.md +41 -0
- package/skills/general-fp-guidelines/SKILL.md +28 -0
- package/skills/general-oop-guidelines/SKILL.md +28 -0
- package/skills/git-guidelines/SKILL.md +46 -0
- package/skills/git-guidelines/reference/commit.md +32 -0
- package/skills/git-guidelines/reference/merge-resolve.md +38 -0
- package/skills/git-guidelines/reference/worktree-abandon.md +48 -0
- package/skills/git-guidelines/reference/worktree-cleanup.md +40 -0
- package/skills/git-guidelines/reference/worktree-commit.md +46 -0
- package/skills/git-guidelines/reference/worktree-create.md +42 -0
- package/skills/git-guidelines/reference/worktree-merge.md +45 -0
- package/skills/git-guidelines/reference/worktree-validate.md +44 -0
- package/skills/hono-guidelines/SKILL.md +49 -0
- package/skills/hono-guidelines/reference/application-structure.md +53 -0
- package/skills/hono-guidelines/reference/context-storage.md +46 -0
- package/skills/hono-guidelines/reference/cookie-handling.md +63 -0
- package/skills/hono-guidelines/reference/error-handling.md +69 -0
- package/skills/hono-guidelines/reference/middleware-combine.md +47 -0
- package/skills/hono-guidelines/reference/middleware-patterns.md +58 -0
- package/skills/hono-guidelines/reference/platform-runtime.md +41 -0
- package/skills/hono-guidelines/reference/security-middleware.md +60 -0
- package/skills/hono-guidelines/reference/validation-type-safety.md +43 -0
- package/skills/hono-guidelines/reference/websocket-support.md +59 -0
- package/skills/hono-opinionated-guidelines/SKILL.md +49 -0
- package/skills/hono-opinionated-guidelines/reference/application-structure.md +53 -0
- package/skills/hono-opinionated-guidelines/reference/body-limit.md +57 -0
- package/skills/hono-opinionated-guidelines/reference/context-storage.md +46 -0
- package/skills/hono-opinionated-guidelines/reference/controllers.md +38 -0
- package/skills/hono-opinionated-guidelines/reference/cookie-handling.md +63 -0
- package/skills/hono-opinionated-guidelines/reference/error-handling.md +69 -0
- package/skills/hono-opinionated-guidelines/reference/middleware-combine.md +47 -0
- package/skills/hono-opinionated-guidelines/reference/middleware-patterns.md +58 -0
- package/skills/hono-opinionated-guidelines/reference/openapi-explicit-status-codes.md +61 -0
- package/skills/hono-opinionated-guidelines/reference/openapi-inline-handlers.md +56 -0
- package/skills/hono-opinionated-guidelines/reference/openapi-router-hierarchy.md +64 -0
- package/skills/hono-opinionated-guidelines/reference/openapi-spec-generation.md +57 -0
- package/skills/hono-opinionated-guidelines/reference/platform-runtime.md +41 -0
- package/skills/hono-opinionated-guidelines/reference/router-selection.md +34 -0
- package/skills/hono-opinionated-guidelines/reference/security-middleware.md +60 -0
- package/skills/hono-opinionated-guidelines/reference/validation-type-safety.md +43 -0
- package/skills/hono-opinionated-guidelines/reference/websocket-support.md +59 -0
- package/skills/insights-guidelines/SKILL.md +28 -0
- package/skills/insights-guidelines/reference/insights-extract.md +31 -0
- package/skills/insights-guidelines/reference/insights-integrate.md +35 -0
- package/skills/instruction-guidelines/SKILL.md +26 -0
- package/skills/instruction-guidelines/reference/assimilate.md +38 -0
- package/skills/instruction-guidelines/reference/simplify.md +46 -0
- package/skills/instruction-guidelines/reference/sync.md +41 -0
- package/skills/kubernetes-guidelines/SKILL.md +28 -0
- package/skills/kubernetes-guidelines/reference/configmaps-secrets.md +34 -0
- package/skills/kubernetes-guidelines/reference/deployments.md +55 -0
- package/skills/kubernetes-guidelines/reference/kustomize.md +41 -0
- package/skills/kubernetes-guidelines/reference/network-policies.md +53 -0
- package/skills/kubernetes-guidelines/reference/services.md +36 -0
- package/skills/kubernetes-guidelines/reference/validation.md +32 -0
- package/skills/lua-guidelines/SKILL.md +29 -0
- package/skills/lua-guidelines/reference/coroutines.md +66 -0
- package/skills/lua-guidelines/reference/error-handling.md +41 -0
- package/skills/lua-guidelines/reference/idiomatic-patterns.md +40 -0
- package/skills/lua-guidelines/reference/input-validation.md +42 -0
- package/skills/lua-guidelines/reference/local-variables.md +33 -0
- package/skills/lua-guidelines/reference/metatables.md +52 -0
- package/skills/lua-guidelines/reference/module-pattern.md +37 -0
- package/skills/lua-guidelines/reference/string-concatenation.md +31 -0
- package/skills/lua-opinionated-guidelines/SKILL.md +32 -0
- package/skills/lua-opinionated-guidelines/reference/cache-lookups.md +43 -0
- package/skills/lua-opinionated-guidelines/reference/coroutines.md +66 -0
- package/skills/lua-opinionated-guidelines/reference/error-handling.md +41 -0
- package/skills/lua-opinionated-guidelines/reference/idiomatic-patterns.md +40 -0
- package/skills/lua-opinionated-guidelines/reference/input-validation.md +42 -0
- package/skills/lua-opinionated-guidelines/reference/jit-friendly-tables.md +57 -0
- package/skills/lua-opinionated-guidelines/reference/local-variables.md +33 -0
- package/skills/lua-opinionated-guidelines/reference/metatables.md +52 -0
- package/skills/lua-opinionated-guidelines/reference/module-pattern.md +37 -0
- package/skills/lua-opinionated-guidelines/reference/string-concatenation.md +31 -0
- package/skills/moon-guidelines/SKILL.md +30 -0
- package/skills/moon-guidelines/reference/docker-multistage.md +42 -0
- package/skills/moon-guidelines/reference/project-constraints.md +25 -0
- package/skills/moon-guidelines/reference/query-language.md +27 -0
- package/skills/moon-guidelines/reference/tag-based-filtering.md +28 -0
- package/skills/moon-guidelines/reference/task-configuration.md +38 -0
- package/skills/moon-guidelines/reference/task-inheritance.md +30 -0
- package/skills/motion-react-guidelines/SKILL.md +66 -0
- package/skills/motion-react-guidelines/reference/3d-effects.md +35 -0
- package/skills/motion-react-guidelines/reference/entrance.md +36 -0
- package/skills/motion-react-guidelines/reference/exit.md +35 -0
- package/skills/motion-react-guidelines/reference/gestures.md +23 -0
- package/skills/motion-react-guidelines/reference/layout.md +39 -0
- package/skills/motion-react-guidelines/reference/motion-values.md +33 -0
- package/skills/motion-react-guidelines/reference/performance.md +32 -0
- package/skills/motion-react-guidelines/reference/scroll.md +38 -0
- package/skills/motion-react-guidelines/reference/spring-physics.md +40 -0
- package/skills/motion-react-guidelines/reference/stagger.md +34 -0
- package/skills/motion-react-guidelines/reference/svg-path.md +33 -0
- package/skills/motion-react-guidelines/reference/text-effects.md +39 -0
- package/skills/plan-guidelines/SKILL.md +56 -0
- package/skills/plan-guidelines/reference/code-align.md +23 -0
- package/skills/plan-guidelines/reference/code-barrels-remove.md +24 -0
- package/skills/plan-guidelines/reference/code-comments-remove.md +28 -0
- package/skills/plan-guidelines/reference/code-harden.md +30 -0
- package/skills/plan-guidelines/reference/code-shared-extract.md +25 -0
- package/skills/plan-guidelines/reference/code-simplify.md +33 -0
- package/skills/plan-guidelines/reference/code-template-extract.md +34 -0
- package/skills/plan-guidelines/reference/code-template-scaffold.md +36 -0
- package/skills/plan-guidelines/reference/general-research.md +35 -0
- package/skills/plan-guidelines/reference/plan-create.md +37 -0
- package/skills/plan-guidelines/reference/plan-tdd-create.md +44 -0
- package/skills/plan-guidelines/reference/todos.md +39 -0
- package/skills/presentation-guidelines/SKILL.md +25 -0
- package/skills/presentation-guidelines/reference/presentation-create.md +41 -0
- package/skills/presentation-guidelines/reference/presentation-motion-scaffold.md +38 -0
- package/skills/python-guidelines/SKILL.md +32 -0
- package/skills/python-guidelines/reference/async-await-patterns.md +62 -0
- package/skills/python-guidelines/reference/caching-functions.md +47 -0
- package/skills/python-guidelines/reference/dataclasses-type-hints.md +63 -0
- package/skills/python-guidelines/reference/exception-handling.md +72 -0
- package/skills/python-guidelines/reference/generators-comprehensions.md +54 -0
- package/skills/python-guidelines/reference/pathlib-file-ops.md +60 -0
- package/skills/python-guidelines/reference/resource-management.md +58 -0
- package/skills/python-guidelines/reference/string-formatting.md +41 -0
- package/skills/python-guidelines/reference/type-checking.md +47 -0
- package/skills/react-guidelines/SKILL.md +105 -0
- package/skills/react-guidelines/reference/accessibility.md +31 -0
- package/skills/react-guidelines/reference/activity-effect-event.md +42 -0
- package/skills/react-guidelines/reference/component-design.md +57 -0
- package/skills/react-guidelines/reference/hooks.md +39 -0
- package/skills/react-guidelines/reference/migration-anti-patterns.md +33 -0
- package/skills/react-guidelines/reference/migration-deprecations.md +109 -0
- package/skills/react-guidelines/reference/migration-paradigm-shifts.md +33 -0
- package/skills/react-guidelines/reference/migration-typescript.md +95 -0
- package/skills/react-guidelines/reference/new-hooks.md +94 -0
- package/skills/react-guidelines/reference/performance-optimization.md +41 -0
- package/skills/react-guidelines/reference/react-compiler.md +34 -0
- package/skills/react-guidelines/reference/server-components.md +99 -0
- package/skills/react-guidelines/reference/state-management.md +72 -0
- package/skills/react-guidelines/reference/suspense-streaming.md +36 -0
- package/skills/remotion-guidelines/SKILL.md +67 -0
- package/skills/remotion-guidelines/reference/animations.md +121 -0
- package/skills/remotion-guidelines/reference/assets.md +21 -0
- package/skills/remotion-guidelines/reference/captions.md +33 -0
- package/skills/remotion-guidelines/reference/charts.md +35 -0
- package/skills/remotion-guidelines/reference/compositions.md +40 -0
- package/skills/remotion-guidelines/reference/dom-measurement.md +82 -0
- package/skills/remotion-guidelines/reference/gifs.md +33 -0
- package/skills/remotion-guidelines/reference/lottie.md +41 -0
- package/skills/remotion-guidelines/reference/maps.md +26 -0
- package/skills/remotion-guidelines/reference/media.md +39 -0
- package/skills/remotion-guidelines/reference/mediabunny.md +28 -0
- package/skills/remotion-guidelines/reference/sequencing.md +44 -0
- package/skills/remotion-guidelines/reference/text.md +24 -0
- package/skills/remotion-guidelines/reference/three-d.md +33 -0
- package/skills/remotion-guidelines/reference/timing.md +22 -0
- package/skills/remotion-guidelines/reference/transitions.md +52 -0
- package/skills/shell-scripting-guidelines/SKILL.md +31 -0
- package/skills/shell-scripting-guidelines/reference/argument-parsing.md +67 -0
- package/skills/shell-scripting-guidelines/reference/common-patterns.md +46 -0
- package/skills/shell-scripting-guidelines/reference/error-handling.md +62 -0
- package/skills/shell-scripting-guidelines/reference/functions.md +66 -0
- package/skills/shell-scripting-guidelines/reference/idempotency.md +57 -0
- package/skills/shell-scripting-guidelines/reference/parameter-expansion.md +38 -0
- package/skills/shell-scripting-guidelines/reference/posix-compatibility.md +53 -0
- package/skills/shell-scripting-guidelines/reference/quoting.md +42 -0
- package/skills/shell-scripting-guidelines/reference/script-template.md +70 -0
- package/skills/shell-scripting-guidelines/reference/strict-mode.md +41 -0
- package/skills/shell-scripting-guidelines/reference/validation.md +30 -0
- package/skills/skill-guidelines/SKILL.md +33 -0
- package/skills/skill-guidelines/reference/assimilate.md +51 -0
- package/skills/skill-guidelines/reference/create.md +48 -0
- package/skills/skill-guidelines/reference/extract.md +48 -0
- package/skills/skill-guidelines/reference/simplify.md +56 -0
- package/skills/sql-postgresql-guidelines/SKILL.md +31 -0
- package/skills/sql-postgresql-guidelines/reference/constraints.md +47 -0
- package/skills/sql-postgresql-guidelines/reference/cte-patterns.md +42 -0
- package/skills/sql-postgresql-guidelines/reference/data-types.md +46 -0
- package/skills/sql-postgresql-guidelines/reference/indexing.md +45 -0
- package/skills/sql-postgresql-guidelines/reference/jsonb.md +54 -0
- package/skills/sql-postgresql-guidelines/reference/performance.md +46 -0
- package/skills/sql-postgresql-guidelines/reference/role-based-access.md +47 -0
- package/skills/sql-postgresql-guidelines/reference/row-level-security.md +66 -0
- package/skills/strudel-guidelines/SKILL.md +52 -0
- package/skills/strudel-guidelines/reference/arrangement.md +24 -0
- package/skills/strudel-guidelines/reference/conditionals.md +22 -0
- package/skills/strudel-guidelines/reference/effects.md +22 -0
- package/skills/strudel-guidelines/reference/genre-ambient.md +26 -0
- package/skills/strudel-guidelines/reference/genre-harsh.md +21 -0
- package/skills/strudel-guidelines/reference/genre-trance.md +23 -0
- package/skills/strudel-guidelines/reference/layering.md +22 -0
- package/skills/strudel-guidelines/reference/mini-notation.md +74 -0
- package/skills/strudel-guidelines/reference/modulation.md +22 -0
- package/skills/strudel-guidelines/reference/scales-harmony.md +20 -0
- package/skills/strudel-guidelines/reference/sounds.md +89 -0
- package/skills/strudel-guidelines/reference/tempo-timing.md +23 -0
- package/skills/terraform-guidelines/SKILL.md +28 -0
- package/skills/terraform-guidelines/reference/advanced-patterns.md +88 -0
- package/skills/terraform-guidelines/reference/locals.md +53 -0
- package/skills/terraform-guidelines/reference/module-definition.md +81 -0
- package/skills/terraform-guidelines/reference/module-structure.md +51 -0
- package/skills/terraform-guidelines/reference/remote-state.md +38 -0
- package/skills/terraform-guidelines/reference/root-module.md +71 -0
- package/skills/terraform-guidelines/reference/typed-variables.md +90 -0
- package/skills/threejs-guidelines/SKILL.md +38 -0
- package/skills/threejs-guidelines/reference/animation.md +26 -0
- package/skills/threejs-guidelines/reference/cameras-controls.md +26 -0
- package/skills/threejs-guidelines/reference/geometry.md +22 -0
- package/skills/threejs-guidelines/reference/interaction.md +25 -0
- package/skills/threejs-guidelines/reference/lighting-shadows.md +31 -0
- package/skills/threejs-guidelines/reference/loaders.md +29 -0
- package/skills/threejs-guidelines/reference/materials.md +25 -0
- package/skills/threejs-guidelines/reference/math.md +27 -0
- package/skills/threejs-guidelines/reference/node-materials.md +32 -0
- package/skills/threejs-guidelines/reference/patterns.md +29 -0
- package/skills/threejs-guidelines/reference/performance.md +24 -0
- package/skills/threejs-guidelines/reference/physics-vr.md +36 -0
- package/skills/threejs-guidelines/reference/postprocessing.md +26 -0
- package/skills/threejs-guidelines/reference/scene-fundamentals.md +26 -0
- package/skills/threejs-guidelines/reference/shaders.md +28 -0
- package/skills/threejs-guidelines/reference/textures.md +21 -0
- package/skills/threejs-guidelines/reference/webgpu.md +34 -0
- package/skills/typescript-guidelines/SKILL.md +37 -0
- package/skills/typescript-guidelines/reference/async-without-await.md +32 -0
- package/skills/typescript-guidelines/reference/avoid-barrel-exports.md +25 -0
- package/skills/typescript-guidelines/reference/avoid-eslint-disable.md +28 -0
- package/skills/typescript-guidelines/reference/avoid-reexports.md +26 -0
- package/skills/typescript-guidelines/reference/env-access-bracket-notation.md +29 -0
- package/skills/typescript-guidelines/reference/numeric-separator-enforcement.md +30 -0
- package/skills/typescript-guidelines/reference/template-literals-require-string-conversion.md +26 -0
- package/skills/typescript-guidelines/reference/unbound-method-references.md +32 -0
- package/skills/typescript-guidelines/reference/unnecessary-async-keywords.md +37 -0
- package/skills/typescript-to-lua-guidelines/SKILL.md +33 -0
- package/skills/typescript-to-lua-guidelines/reference/avoiding-heavy-features.md +41 -0
- package/skills/typescript-to-lua-guidelines/reference/coroutine-patterns.md +49 -0
- package/skills/typescript-to-lua-guidelines/reference/function-patterns.md +59 -0
- package/skills/typescript-to-lua-guidelines/reference/lua-interop.md +49 -0
- package/skills/typescript-to-lua-guidelines/reference/module-organization.md +42 -0
- package/skills/typescript-to-lua-guidelines/reference/multi-return-functions.md +47 -0
- package/skills/typescript-to-lua-guidelines/reference/namespaces-vs-classes.md +52 -0
- package/skills/typescript-to-lua-guidelines/reference/performance-tips.md +68 -0
- package/skills/typescript-to-lua-guidelines/reference/stable-tables.md +60 -0
- package/skills/typescript-to-lua-guidelines/reference/tsconfig.md +46 -0
- package/skills/typescript-to-lua-guidelines/reference/tstl-decorators.md +61 -0
- package/skills/typescript-to-lua-guidelines/reference/type-safety.md +79 -0
- package/skills/vitest-guidelines/SKILL.md +32 -0
- package/skills/vitest-guidelines/reference/cors-preflight-status-code.md +34 -0
- package/skills/vitest-guidelines/reference/http-testing.md +57 -0
- package/skills/vitest-guidelines/reference/json-response-type-safety.md +40 -0
- package/skills/vitest-guidelines/reference/mock-patterns.md +53 -0
- package/skills/vitest-guidelines/reference/project-references-path-resolution.md +36 -0
- package/skills/vitest-guidelines/reference/test-organization.md +25 -0
- package/skills/vitest-guidelines/reference/timestamp-testing.md +55 -0
- package/skills/vitest-guidelines/reference/type-safety.md +55 -0
- package/skills/vitest-guidelines/reference/typescript-config.md +43 -0
- package/skills/zod-guidelines/SKILL.md +33 -0
- package/skills/zod-guidelines/reference/default-values-output-type.md +63 -0
- package/skills/zod-guidelines/reference/migration-string-validators.md +38 -0
- package/skills/zod-guidelines/reference/migration-v4.md +46 -0
- package/skills/zod-guidelines/reference/schema-organization.md +73 -0
- package/skills/zod-guidelines/reference/validation-patterns.md +37 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# websocket-support: WebSocket Server Setup and Route Patterns
|
|
2
|
+
|
|
3
|
+
**Guideline:** Keep the object reference returned from `createNodeWebSocket()` and call methods on that object rather than destructuring, to maintain proper `this` binding.
|
|
4
|
+
|
|
5
|
+
**Rationale:** JavaScript methods that rely on `this` context lose their binding when destructured. The `@hono/node-ws` package's `createNodeWebSocket()` returns methods that depend on `this` to access internal state. Keeping the object reference preserves the binding while factory functions like `upgradeWebSocket` can safely be destructured.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {serve} from "@hono/node-server";
|
|
11
|
+
import {createNodeWebSocket} from "@hono/node-ws";
|
|
12
|
+
import {Hono} from "hono";
|
|
13
|
+
import {createApp} from "./app.js";
|
|
14
|
+
|
|
15
|
+
const app = createApp();
|
|
16
|
+
|
|
17
|
+
// ✅ CORRECT - Keep object reference
|
|
18
|
+
const wsHelpers = createNodeWebSocket({app});
|
|
19
|
+
|
|
20
|
+
const server = serve({
|
|
21
|
+
fetch: app.fetch,
|
|
22
|
+
port: 3000,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Call method on object to maintain binding
|
|
26
|
+
wsHelpers.injectWebSocket(server);
|
|
27
|
+
|
|
28
|
+
// Destructuring upgradeWebSocket is safe (it's a factory)
|
|
29
|
+
const {upgradeWebSocket} = createNodeWebSocket({app: new Hono()});
|
|
30
|
+
|
|
31
|
+
export const wsRouter = new Hono();
|
|
32
|
+
|
|
33
|
+
wsRouter.get(
|
|
34
|
+
"/chat",
|
|
35
|
+
upgradeWebSocket(() => ({
|
|
36
|
+
onOpen(_evt, ws) {
|
|
37
|
+
console.log("Client connected");
|
|
38
|
+
},
|
|
39
|
+
onMessage(event, ws) {
|
|
40
|
+
const data = JSON.parse(String(event.data)) as {message: string};
|
|
41
|
+
ws.send(JSON.stringify({echo: data.message}));
|
|
42
|
+
},
|
|
43
|
+
onClose(_evt, ws) {
|
|
44
|
+
console.log("Client disconnected");
|
|
45
|
+
},
|
|
46
|
+
onError(evt, ws) {
|
|
47
|
+
console.error("WebSocket error:", evt);
|
|
48
|
+
},
|
|
49
|
+
})),
|
|
50
|
+
);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Techniques:**
|
|
54
|
+
- Import `createNodeWebSocket` from `@hono/node-ws` and call with `{app}` parameter
|
|
55
|
+
- Keep entire object reference (e.g., `wsHelpers`) for method-based APIs
|
|
56
|
+
- Call methods on the object: `wsHelpers.injectWebSocket(server)`
|
|
57
|
+
- Destructuring factory functions like `upgradeWebSocket` is safe
|
|
58
|
+
- Define WebSocket handlers with onOpen, onMessage, onClose, onError callbacks
|
|
59
|
+
- Use TypeScript types for message data to ensure type safety
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hono-opinionated-guidelines
|
|
3
|
+
description: >-
|
|
4
|
+
Trigger on `*.ts` files with Hono imports or `@hono/` packages. Opinionated patterns: inline OpenAPI handlers, router selection, remove unnecessary async, bodyLimit. Keywords: Hono, OpenAPIHono, LinearRouter/RegExpRouter, inline handlers, bodyLimit.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Hono Opinionated Guidelines
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Hono ≥ 4.0, @hono/node-server, @hono/zod-openapi, TypeScript ≥ 5.8
|
|
12
|
+
|
|
13
|
+
## Opinionated patterns
|
|
14
|
+
|
|
15
|
+
- **Async controllers** - Remove unnecessary `async` from synchronous handlers, see [reference/controllers.md](reference/controllers.md)
|
|
16
|
+
- **OpenAPI type inference** - Use inline handlers for type safety, explicit status codes, OpenAPIHono hierarchy, see [reference/openapi-inline-handlers.md](reference/openapi-inline-handlers.md), [reference/openapi-explicit-status-codes.md](reference/openapi-explicit-status-codes.md), [reference/openapi-router-hierarchy.md](reference/openapi-router-hierarchy.md)
|
|
17
|
+
- **OpenAPI documentation** - Use `app.doc()` for automatic spec generation, see [reference/openapi-spec-generation.md](reference/openapi-spec-generation.md)
|
|
18
|
+
- **Router selection** - LinearRouter for serverless, RegExpRouter for high-throughput, see [reference/router-selection.md](reference/router-selection.md)
|
|
19
|
+
- **Request limits** - Use `bodyLimit` middleware to prevent DoS, see [reference/body-limit.md](reference/body-limit.md)
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {OpenAPIHono} from "@hono/zod-openapi";
|
|
25
|
+
import {bodyLimit} from "hono/body-limit";
|
|
26
|
+
import {secureHeaders} from "hono/secure-headers";
|
|
27
|
+
|
|
28
|
+
export function createApp() {
|
|
29
|
+
const app = new OpenAPIHono();
|
|
30
|
+
app.use("*", secureHeaders());
|
|
31
|
+
app.use("*", bodyLimit({maxSize: 100 * 1024}));
|
|
32
|
+
app.route("/api/v1", v1Router);
|
|
33
|
+
app.doc("/openapi.json", {
|
|
34
|
+
openapi: "3.1.0",
|
|
35
|
+
info: {title: "API", version: "1.0.0"},
|
|
36
|
+
});
|
|
37
|
+
return app;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Progressive disclosure
|
|
42
|
+
|
|
43
|
+
- Read [reference/controllers.md](reference/controllers.md) - When seeing unnecessary async functions
|
|
44
|
+
- Read [reference/openapi-inline-handlers.md](reference/openapi-inline-handlers.md) - When OpenAPI loses type inference
|
|
45
|
+
- Read [reference/openapi-explicit-status-codes.md](reference/openapi-explicit-status-codes.md) - When defining OpenAPI response schemas
|
|
46
|
+
- Read [reference/openapi-router-hierarchy.md](reference/openapi-router-hierarchy.md) - When composing multiple routers
|
|
47
|
+
- Read [reference/openapi-spec-generation.md](reference/openapi-spec-generation.md) - When generating OpenAPI documentation
|
|
48
|
+
- Read [reference/router-selection.md](reference/router-selection.md) - When optimizing for serverless/edge or high-throughput
|
|
49
|
+
- Read [reference/body-limit.md](reference/body-limit.md) - When preventing oversized request payloads
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# application-structure: Application Factory and Router Organization
|
|
2
|
+
|
|
3
|
+
**Guideline:** Use factory functions to create Hono applications instead of exporting instances, and organize routes into separate router files by domain.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Factory functions enable testability by creating fresh instances per test, support dependency injection, and improve isolation. Domain-based router organization provides clear separation of concerns and reduces merge conflicts in team environments.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// src/app.ts - Main application factory
|
|
11
|
+
import {Hono} from "hono";
|
|
12
|
+
import {cors} from "hono/cors";
|
|
13
|
+
import {logger} from "hono/logger";
|
|
14
|
+
import {v1Router} from "./routes/v1/index.js";
|
|
15
|
+
import {v2Router} from "./routes/v2/index.js";
|
|
16
|
+
|
|
17
|
+
export function createApp() {
|
|
18
|
+
const app = new Hono();
|
|
19
|
+
|
|
20
|
+
// Global middleware
|
|
21
|
+
app.use("*", logger());
|
|
22
|
+
app.use("*", cors());
|
|
23
|
+
|
|
24
|
+
// Mount routers by version
|
|
25
|
+
app.route("/api/v1", v1Router);
|
|
26
|
+
app.route("/api/v2", v2Router);
|
|
27
|
+
|
|
28
|
+
return app;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/routes/v1/users.ts - Domain router
|
|
32
|
+
import {Hono} from "hono";
|
|
33
|
+
import {zValidator} from "@hono/zod-validator";
|
|
34
|
+
import * as controller from "../../controllers/users.controller.js";
|
|
35
|
+
import {CreateUserSchema} from "../../schemas/users.js";
|
|
36
|
+
|
|
37
|
+
export const usersRouter = new Hono();
|
|
38
|
+
|
|
39
|
+
usersRouter.post(
|
|
40
|
+
"/",
|
|
41
|
+
zValidator("json", CreateUserSchema),
|
|
42
|
+
controller.createUser,
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Techniques:**
|
|
47
|
+
- Create `createApp()` factory function instead of exporting instances
|
|
48
|
+
- Configure global middleware inside the factory
|
|
49
|
+
- Mount domain routers using `app.route()`
|
|
50
|
+
- Organize routers in separate files by domain (users, items, etc.)
|
|
51
|
+
- Import controllers from dedicated controller files
|
|
52
|
+
- Keep route definitions focused on routing logic only
|
|
53
|
+
- Export factory functions for testability
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# body-limit: Preventing Large Payload Attacks
|
|
2
|
+
|
|
3
|
+
**Guideline:** Use Body Limit middleware to prevent DoS attacks from oversized request payloads, configuring appropriate limits per endpoint based on expected data.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Large request bodies can exhaust server memory, cause denial of service, and overwhelm downstream services. Body Limit middleware rejects requests before fully reading them, uses stream reading without Content-Length requirements, and returns 413 Payload Too Large status while remaining configurable per route.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {bodyLimit} from "hono/body-limit";
|
|
11
|
+
|
|
12
|
+
// Global limit for most endpoints
|
|
13
|
+
app.use(
|
|
14
|
+
"*",
|
|
15
|
+
bodyLimit({
|
|
16
|
+
maxSize: 100 * 1024, // 100KB default
|
|
17
|
+
onError: (c) => {
|
|
18
|
+
return c.json(
|
|
19
|
+
{
|
|
20
|
+
type: "about:blank#payload-too-large",
|
|
21
|
+
title: "Payload Too Large",
|
|
22
|
+
status: 413,
|
|
23
|
+
detail: "Request body exceeds 100KB limit",
|
|
24
|
+
},
|
|
25
|
+
413,
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// Higher limit for file uploads
|
|
32
|
+
app.post(
|
|
33
|
+
"/upload",
|
|
34
|
+
bodyLimit({
|
|
35
|
+
maxSize: 10 * 1024 * 1024, // 10MB for uploads
|
|
36
|
+
}),
|
|
37
|
+
async (c) => {
|
|
38
|
+
const body = await c.req.parseBody();
|
|
39
|
+
// Handle file upload
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Stricter limit for JSON APIs
|
|
44
|
+
app.use(
|
|
45
|
+
"/api/*",
|
|
46
|
+
bodyLimit({
|
|
47
|
+
maxSize: 50 * 1024, // 50KB for JSON
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Techniques:**
|
|
53
|
+
- Import `bodyLimit` from `hono/body-limit` and set appropriate `maxSize` in bytes
|
|
54
|
+
- Apply globally with app.use() or per-route for flexibility
|
|
55
|
+
- Configure different limits for different endpoints (100KB default, 10MB for uploads)
|
|
56
|
+
- Provide custom `onError` handler for formatted error responses
|
|
57
|
+
- Consider internal vs public services when setting limits
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# context-storage: Access Context Globally with AsyncLocalStorage
|
|
2
|
+
|
|
3
|
+
**Guideline:** Use `contextStorage()` middleware with `getContext()` to access Hono Context outside route handlers, enabling cleaner service layer code without parameter drilling.
|
|
4
|
+
|
|
5
|
+
**Rationale:** AsyncLocalStorage provides global access to the current request context without parameter drilling through the call stack, enabling clean separation between routing and business logic while automatically cleaning up context after requests.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {Hono} from "hono";
|
|
11
|
+
import {contextStorage, getContext} from "hono/context-storage";
|
|
12
|
+
|
|
13
|
+
const app = new Hono();
|
|
14
|
+
|
|
15
|
+
// Enable context storage early
|
|
16
|
+
app.use(contextStorage());
|
|
17
|
+
|
|
18
|
+
// Set request metadata
|
|
19
|
+
app.use("*", async (c, next) => {
|
|
20
|
+
c.set("requestId", crypto.randomUUID());
|
|
21
|
+
c.set("tenantId", c.req.header("X-Tenant-ID"));
|
|
22
|
+
await next();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.get("/items", (c) => {
|
|
26
|
+
const items = itemsService.list(); // No context passed
|
|
27
|
+
return c.json(items);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// In service layer (separate file)
|
|
31
|
+
export function list() {
|
|
32
|
+
const c = getContext();
|
|
33
|
+
const tenantId = c.get("tenantId");
|
|
34
|
+
const requestId = c.get("requestId");
|
|
35
|
+
|
|
36
|
+
logger.info(`[${requestId}] Listing items for tenant ${tenantId}`);
|
|
37
|
+
return db.items.findMany({where: {tenantId}});
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Techniques:**
|
|
42
|
+
- Import `contextStorage` and `getContext` from `hono/context-storage`
|
|
43
|
+
- Apply `contextStorage()` middleware early in middleware chain
|
|
44
|
+
- Call `getContext()` anywhere during request handling to access context
|
|
45
|
+
- For Cloudflare Workers enable `nodejs_compat` flag
|
|
46
|
+
- Use sparingly as explicit parameters are more testable
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# controllers: Remove Unnecessary Async from Synchronous Controllers
|
|
2
|
+
|
|
3
|
+
**Guideline:** Remove the `async` keyword from controller functions that don't use `await`, as unnecessary async adds overhead without providing benefits.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Marking a function `async` without awaiting anything creates unnecessary Promise wrapping overhead, adds microtask queue delays, and misleads developers about async operations. Synchronous controllers are faster, clearer in intent, and produce simpler stack traces.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import type {Context} from "hono";
|
|
11
|
+
|
|
12
|
+
// ✅ CORRECT - No async needed
|
|
13
|
+
export function getUser(c: Context) {
|
|
14
|
+
const {id} = (c.req.valid as (target: string) => {id: string})("param");
|
|
15
|
+
const user = userService.getById(id); // Synchronous call
|
|
16
|
+
return c.json(user);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ✅ CORRECT - Async needed for await
|
|
20
|
+
export async function createUser(c: Context) {
|
|
21
|
+
const data = (c.req.valid as (target: string) => CreateUser)("json");
|
|
22
|
+
const user = await userService.create(data); // Awaiting async operation
|
|
23
|
+
return c.json(user, 201);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ✅ CORRECT - No async, just returns response
|
|
27
|
+
export function listUsers(c: Context) {
|
|
28
|
+
const users = userService.list();
|
|
29
|
+
return c.json(users);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Techniques:**
|
|
34
|
+
- Review controller function body for `await` keyword usage
|
|
35
|
+
- Remove `async` keyword if no `await` exists in function
|
|
36
|
+
- Ensure return statements work with or without async (c.json() compatible)
|
|
37
|
+
- Keep `async` only when awaiting DB queries, external APIs, or other async operations
|
|
38
|
+
- Check for performance improvements after removing unnecessary async
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# cookie-handling: Secure Cookie Configuration and Signed Cookies
|
|
2
|
+
|
|
3
|
+
**Guideline:** Set secure cookie options explicitly, use signed cookies for sensitive data, and follow browser-enforced prefix requirements for additional security.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Cookies require careful configuration to ensure HTTPS-only transmission, prevent JavaScript access, defend against CSRF, and verify integrity. Cookie prefixes enforce additional security guarantees, while signed cookies prevent tampering and provide strong integrity verification for sensitive client-side state.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {
|
|
11
|
+
getCookie,
|
|
12
|
+
getSignedCookie,
|
|
13
|
+
setCookie,
|
|
14
|
+
setSignedCookie,
|
|
15
|
+
} from "hono/cookie";
|
|
16
|
+
|
|
17
|
+
// Standard secure cookie
|
|
18
|
+
app.post("/login", (c) => {
|
|
19
|
+
setCookie(c, "session", sessionId, {
|
|
20
|
+
secure: true,
|
|
21
|
+
httpOnly: true,
|
|
22
|
+
sameSite: "Strict",
|
|
23
|
+
maxAge: 86400, // 1 day
|
|
24
|
+
path: "/",
|
|
25
|
+
});
|
|
26
|
+
return c.json({success: true});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Signed cookie for integrity (async)
|
|
30
|
+
app.post("/preferences", async (c) => {
|
|
31
|
+
await setSignedCookie(c, "prefs", JSON.stringify(prefs), "secret-key", {
|
|
32
|
+
secure: true,
|
|
33
|
+
httpOnly: true,
|
|
34
|
+
sameSite: "Lax",
|
|
35
|
+
});
|
|
36
|
+
return c.json({saved: true});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Verify signed cookie
|
|
40
|
+
app.get("/preferences", async (c) => {
|
|
41
|
+
const prefs = await getSignedCookie(c, "secret-key", "prefs");
|
|
42
|
+
if (prefs === false) {
|
|
43
|
+
return c.json({error: "Invalid signature"}, 400);
|
|
44
|
+
}
|
|
45
|
+
return c.json(JSON.parse(prefs ?? "{}"));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Host-prefixed cookie (strictest)
|
|
49
|
+
setCookie(c, "__Host-session", token, {
|
|
50
|
+
secure: true,
|
|
51
|
+
path: "/",
|
|
52
|
+
// domain must NOT be set for __Host- prefix
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Techniques:**
|
|
57
|
+
- Import cookie helpers from `hono/cookie` (setCookie, getCookie, setSignedCookie, getSignedCookie)
|
|
58
|
+
- Always set `secure: true` and `httpOnly: true` for sensitive cookies
|
|
59
|
+
- Use `sameSite: 'Strict'` for maximum CSRF protection or `'Lax'` for better compatibility
|
|
60
|
+
- Use `setSignedCookie` (async) for cookies requiring integrity verification
|
|
61
|
+
- Verify signed cookies with `getSignedCookie` and check for false value on tampering
|
|
62
|
+
- Use `__Host-` prefix for strictest cookie restrictions (requires `secure: true` and `path: '/'`)
|
|
63
|
+
- Keep `maxAge` under 400 days to respect browser limits
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# error-handling: RFC 7807 Problem Details for Consistent Error Responses
|
|
2
|
+
|
|
3
|
+
**Guideline:** Use RFC 7807 Problem Details format for all error responses to provide consistent, structured, machine-readable error information across your API.
|
|
4
|
+
|
|
5
|
+
**Rationale:** RFC 7807 provides a standard structure recognized across HTTP APIs, enabling clients to parse errors consistently with machine-readable field-level validation details and request context. Built-in extensibility and separation between human and machine-readable fields improves debugging and error handling.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import type {Context} from "hono";
|
|
11
|
+
import type {z} from "zod";
|
|
12
|
+
|
|
13
|
+
export interface ProblemDetails {
|
|
14
|
+
type: string;
|
|
15
|
+
title: string;
|
|
16
|
+
status: number;
|
|
17
|
+
detail?: string;
|
|
18
|
+
instance?: string;
|
|
19
|
+
issues?: {
|
|
20
|
+
path: string[];
|
|
21
|
+
message: string;
|
|
22
|
+
code?: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function badRequest(c: Context, error: z.ZodError): Response {
|
|
27
|
+
const problem: ProblemDetails = {
|
|
28
|
+
type: "about:blank#bad-request",
|
|
29
|
+
title: "Bad Request",
|
|
30
|
+
status: 400,
|
|
31
|
+
detail: "Request validation failed",
|
|
32
|
+
instance: c.req.path,
|
|
33
|
+
issues: error.issues.map((issue) => ({
|
|
34
|
+
path: issue.path.map(String),
|
|
35
|
+
message: issue.message,
|
|
36
|
+
code: issue.code,
|
|
37
|
+
})),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return new Response(JSON.stringify(problem), {
|
|
41
|
+
status: 400,
|
|
42
|
+
headers: {"Content-Type": "application/json"},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function notFound(c: Context, detail: string): Response {
|
|
47
|
+
const problem: ProblemDetails = {
|
|
48
|
+
type: "about:blank#not-found",
|
|
49
|
+
title: "Not Found",
|
|
50
|
+
status: 404,
|
|
51
|
+
detail,
|
|
52
|
+
instance: c.req.path,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return new Response(JSON.stringify(problem), {
|
|
56
|
+
status: 404,
|
|
57
|
+
headers: {"Content-Type": "application/json"},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Techniques:**
|
|
63
|
+
- Define `ProblemDetails` TypeScript interface matching RFC 7807 spec
|
|
64
|
+
- Include required fields: type, title, status
|
|
65
|
+
- Include optional fields: detail, instance, custom extensions
|
|
66
|
+
- For validation errors add `issues` array with field-level details
|
|
67
|
+
- Create helper functions for common error types (badRequest, notFound, etc.)
|
|
68
|
+
- Return proper HTTP status codes matching the status field
|
|
69
|
+
- Set `Content-Type: application/json` header
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# middleware-combine: Composing Middleware with some, every, except
|
|
2
|
+
|
|
3
|
+
**Guideline:** Use the `combine` module (`some`, `every`, `except`) to compose complex middleware logic for conditional execution and access control.
|
|
4
|
+
|
|
5
|
+
**Rationale:** The combine module provides declarative composition of complex requirements: `some()` implements OR logic for alternative auth methods, `every()` implements AND logic for layered checks, and `except()` skips middleware for specific paths, enabling cleaner code than nested conditionals.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {basicAuth} from "hono/basic-auth";
|
|
11
|
+
import {bearerAuth} from "hono/bearer-auth";
|
|
12
|
+
import {every, except, some} from "hono/combine";
|
|
13
|
+
|
|
14
|
+
// Accept either basic auth OR bearer token
|
|
15
|
+
app.use(
|
|
16
|
+
"/api/*",
|
|
17
|
+
some(
|
|
18
|
+
basicAuth({verifyUser: verifyBasicAuth}),
|
|
19
|
+
bearerAuth({verifyToken: verifyBearerToken}),
|
|
20
|
+
),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Must be authenticated AND have admin role
|
|
24
|
+
app.use(
|
|
25
|
+
"/admin/*",
|
|
26
|
+
every(bearerAuth({verifyToken: verifyToken}), async (c, next) => {
|
|
27
|
+
const user = c.get("user");
|
|
28
|
+
if (user.role !== "admin") {
|
|
29
|
+
return c.json({error: "Forbidden"}, 403);
|
|
30
|
+
}
|
|
31
|
+
await next();
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Apply rate limiting to all routes EXCEPT health checks
|
|
36
|
+
app.use("*", except("/health", rateLimiter({max: 100, window: 60})));
|
|
37
|
+
|
|
38
|
+
// Multiple path exclusions
|
|
39
|
+
app.use("*", except(["/health", "/metrics", "/ready"], authMiddleware()));
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Techniques:**
|
|
43
|
+
- Import `some`, `every`, `except` from `hono/combine`
|
|
44
|
+
- Use `some()` for alternative auth methods (OAuth OR API key)
|
|
45
|
+
- Use `every()` for layered requirements (authenticated AND has role)
|
|
46
|
+
- Use `except()` for path-based middleware exclusions
|
|
47
|
+
- Combine module handlers with other Hono middleware seamlessly
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# middleware-patterns: CORS Configuration and Custom Middleware
|
|
2
|
+
|
|
3
|
+
**Guideline:** Configure CORS differently for development and production, and use middleware factory functions to ensure proper `this` binding and parameterization.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Environment-specific CORS balances development convenience with production security. Middleware factories ensure correct context binding in async operations, enable parameterization, and provide consistent patterns across applications through proper closure over configuration values.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import type {Context, Next} from "hono";
|
|
11
|
+
import {cors} from "hono/cors";
|
|
12
|
+
|
|
13
|
+
// Environment-specific CORS
|
|
14
|
+
const isDevelopment = process.env.NODE_ENV === "development";
|
|
15
|
+
|
|
16
|
+
if (isDevelopment) {
|
|
17
|
+
// Development: Permissive
|
|
18
|
+
app.use(
|
|
19
|
+
"*",
|
|
20
|
+
cors({
|
|
21
|
+
origin: "*",
|
|
22
|
+
allowMethods: ["GET", "POST", "PUT", "DELETE"],
|
|
23
|
+
maxAge: 86_400, // 24 hours
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
} else {
|
|
27
|
+
// Production: Restrictive
|
|
28
|
+
app.use(
|
|
29
|
+
"*",
|
|
30
|
+
cors({
|
|
31
|
+
origin: ["https://app.example.com"],
|
|
32
|
+
allowMethods: ["GET", "POST", "PUT", "DELETE"],
|
|
33
|
+
credentials: true,
|
|
34
|
+
maxAge: 600, // 10 minutes
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Custom middleware factory with proper binding
|
|
40
|
+
function requestId() {
|
|
41
|
+
return async (c: Context, next: Next) => {
|
|
42
|
+
const id = crypto.randomUUID();
|
|
43
|
+
c.set("requestId", id);
|
|
44
|
+
c.header("X-Request-ID", id);
|
|
45
|
+
await next();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
app.use("*", requestId());
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Techniques:**
|
|
53
|
+
- Import CORS from `hono/cors` and configure based on environment
|
|
54
|
+
- For development use `origin: "*"` for permissive access
|
|
55
|
+
- For production specify allowed origins explicitly
|
|
56
|
+
- Create middleware factory function that returns `async (c, next) => {...}`
|
|
57
|
+
- Call factory function when registering: `app.use("*", requestId())`
|
|
58
|
+
- Never destructure methods from helpers that rely on `this` binding
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# openapi-explicit-status-codes: Always Provide Explicit Status Codes in Responses
|
|
2
|
+
|
|
3
|
+
**Guideline:** Always provide explicit status codes in all `c.json()` calls within OpenAPI routes, as discriminated unions require them for proper TypeScript type narrowing.
|
|
4
|
+
|
|
5
|
+
**Rationale:** OpenAPI routes define multiple possible response types, each with a specific status code. TypeScript uses discriminated unions to represent these possibilities. Without explicit status codes, TypeScript cannot narrow the response type at compile time, causing type inference to break and losing type safety guarantees.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {createRoute, z} from "@hono/zod-openapi";
|
|
11
|
+
|
|
12
|
+
const getItemRoute = createRoute({
|
|
13
|
+
method: "get",
|
|
14
|
+
path: "/items/{id}",
|
|
15
|
+
responses: {
|
|
16
|
+
200: {
|
|
17
|
+
content: {"application/json": {schema: ItemSchema}},
|
|
18
|
+
description: "Item found",
|
|
19
|
+
},
|
|
20
|
+
404: {
|
|
21
|
+
content: {"application/json": {schema: ProblemDetailsSchema}},
|
|
22
|
+
description: "Item not found",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// ✅ CORRECT - Explicit status codes
|
|
28
|
+
itemsRouter.openapi(getItemRoute, (c) => {
|
|
29
|
+
const {id} = c.req.valid("param");
|
|
30
|
+
const item = itemsService.findById(id);
|
|
31
|
+
|
|
32
|
+
if (!item) {
|
|
33
|
+
return c.json(
|
|
34
|
+
{
|
|
35
|
+
type: "about:blank#not-found",
|
|
36
|
+
title: "Not Found",
|
|
37
|
+
status: 404,
|
|
38
|
+
detail: "Item not found",
|
|
39
|
+
},
|
|
40
|
+
404,
|
|
41
|
+
); // Explicit status code
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return c.json(item, 200); // Explicit status code
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// ✅ CORRECT - Explicit 201 for creation
|
|
48
|
+
itemsRouter.openapi(createItemRoute, (c) => {
|
|
49
|
+
const data = c.req.valid("json");
|
|
50
|
+
const item = itemsService.create(data);
|
|
51
|
+
return c.json(item, 201); // Explicit 201 for created resource
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Techniques:**
|
|
56
|
+
- Review all `c.json()` calls in OpenAPI handlers and add status code parameter
|
|
57
|
+
- Use 200 for success (OK) and 201 for creation (Created)
|
|
58
|
+
- Use 400 (Bad Request), 404 (Not Found), 500 (Server Error) for error cases
|
|
59
|
+
- Match status codes to those defined in route's `responses` object
|
|
60
|
+
- For Problem Details errors, include status in both response object and HTTP status
|
|
61
|
+
- Never rely on implicit default status codes in OpenAPI routes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# openapi-inline-handlers: Use Inline Handlers for OpenAPI Routes
|
|
2
|
+
|
|
3
|
+
**Guideline:** Implement handler logic inline within OpenAPI route definitions instead of separate controller functions to enable proper TypeScript type inference from route schemas.
|
|
4
|
+
|
|
5
|
+
**Rationale:** Hono's OpenAPI integration uses TypeScript type inference to match route schemas with handlers. This only works with inline handlers because TypeScript cannot infer types across function boundaries, and separate controllers return generic `Response` types instead of being automatically typed by route definitions.
|
|
6
|
+
|
|
7
|
+
**Example:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
|
11
|
+
|
|
12
|
+
// Define route with schemas
|
|
13
|
+
const listItemsRoute = createRoute({
|
|
14
|
+
method: "get",
|
|
15
|
+
path: "/items",
|
|
16
|
+
request: {
|
|
17
|
+
query: z.object({
|
|
18
|
+
page: z.coerce.number().default(1),
|
|
19
|
+
limit: z.coerce.number().default(10),
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
responses: {
|
|
23
|
+
200: {
|
|
24
|
+
content: {
|
|
25
|
+
"application/json": {
|
|
26
|
+
schema: z.object({
|
|
27
|
+
items: z.array(ItemSchema),
|
|
28
|
+
pagination: z.object({
|
|
29
|
+
page: z.number(),
|
|
30
|
+
limit: z.number(),
|
|
31
|
+
total: z.number(),
|
|
32
|
+
}),
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
description: "List of items",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ✅ CORRECT - Inline handler with type inference
|
|
42
|
+
itemsRouter.openapi(listItemsRoute, (c) => {
|
|
43
|
+
// Types automatically inferred from route definition
|
|
44
|
+
const {page, limit} = c.req.valid("query");
|
|
45
|
+
const {items, total} = itemsService.listItems(page, limit);
|
|
46
|
+
return c.json({items, pagination: {page, limit, total}}, 200);
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Techniques:**
|
|
51
|
+
- Define route using `createRoute()` with full request and response schemas
|
|
52
|
+
- Register route with `router.openapi(route, (c) => {...})` with inline handler
|
|
53
|
+
- Access validated data via `c.req.valid()` to get automatically typed request data
|
|
54
|
+
- Return responses with `c.json(data, statusCode)` and explicit status codes
|
|
55
|
+
- Keep route handler focused on request/response mapping
|
|
56
|
+
- Extract complex business logic to service functions called from handler
|