@punks/cli 0.1.16 → 1.0.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/AGENTS.md +10 -0
- package/README.md +64 -0
- package/dist/data/AGENTS.md +123 -0
- package/dist/data/catalog/lint.ts +349 -0
- package/dist/data/catalog/packs.ts +44 -0
- package/dist/data/catalog/skills.ts +47 -0
- package/dist/data/catalog/tools.ts +22 -0
- package/dist/data/hooks/format-edited-file.mjs +554 -0
- package/dist/data/hooks/format-edited-file.py +157 -0
- package/dist/data/hooks/format-edited-file.sh +37 -0
- package/dist/data/hooks/require-tests-for-pr.mjs +144 -0
- package/dist/data/scripts/sync-subagents.mjs +420 -0
- package/dist/data/subagents/manifest.mjs +253 -0
- package/dist/index.js +46415 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/SKILL.md +50 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/references/layout.md +167 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/SKILL.md +49 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/test-matrix.md +34 -0
- package/dist/skills/agnostic/docs/docs-maintenance/SKILL.md +193 -0
- package/dist/skills/agnostic/docs/docs-maintenance/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/concept-pages.md +48 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/flow-pages.md +41 -0
- package/dist/skills/agnostic/frontend/agent-browser/.clawdhub/origin.json +7 -0
- package/dist/skills/agnostic/frontend/agent-browser/SKILL.md +229 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/authentication.md +202 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/commands.md +259 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/proxy-support.md +188 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/session-management.md +193 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/snapshot-refs.md +194 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/video-recording.md +173 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/authenticated-session.sh +97 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/capture-workflow.sh +69 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/form-automation.sh +62 -0
- package/dist/skills/agnostic/frontend/design-taste-frontend/SKILL.md +226 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/SKILL.md +55 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/react/structure.md +102 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/structure.md +257 -0
- package/dist/skills/agnostic/frontend/gpt-taste/SKILL.md +74 -0
- package/dist/skills/agnostic/frontend/image-taste-frontend/SKILL.md +1102 -0
- package/dist/skills/agnostic/frontend/redesign-existing-projects/SKILL.md +178 -0
- package/dist/skills/agnostic/planning/create-plan/REFERENCE.md +37 -0
- package/dist/skills/agnostic/planning/create-plan/SKILL.md +69 -0
- package/dist/skills/agnostic/planning/create-plan/references/backlog-sync.md +44 -0
- package/dist/skills/agnostic/planning/create-plan/references/grill-phase.md +86 -0
- package/dist/skills/agnostic/planning/create-plan/references/plan-schema.md +66 -0
- package/dist/skills/agnostic/planning/create-plan/references/planner-phase.md +39 -0
- package/dist/skills/agnostic/planning/create-plan/references/stop-conditions.md +18 -0
- package/dist/skills/agnostic/planning/create-plan/references/tdd-phase.md +26 -0
- package/dist/skills/agnostic/planning/create-spec/SKILL.md +57 -0
- package/dist/skills/agnostic/planning/create-spec/assets/SPEC-TEMPLATE.md +91 -0
- package/dist/skills/agnostic/planning/create-spec/references/discovery.md +44 -0
- package/dist/skills/agnostic/planning/create-spec/references/folder-naming.md +27 -0
- package/dist/skills/agnostic/planning/create-spec/references/handoff.md +47 -0
- package/dist/skills/agnostic/planning/create-spec/references/questioning.md +41 -0
- package/dist/skills/agnostic/planning/create-spec/references/spec-quality-bar.md +58 -0
- package/dist/skills/agnostic/planning/create-spec/references/wiki-bookkeeping.md +26 -0
- package/dist/skills/agnostic/planning/grill-me/SKILL.md +28 -0
- package/dist/skills/agnostic/planning/implement-spec/SKILL.md +72 -0
- package/dist/skills/agnostic/planning/implement-spec/assets/IMPLEMENTATION-NOTES-TEMPLATE.md +47 -0
- package/dist/skills/agnostic/planning/implement-spec/references/lifecycle.md +149 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-orchestration.md +102 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-worker-brief.md +65 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel.md +56 -0
- package/dist/skills/agnostic/planning/implement-spec/references/sequential.md +28 -0
- package/dist/skills/agnostic/planning/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/quality/simplify/SKILL.md +14 -0
- package/dist/skills/agnostic/quality/tdd/SKILL.md +107 -0
- package/dist/skills/agnostic/quality/tdd/deep-modules.md +33 -0
- package/dist/skills/agnostic/quality/tdd/interface-design.md +31 -0
- package/dist/skills/agnostic/quality/tdd/mocking.md +59 -0
- package/dist/skills/agnostic/quality/tdd/refactoring.md +10 -0
- package/dist/skills/agnostic/quality/tdd/tests.md +61 -0
- package/dist/skills/agnostic/requirements/requirements-grill/SKILL.md +42 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/artifact-output.md +73 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/grilling-flow.md +57 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/wiki-output.md +94 -0
- package/dist/skills/agnostic/requirements/write-backlog/EXAMPLES.md +67 -0
- package/dist/skills/agnostic/requirements/write-backlog/REFERENCE.md +253 -0
- package/dist/skills/agnostic/requirements/write-backlog/SKILL.md +68 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/backlog-model.md +69 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/story-shape.md +66 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/azure-devops-create-payload.md +63 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/github-issues-create-payload.md +48 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/linear-create-payload.md +76 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/REFERENCE.md +78 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/SKILL.md +76 -0
- package/dist/skills/agnostic/research/parallel-research/SKILL.md +68 -0
- package/dist/skills/agnostic/research/parallel-research/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/subagents/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/write-a-skill/SKILL.md +117 -0
- package/dist/skills/frameworks/better-auth/better-auth-best-practices/SKILL.md +166 -0
- package/dist/skills/frameworks/better-auth/better-auth-security-best-practices/SKILL.MD +432 -0
- package/dist/skills/frameworks/effect/effect-authoring/SKILL.md +116 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/branded-types.md +98 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-atom-patterns.md +257 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-primitives.md +144 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/error-patterns.md +156 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/otel-patterns.md +113 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/test-patterns.md +146 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/SKILL.md +96 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/references/layout.md +68 -0
- package/dist/skills/frameworks/effect/effect-best-practices/SKILL.md +517 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/anti-patterns.md +392 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/effect-atom-patterns.md +653 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/error-patterns.md +464 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/language-server.md +287 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/layer-patterns.md +495 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/observability-patterns.md +342 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/rpc-cluster-patterns.md +418 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/schema-patterns.md +353 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/service-patterns.md +299 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/SKILL.md +65 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/flow-examples.md +154 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/source-backed-primitives.md +104 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/test-matrix.md +36 -0
- package/dist/skills/frameworks/elysia/elysiajs/SKILL.md +475 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/basic.ts +9 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/body-parser.ts +33 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/complex.ts +112 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/cookie.ts +45 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/error.ts +38 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/file.ts +10 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/guard.ts +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/map-response.ts +15 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/redirect.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/rename.ts +32 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/schema.ts +61 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/state.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/upload-file.ts +20 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/websocket.ts +25 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/ai-sdk.md +92 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/astro.md +59 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/better-auth.md +117 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/cloudflare-worker.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/deno.md +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/drizzle.md +258 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/expo.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nextjs.md +103 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nodejs.md +64 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nuxt.md +67 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/prisma.md +93 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/react-email.md +134 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/sveltekit.md +53 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/tanstack-start.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/vercel.md +55 -0
- package/dist/skills/frameworks/elysia/elysiajs/patterns/mvc.md +380 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/bearer.md +30 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cors.md +141 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cron.md +265 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-apollo.md +90 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-yoga.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/html.md +188 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/jwt.md +197 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/openapi.md +246 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/opentelemetry.md +167 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/server-timing.md +71 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/static.md +84 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/bun-fullstack-dev-server.md +129 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/cookie.md +187 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/deployment.md +413 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/eden.md +158 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/lifecycle.md +198 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/macro.md +83 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/plugin.md +207 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/route.md +331 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/testing.md +385 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/validation.md +491 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/websocket.md +250 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/branch-protection.yml +24 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/deploy.yml +61 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/AGENTS.md +5958 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/SKILL.md +130 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-dto-serialization.md +182 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-interceptors.md +202 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-pipes.md +205 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-versioning.md +191 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-avoid-circular-deps.md +80 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-feature-modules.md +82 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-module-sharing.md +141 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-single-responsibility.md +106 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-events.md +108 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-repository-pattern.md +97 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-avoid-n-plus-one.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-migrations.md +129 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-transactions.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-graceful-shutdown.md +222 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-config-module.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-logging.md +232 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-avoid-service-locator.md +104 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-interface-segregation.md +165 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-liskov-substitution.md +221 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-prefer-constructor-injection.md +86 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-scope-awareness.md +94 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-use-interfaces-tokens.md +101 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-handle-async-errors.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-throw-http-exceptions.md +114 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-use-exception-filters.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-health-checks.md +226 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-patterns.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-queues.md +252 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-async-hooks.md +109 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-lazy-loading.md +121 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-optimize-database.md +131 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-use-caching.md +128 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-auth-jwt.md +146 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-rate-limiting.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-sanitize-output.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-use-guards.md +135 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-validate-all-input.md +150 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-e2e-supertest.md +178 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-mock-external-services.md +179 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-use-testing-module.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build-agents.ts +299 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build.sh +16 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package-lock.json +237 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package.json +15 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/SKILL.md +208 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/authentication.md +166 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/controllers-routing.md +111 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/dtos-validation.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/migration-from-express.md +1237 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/services-di.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/testing-patterns.md +186 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/SKILL.md +153 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/async-patterns.md +87 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/bundling.md +180 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/data-patterns.md +297 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/debug-tricks.md +105 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/directives.md +73 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/error-handling.md +227 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/file-conventions.md +140 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/font.md +245 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/functions.md +108 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/hydration-error.md +91 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/image.md +173 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/metadata.md +301 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/parallel-routes.md +287 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/route-handlers.md +146 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/rsc-boundaries.md +159 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/runtime-selection.md +39 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/scripts.md +141 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/self-hosting.md +371 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/suspense-boundaries.md +67 -0
- package/dist/skills/frameworks/nextjs/next-cache-components/SKILL.md +360 -0
- package/dist/skills/frameworks/react/async-react-patterns/SKILL.md +78 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/AGENTS.md +946 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/SKILL.md +89 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/AGENTS.md +3750 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/SKILL.md +148 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/trpc/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/trpc/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/trpc/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/trpc/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/trpc/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/turborepo/turborepo/SKILL.md +914 -0
- package/dist/skills/frameworks/turborepo/turborepo/command/turborepo.md +70 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/RULE.md +241 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/dependencies.md +246 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/packages.md +335 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/structure.md +270 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/boundaries/RULE.md +126 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/RULE.md +107 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/gotchas.md +169 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/remote-cache.md +127 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/RULE.md +79 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/github-actions.md +162 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/patterns.md +145 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/vercel.md +103 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/RULE.md +100 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/commands.md +297 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/RULE.md +211 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/global-options.md +187 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/gotchas.md +348 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/tasks.md +285 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/RULE.md +96 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/gotchas.md +141 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/modes.md +101 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/RULE.md +148 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/patterns.md +152 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/watch/RULE.md +99 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/README.md +20 -0
- package/docs/reference/dp-requirements.md +210 -0
- package/docs/runbooks/dp-cli-scaffolding.md +187 -0
- package/package.json +24 -50
- package/.eslintignore +0 -4
- package/.eslintrc +0 -127
- package/.prettierignore +0 -4
- package/.prettierrc +0 -7
- package/bin/abstractions/builder.d.ts +0 -4
- package/bin/abstractions/builder.js +0 -7
- package/bin/builders/dotnet/base.d.ts +0 -18
- package/bin/builders/dotnet/base.js +0 -47
- package/bin/builders/dotnet/entity-configuration/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-configuration/index.js +0 -29
- package/bin/builders/dotnet/entity-converter/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-converter/index.js +0 -29
- package/bin/builders/dotnet/entity-model-create/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-create/index.js +0 -29
- package/bin/builders/dotnet/entity-model-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-list-item-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-list-item-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-update/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-update/index.js +0 -29
- package/bin/builders/dotnet/entity-search-parameters/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-parameters/index.js +0 -29
- package/bin/builders/dotnet/entity-search-query-builder/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-query-builder/index.js +0 -29
- package/bin/builders/dotnet/firestore-connector/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-connector/index.js +0 -29
- package/bin/builders/dotnet/firestore-mapper/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-mapper/index.js +0 -29
- package/bin/builders/dotnet/types.d.ts +0 -10
- package/bin/builders/dotnet/types.js +0 -3
- package/bin/commands/entity-add/__test__/dotnet/common.d.ts +0 -2
- package/bin/commands/entity-add/__test__/dotnet/common.js +0 -11
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.js +0 -22
- package/bin/commands/entity-add/index.d.ts +0 -26
- package/bin/commands/entity-add/index.js +0 -44
- package/bin/logging/index.d.ts +0 -8
- package/bin/logging/index.js +0 -28
- package/bin/providers/rendering/base.d.ts +0 -3
- package/bin/providers/rendering/base.js +0 -7
- package/bin/providers/rendering/factory.d.ts +0 -5
- package/bin/providers/rendering/factory.js +0 -16
- package/bin/providers/rendering/handlebars.d.ts +0 -4
- package/bin/providers/rendering/handlebars.js +0 -16
- package/bin/renderer/index.d.ts +0 -6
- package/bin/renderer/index.js +0 -27
- package/bin/run.d.ts +0 -2
- package/bin/run.js +0 -70
- package/bin/services/folders.d.ts +0 -1
- package/bin/services/folders.js +0 -31
- package/bin/types/commands.d.ts +0 -5
- package/bin/types/commands.js +0 -3
- package/bin/utils/collections.d.ts +0 -1
- package/bin/utils/collections.js +0 -6
- package/bin/utils/files.d.ts +0 -3
- package/bin/utils/files.js +0 -19
- package/bin/utils/strings.d.ts +0 -4
- package/bin/utils/strings.js +0 -22
- package/bin/utils/text.d.ts +0 -1
- package/bin/utils/text.js +0 -8
- package/em-cli +0 -0
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.configuration.spec.ts.snap +0 -49
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.converter.spec.ts.snap +0 -53
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-connector.spec.ts.snap +0 -20
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-mapper.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-create.spec.ts.snap +0 -10
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-dto.spec.ts.snap +0 -9
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-list-item-dto.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-update.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-parameters.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-query.spec.ts.snap +0 -42
- package/templates/dotnet/NewEntity/Configuration/<PluralizedEntity>Configuration.cs.template +0 -48
- package/templates/dotnet/NewEntity/Connectors/<PluralizedEntity>FirestoreConnector.cs.template +0 -15
- package/templates/dotnet/NewEntity/Converters/<PluralizedEntity>Converter.cs.template +0 -48
- package/templates/dotnet/NewEntity/Mappers/<PluralizedEntity>FirestoreMapper.cs.template +0 -25
- package/templates/dotnet/NewEntity/Models/<Entity>CreateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>Dto.cs.template +0 -5
- package/templates/dotnet/NewEntity/Models/<Entity>ListItemDto.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>UpdateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>QueryBuilder.cs.template +0 -38
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>SearchParameters.cs.template +0 -24
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Effect-Atom Patterns Checklist
|
|
2
|
+
|
|
3
|
+
Effect-Atom (`@effect-atom/atom-react`) is the standard way to handle data fetching, mutations, and server state in React components in this codebase. If new UI code is NOT using Effect-Atom, recommend adopting it.
|
|
4
|
+
|
|
5
|
+
## Package & Imports
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Atom, AtomHttpApi, Result, Registry, RegistryContext } from "@effect-atom/atom-react"
|
|
9
|
+
import { AtomRpc } from "@effect-atom/atom-react"
|
|
10
|
+
import { useAtom, useAtomValue, useAtomSet, useAtomRefresh } from "@effect-atom/atom-react"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 1. Use Typesafe Clients (AtomHttpApi or AtomRpc)
|
|
14
|
+
|
|
15
|
+
API calls to **our own Effect HttpApi or Effect RPC backends** should go through a **typesafe client** — `AtomHttpApi.Tag` for Effect HttpApi backends or `AtomRpc.Tag` for Effect RPC backends. This gives end-to-end type safety from the server schema to the client. Raw `fetch`/`axios` is acceptable for third-party/external APIs or non-Effect backends.
|
|
16
|
+
|
|
17
|
+
### HTTP API Client (AtomHttpApi)
|
|
18
|
+
|
|
19
|
+
For REST-style APIs defined with `HttpApi` from `@effect/platform`:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Define a typesafe client bound to your API schema
|
|
23
|
+
export class ApiClient extends AtomHttpApi.Tag<ApiClient>()(
|
|
24
|
+
"@myorg/web/ApiClient",
|
|
25
|
+
{
|
|
26
|
+
api: MyApi, // Your HttpApi definition (provides full type safety)
|
|
27
|
+
httpClient: AuthClient, // Pre-configured HTTP client with auth
|
|
28
|
+
baseUrl: API_BASE,
|
|
29
|
+
}
|
|
30
|
+
) {}
|
|
31
|
+
|
|
32
|
+
// Queries and mutations are fully typed from the API schema
|
|
33
|
+
export const usersAtom = ApiClient.query("users", "listUsers", { ... })
|
|
34
|
+
export const createUserMutation = ApiClient.mutation("users", "createUser")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### RPC Client (AtomRpc)
|
|
38
|
+
|
|
39
|
+
For Effect RPC services — provides end-to-end type safety from server to client:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
export class UsersClient extends AtomRpc.Tag<UsersClient>()(
|
|
43
|
+
"@myorg/web/UsersClient",
|
|
44
|
+
{
|
|
45
|
+
group: UsersRpcGroup,
|
|
46
|
+
protocol: makeProtocolLayer("/rpc/users"),
|
|
47
|
+
}
|
|
48
|
+
) {}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### What to Flag
|
|
52
|
+
|
|
53
|
+
Only flag raw fetch/axios when targeting **our own Effect HttpApi or Effect RPC backends** where a typesafe client can derive types from the server schema. Calls to external APIs or non-Effect backends are fine.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// BAD — raw fetch to our own API, no type safety
|
|
57
|
+
const res = await fetch("/api/users", { method: "POST", body: JSON.stringify(data) })
|
|
58
|
+
const users = await res.json() // `any` type, no validation
|
|
59
|
+
|
|
60
|
+
// FINE — external third-party API, we don't control it
|
|
61
|
+
const res = await fetch("https://api.stripe.com/v1/customers", { ... })
|
|
62
|
+
|
|
63
|
+
// GOOD — typesafe client for our own API
|
|
64
|
+
export const usersAtom = ApiClient.query("users", "listUsers", { timeToLive: "5 minutes" })
|
|
65
|
+
export const createUserMutation = ApiClient.mutation("users", "createUser")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 2. Query Atoms for Data Fetching
|
|
69
|
+
|
|
70
|
+
Data fetching should use `AtomHttpApi.query()` or an RPC client, NOT `useState` + `useEffect` + `fetch`, and NOT React Query/SWR.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// GOOD — query atom with TTL
|
|
74
|
+
export const usersAtom = ApiClient.query("users", "listUsers", {
|
|
75
|
+
timeToLive: "5 minutes",
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Parameterized query — function returning atom
|
|
79
|
+
export const userAtom = (userId: UserId) =>
|
|
80
|
+
ApiClient.query("users", "getUser", {
|
|
81
|
+
urlParams: { user_id: userId },
|
|
82
|
+
timeToLive: "3 minutes",
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// BAD — manual fetch with useState/useEffect
|
|
86
|
+
const [users, setUsers] = useState([])
|
|
87
|
+
const [loading, setLoading] = useState(true)
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
fetch("/api/users").then(res => res.json()).then(setUsers).finally(() => setLoading(false))
|
|
90
|
+
}, [])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 3. Mutation Atoms for Write Operations
|
|
94
|
+
|
|
95
|
+
Mutations should use `AtomHttpApi.mutation()`.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// GOOD
|
|
99
|
+
export const createUserMutation = ApiClient.mutation("users", "createUser")
|
|
100
|
+
export const deleteUserMutation = ApiClient.mutation("users", "deleteUser")
|
|
101
|
+
|
|
102
|
+
// BAD — manual fetch POST
|
|
103
|
+
const handleCreate = async () => {
|
|
104
|
+
const res = await fetch("/api/users", { method: "POST", body: JSON.stringify(data) })
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 4. Consuming Queries — useAtomValue + Result.builder
|
|
109
|
+
|
|
110
|
+
Read query results with `useAtomValue`. Render states with `Result.builder()`.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// GOOD
|
|
114
|
+
function UsersList() {
|
|
115
|
+
const result = useAtomValue(usersAtom)
|
|
116
|
+
|
|
117
|
+
return Result.builder(result)
|
|
118
|
+
.onInitialOrWaiting(() => <Loading />)
|
|
119
|
+
.onFailure((error) => <ErrorDisplay message={String(error)} />)
|
|
120
|
+
.onSuccess((response) => (
|
|
121
|
+
<ul>{response.data.map(u => <li key={u.id}>{u.name}</li>)}</ul>
|
|
122
|
+
))
|
|
123
|
+
.render()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// BAD — manual state matching
|
|
127
|
+
function UsersList() {
|
|
128
|
+
const result = useAtomValue(usersAtom)
|
|
129
|
+
if (result.waiting) return <Loading />
|
|
130
|
+
if (Result.isFailure(result)) return <Error />
|
|
131
|
+
return <ul>...</ul>
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 5. Consuming Mutations — useAtom with Promise Mode
|
|
136
|
+
|
|
137
|
+
Use `useAtom(mutation, { mode: "promise" })` for mutations. Derive loading from `result.waiting`, NOT `useState`.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// GOOD
|
|
141
|
+
const [result, mutate] = useAtom(createUserMutation, { mode: "promise" })
|
|
142
|
+
const isLoading = result.waiting
|
|
143
|
+
|
|
144
|
+
const handleSubmit = async () => {
|
|
145
|
+
try {
|
|
146
|
+
await mutate({ payload: formData })
|
|
147
|
+
onSuccess?.()
|
|
148
|
+
} catch (err) {
|
|
149
|
+
showError(err)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
<Button disabled={isLoading}>
|
|
154
|
+
{isLoading ? "Creating..." : "Create"}
|
|
155
|
+
</Button>
|
|
156
|
+
|
|
157
|
+
// BAD — useState for loading
|
|
158
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
159
|
+
const handleSubmit = async () => {
|
|
160
|
+
setIsLoading(true)
|
|
161
|
+
try { await mutate({ payload }) } finally { setIsLoading(false) }
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## 6. useAtomSet for Fire-and-Forget Mutations
|
|
166
|
+
|
|
167
|
+
When you only need the mutate function without tracking result state:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// GOOD — multiple mutations, no state tracking needed
|
|
171
|
+
const setCreate = useAtomSet(createMutation, { mode: "promise" })
|
|
172
|
+
const setUpdate = useAtomSet(updateMutation, { mode: "promise" })
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## 7. Cache Invalidation — useAtomRefresh
|
|
176
|
+
|
|
177
|
+
Invalidate query caches after mutations with `useAtomRefresh`. NOT manual refetch logic.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// GOOD
|
|
181
|
+
const refreshUsers = useAtomRefresh(usersAtom)
|
|
182
|
+
|
|
183
|
+
const handleCreate = async () => {
|
|
184
|
+
await mutate({ payload })
|
|
185
|
+
refreshUsers() // Invalidate and refetch
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// BAD — manual refetch state
|
|
189
|
+
const [refetchKey, setRefetchKey] = useState(0)
|
|
190
|
+
const handleCreate = async () => {
|
|
191
|
+
await createUser(data)
|
|
192
|
+
setRefetchKey(k => k + 1) // Force re-render
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 8. Derived/Computed Atoms — Atom.make
|
|
197
|
+
|
|
198
|
+
Combine multiple atoms into derived state with `Atom.make()`:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// GOOD
|
|
202
|
+
export const dashboardAtom = (appId: ApplicationId) => {
|
|
203
|
+
const usersAtom = chartDataAtom(appId, { metric: "users" })
|
|
204
|
+
const revenueAtom = chartDataAtom(appId, { metric: "revenue" })
|
|
205
|
+
|
|
206
|
+
return Atom.make((get) => {
|
|
207
|
+
const combined = Result.all({
|
|
208
|
+
users: get(usersAtom),
|
|
209
|
+
revenue: get(revenueAtom),
|
|
210
|
+
})
|
|
211
|
+
return Result.map(combined, ({ users, revenue }) => ({
|
|
212
|
+
totalUsers: users.total,
|
|
213
|
+
totalRevenue: revenue.total,
|
|
214
|
+
}))
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 9. Dialog Pattern
|
|
220
|
+
|
|
221
|
+
Dialogs own their mutation hooks internally. Parent passes data props and `onOpenChange`/`onSuccess` callbacks.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// GOOD — dialog owns mutation
|
|
225
|
+
function CreateUserDialog({ open, onOpenChange, organizationId }: Props) {
|
|
226
|
+
const [result, mutate] = useAtom(createUserMutation, { mode: "promise" })
|
|
227
|
+
const isLoading = result.waiting
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
231
|
+
<form onSubmit={() => mutate({ payload: { organizationId, ...formData } })}>
|
|
232
|
+
<Button disabled={isLoading}>{isLoading ? "Creating..." : "Create"}</Button>
|
|
233
|
+
</form>
|
|
234
|
+
</Dialog>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// BAD — parent passes mutation handler
|
|
239
|
+
function CreateUserDialog({ open, onOpenChange, onSubmit, isLoading }: Props) {
|
|
240
|
+
return (
|
|
241
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
242
|
+
<form onSubmit={onSubmit}>
|
|
243
|
+
<Button disabled={isLoading}>Create</Button>
|
|
244
|
+
</form>
|
|
245
|
+
</Dialog>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## What to Flag
|
|
251
|
+
|
|
252
|
+
- **Critical**: Raw `fetch`/`axios` calls to **our own Effect HttpApi/RPC backends** without a typesafe client (should use `AtomHttpApi` or `AtomRpc`). External APIs or non-Effect backends are fine.
|
|
253
|
+
- **Critical**: `useState` + `useEffect` + `fetch` for data fetching (should use Effect-Atom query atoms)
|
|
254
|
+
- **Critical**: `useState` for loading state when an atom mutation is available (`result.waiting`)
|
|
255
|
+
- **Warning**: Manual if/else for result states instead of `Result.builder()`
|
|
256
|
+
- **Warning**: Missing `useAtomRefresh` after mutations that affect visible queries
|
|
257
|
+
- **Info**: Recommend Effect-Atom if component uses React Query, SWR, or manual fetch patterns
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Effect Primitives Checklist
|
|
2
|
+
|
|
3
|
+
## 1. Effect Array/HashMap Over Native
|
|
4
|
+
|
|
5
|
+
Use `Array` from `effect` for functional array operations in Effect code. Use `HashMap` for key-value lookups instead of plain objects or `Map`.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// GOOD
|
|
9
|
+
import { Array, HashMap } from "effect"
|
|
10
|
+
const ids = Array.map(items, (item) => item.id)
|
|
11
|
+
const lookup = HashMap.fromIterable(items.map((i) => [i.id, i]))
|
|
12
|
+
|
|
13
|
+
// BAD
|
|
14
|
+
const ids = items.map((item) => item.id) // native .map in Effect service code
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. Effect.forEach Over For Loops
|
|
18
|
+
|
|
19
|
+
Any loop body that performs an Effect must use `Effect.forEach`. Supports `concurrency` option for parallel execution.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// GOOD
|
|
23
|
+
yield* Effect.forEach(users, (user) => sendNotification(user), { concurrency: 5 })
|
|
24
|
+
|
|
25
|
+
// BAD
|
|
26
|
+
for (const user of users) {
|
|
27
|
+
yield* sendNotification(user)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 3. Match Over Switch Statements
|
|
32
|
+
|
|
33
|
+
All `switch` statements on discriminated unions or string literals should use `Match.value()` or `Match.type<T>()` with `Match.exhaustive`.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// GOOD
|
|
37
|
+
import { Match } from "effect"
|
|
38
|
+
const result = Match.value(platform).pipe(
|
|
39
|
+
Match.when("IOS", () => "ios" as const),
|
|
40
|
+
Match.when("ANDROID", () => "android" as const),
|
|
41
|
+
Match.exhaustive
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// BAD
|
|
45
|
+
switch (platform) {
|
|
46
|
+
case "IOS": return "ios"
|
|
47
|
+
case "ANDROID": return "android"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 4. Option Over Optional Chaining
|
|
52
|
+
|
|
53
|
+
In Effect services and domain types, prefer `Option<T>` over `T | null | undefined`. Use `Option.match`, `Option.map`, `Option.getOrElse` instead of `?.` chains.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// GOOD
|
|
57
|
+
import { Option } from "effect"
|
|
58
|
+
const name = Option.match(user.displayName, {
|
|
59
|
+
onNone: () => "Anonymous",
|
|
60
|
+
onSome: (name) => name
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// BAD
|
|
64
|
+
const name = user?.displayName ?? "Anonymous" // in Effect service code
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Note: `?.` is acceptable in React components and non-Effect utility code. Flag it only in Effect services/repositories/handlers.
|
|
68
|
+
|
|
69
|
+
## 5. Effect Schema Over Zod/Manual Validation
|
|
70
|
+
|
|
71
|
+
All runtime validation should use `Schema` from `effect`. No Zod imports. No manual `typeof`/`instanceof` guards for data parsing.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// GOOD
|
|
75
|
+
import { Schema } from "effect"
|
|
76
|
+
const UserInput = Schema.Struct({
|
|
77
|
+
name: Schema.String,
|
|
78
|
+
email: Schema.String.pipe(Schema.pattern(/@/)),
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// BAD
|
|
82
|
+
import { z } from "zod"
|
|
83
|
+
const UserInput = z.object({ name: z.string() })
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 6. Layer.provide Not Effect.provide
|
|
87
|
+
|
|
88
|
+
Dependencies should be composed via `Layer` in service definitions and layer files, not via `Effect.provide` at call sites. Exception: final runner/test boundaries and infrastructure bindings in entry points.
|
|
89
|
+
|
|
90
|
+
Keep requirements visible. If a function needs a repository, client, flag service, clock, config, or runtime binding, that need should appear as an Effect environment requirement or an `Effect.Service` dependency until a layer provides it.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// GOOD
|
|
94
|
+
export class MyService extends Effect.Service<MyService>()("MyService", {
|
|
95
|
+
dependencies: [DepA.Default, DepB.Default],
|
|
96
|
+
effect: Effect.gen(function* () { ... })
|
|
97
|
+
}) {}
|
|
98
|
+
|
|
99
|
+
// Also GOOD (Layer.provide chain)
|
|
100
|
+
const MainLayer = ServiceA.Default.pipe(
|
|
101
|
+
Layer.provideMerge(ServiceB.Default),
|
|
102
|
+
Layer.provide(Database)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
// BAD (providing at call site)
|
|
106
|
+
const result = yield* myEffect.pipe(Effect.provide(someLayer))
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 7. No try/catch
|
|
110
|
+
|
|
111
|
+
Everything uses Effect error channel. No `try { } catch { }` blocks in Effect code.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// GOOD
|
|
115
|
+
yield* Effect.tryPromise({
|
|
116
|
+
try: () => fetch(url),
|
|
117
|
+
catch: (e) => new FetchError({ cause: e })
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// BAD
|
|
121
|
+
try {
|
|
122
|
+
const res = await fetch(url)
|
|
123
|
+
} catch (e) {
|
|
124
|
+
throw new Error("fetch failed")
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 8. No Promise-Based Code
|
|
129
|
+
|
|
130
|
+
Service methods return `Effect`, not `Promise`. No `async/await` in Effect service implementations.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// GOOD
|
|
134
|
+
const fetchUser = Effect.fn("fetchUser")(function* (id: UserId) {
|
|
135
|
+
const user = yield* userRepo.findById(id)
|
|
136
|
+
return user
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// BAD
|
|
140
|
+
const fetchUser = async (id: string) => {
|
|
141
|
+
const user = await userRepo.findById(id)
|
|
142
|
+
return user
|
|
143
|
+
}
|
|
144
|
+
```
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Error Patterns Checklist
|
|
2
|
+
|
|
3
|
+
## 1. Schema.TaggedError With HTTP Annotations
|
|
4
|
+
|
|
5
|
+
All errors reaching HTTP boundaries must use `Schema.TaggedError` with `HttpApiSchema.annotations`.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// GOOD
|
|
9
|
+
export class ResourceNotFound extends Schema.TaggedError<ResourceNotFound>()(
|
|
10
|
+
"@myorg/api/errors/ResourceNotFound",
|
|
11
|
+
{
|
|
12
|
+
type: Schema.optionalWith(ErrorType, { default: () => "invalid_request_error" as const }),
|
|
13
|
+
code: Schema.optionalWith(ErrorCode, { default: () => "resource_missing" as const }),
|
|
14
|
+
message: Schema.optionalWith(Schema.String, {
|
|
15
|
+
default: () => "The requested resource was not found.",
|
|
16
|
+
}),
|
|
17
|
+
param: Schema.String.pipe(Schema.optional),
|
|
18
|
+
resource_type: Schema.String.pipe(Schema.optional),
|
|
19
|
+
resource_id: Schema.String.pipe(Schema.optional),
|
|
20
|
+
},
|
|
21
|
+
HttpApiSchema.annotations({ status: 404, title: "Resource Not Found" })
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
// BAD
|
|
25
|
+
class NotFoundError extends Error {
|
|
26
|
+
constructor(message: string) { super(message) }
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 2. Reverse Domain Notation for Tags
|
|
31
|
+
|
|
32
|
+
Error tags should use reverse domain notation matching the package structure.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// GOOD
|
|
36
|
+
"@myorg/api/errors/ResourceNotFound"
|
|
37
|
+
"@myorg/subscriptions/errors/CheckoutInitiation"
|
|
38
|
+
|
|
39
|
+
// BAD
|
|
40
|
+
"ResourceNotFound"
|
|
41
|
+
"NotFoundError"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 3. Static Factory Methods
|
|
45
|
+
|
|
46
|
+
Errors should have convenience constructors for common cases.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// GOOD
|
|
50
|
+
export class ResourceNotFound extends Schema.TaggedError<ResourceNotFound>()(...) {
|
|
51
|
+
static fromId(resourceType: string, id: string) {
|
|
52
|
+
return new ResourceNotFound({
|
|
53
|
+
message: `No such ${resourceType}: '${id}'`,
|
|
54
|
+
param: "id",
|
|
55
|
+
resource_type: resourceType,
|
|
56
|
+
resource_id: id,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class BadRequestError extends Schema.TaggedError<BadRequestError>()(...) {
|
|
62
|
+
static invalidParam(param: string, message: string) {
|
|
63
|
+
return new BadRequestError({ code: "parameter_invalid", message, param })
|
|
64
|
+
}
|
|
65
|
+
static missingParam(param: string) {
|
|
66
|
+
return new BadRequestError({
|
|
67
|
+
code: "parameter_missing",
|
|
68
|
+
message: `Missing required parameter: ${param}`,
|
|
69
|
+
param,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 4. Rich Context Fields
|
|
76
|
+
|
|
77
|
+
Errors must include enough context for debugging. Never lose valuable information.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// GOOD - preserves context
|
|
81
|
+
new PaymentProcessingError({
|
|
82
|
+
message: `Failed to process payment for subscription ${subscriptionId}`,
|
|
83
|
+
subscriptionId,
|
|
84
|
+
provider,
|
|
85
|
+
cause: originalError,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// BAD - loses info
|
|
89
|
+
new PaymentProcessingError({ message: "Payment failed" })
|
|
90
|
+
new Error("something went wrong")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 5. catchTag/catchTags Only
|
|
94
|
+
|
|
95
|
+
Never use `catchAll` or `mapError`. Always handle specific error tags.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// GOOD
|
|
99
|
+
yield* effect.pipe(
|
|
100
|
+
Effect.catchTag("DatabaseError", (e) =>
|
|
101
|
+
Effect.fail(ResourceNotFound.fromId("paywall", String(id)))
|
|
102
|
+
),
|
|
103
|
+
Effect.catchTag("ValidationError", (e) =>
|
|
104
|
+
Effect.fail(BadRequestError.invalidParam("input", e.message))
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
// BAD
|
|
109
|
+
yield* effect.pipe(
|
|
110
|
+
Effect.catchAll((e) => Effect.fail(new InternalError({ message: String(e) })))
|
|
111
|
+
)
|
|
112
|
+
yield* effect.pipe(
|
|
113
|
+
Effect.mapError((e) => new InternalError({ message: "failed" }))
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 6. Explicit Error Types
|
|
118
|
+
|
|
119
|
+
Error types should be specific to the domain, not generic. The error channel should tell you exactly what went wrong.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// GOOD
|
|
123
|
+
Effect<Paywall, PaywallNotFoundError | PaywallArchived | Unauthorized>
|
|
124
|
+
|
|
125
|
+
// BAD
|
|
126
|
+
Effect<Paywall, Error>
|
|
127
|
+
Effect<Paywall, unknown>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 7. Don't Catch HTTP-Annotated Errors
|
|
131
|
+
|
|
132
|
+
Let errors with `HttpApiSchema.annotations` propagate to the HTTP layer for automatic status code mapping. Don't re-wrap them.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// GOOD - let ResourceNotFound propagate
|
|
136
|
+
yield* paywallRepo.findById(id)
|
|
137
|
+
|
|
138
|
+
// BAD - catching and re-wrapping
|
|
139
|
+
yield* paywallRepo.findById(id).pipe(
|
|
140
|
+
Effect.catchTag("ResourceNotFound", () =>
|
|
141
|
+
Effect.fail(new GenericError({ message: "not found" }))
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 8. Fire-and-Forget for Non-Critical Operations
|
|
147
|
+
|
|
148
|
+
For operations that shouldn't fail the request, use `Effect.tapError` + `Effect.ignore`:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// GOOD
|
|
152
|
+
yield* db.execute(...).pipe(
|
|
153
|
+
Effect.tapError((e) => Effect.logWarning("Failed to update", { error: e })),
|
|
154
|
+
Effect.ignore
|
|
155
|
+
)
|
|
156
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# OTEL / Observability Patterns Checklist
|
|
2
|
+
|
|
3
|
+
## 1. Effect.fn With Trace Names
|
|
4
|
+
|
|
5
|
+
`Effect.fn` replaces the pattern where an arrow function wraps `Effect.gen`. It does NOT apply to bare `Effect.gen` calls without a wrapping function. It also does NOT apply in `.test.ts` files.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// BAD — arrow function wrapping Effect.gen, should use Effect.fn
|
|
9
|
+
const findById = (productId: ProductId) => Effect.gen(function* () {
|
|
10
|
+
// no trace name, anonymous span
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// GOOD — Effect.fn replaces the arrow function wrapper
|
|
14
|
+
const findById = Effect.fn("ProductRepository.findById")(function* (
|
|
15
|
+
productId: ProductId,
|
|
16
|
+
organizationId: OrganizationId
|
|
17
|
+
) {
|
|
18
|
+
yield* Effect.annotateCurrentSpan("productId", productId)
|
|
19
|
+
// ...
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// FINE — bare Effect.gen without wrapping function, no Effect.fn needed
|
|
23
|
+
yield* Effect.gen(function* () {
|
|
24
|
+
const user = yield* UserService
|
|
25
|
+
// inline composition, not a named function
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Naming Convention
|
|
30
|
+
|
|
31
|
+
Follow `ServiceName.methodName` format consistently:
|
|
32
|
+
- `UserService.findById`
|
|
33
|
+
- `PaywallRepository.create`
|
|
34
|
+
- `CampaignService.createTrigger`
|
|
35
|
+
- `OrgResolver.resolveProjectAccess`
|
|
36
|
+
|
|
37
|
+
## 2. annotateCurrentSpan With Essential Data
|
|
38
|
+
|
|
39
|
+
Annotate spans with entity IDs and key business values. Don't over-annotate with internal state or step-by-step progress.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// GOOD - essential IDs and context
|
|
43
|
+
yield* Effect.annotateCurrentSpan("applicationId", applicationId)
|
|
44
|
+
yield* Effect.annotateCurrentSpan("paywallId", paywallId)
|
|
45
|
+
yield* Effect.annotateCurrentSpan("action", "create")
|
|
46
|
+
|
|
47
|
+
// BAD - over-annotating
|
|
48
|
+
yield* Effect.annotateCurrentSpan("step", "1")
|
|
49
|
+
yield* Effect.annotateCurrentSpan("loopIndex", i)
|
|
50
|
+
yield* Effect.annotateCurrentSpan("intermediateResult", JSON.stringify(result))
|
|
51
|
+
|
|
52
|
+
// BAD - sensitive data
|
|
53
|
+
yield* Effect.annotateCurrentSpan("apiKey", apiKey)
|
|
54
|
+
yield* Effect.annotateCurrentSpan("userEmail", email)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### What to Annotate
|
|
58
|
+
|
|
59
|
+
- Entity IDs (applicationId, paywallId, userId, etc.)
|
|
60
|
+
- Action being performed (create, update, delete)
|
|
61
|
+
- Key discriminators (platform, provider, scope)
|
|
62
|
+
- Counts (itemCount, resultCount) when relevant
|
|
63
|
+
|
|
64
|
+
### What NOT to Annotate
|
|
65
|
+
|
|
66
|
+
- PII (emails, names, addresses)
|
|
67
|
+
- Secrets (API keys, tokens)
|
|
68
|
+
- Large payloads (full request/response bodies)
|
|
69
|
+
- Step-by-step progress counters
|
|
70
|
+
|
|
71
|
+
## 3. Structured Logging
|
|
72
|
+
|
|
73
|
+
Use `Effect.log` / `Effect.logInfo` / `Effect.logWarning` / `Effect.logError` with structured data. Never use `console.log`.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// GOOD
|
|
77
|
+
yield* Effect.logInfo("Processing payment").pipe(
|
|
78
|
+
Effect.annotateLogs({ orderId, amount, provider })
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
// BAD
|
|
82
|
+
console.log(`Processing payment for order ${orderId}`)
|
|
83
|
+
console.log("Payment result:", result)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 4. Error Spans
|
|
87
|
+
|
|
88
|
+
Errors should carry enough context for debugging without needing to look at other spans. Include entity IDs and operation context in error construction.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// GOOD
|
|
92
|
+
new ResourceNotFound({
|
|
93
|
+
message: `No such paywall: '${paywallId}'`,
|
|
94
|
+
resource_type: "paywall",
|
|
95
|
+
resource_id: String(paywallId),
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// BAD
|
|
99
|
+
new ResourceNotFound({ message: "Not found" })
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 5. Effect.withSpan for Non-fn Contexts
|
|
103
|
+
|
|
104
|
+
When `Effect.fn` isn't appropriate (inline pipelines, one-off compositions), use `Effect.withSpan`:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// GOOD
|
|
108
|
+
const result = yield* someEffect.pipe(
|
|
109
|
+
Effect.withSpan("OrgResolver.fromProject", {
|
|
110
|
+
attributes: { projectId, scope }
|
|
111
|
+
})
|
|
112
|
+
)
|
|
113
|
+
```
|