@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
package/dist/skills/frameworks/effect/effect-best-practices/references/effect-atom-patterns.md
ADDED
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
# Effect Atom Patterns
|
|
2
|
+
|
|
3
|
+
Effect Atom is a reactive state management library that integrates with Effect-TS. It provides atoms (reactive containers), automatic dependency tracking, and seamless React integration.
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
|
|
7
|
+
- **Atoms**: Reactive state containers with automatic dependency tracking
|
|
8
|
+
- **Result**: Handles async/effectful computations with initial, success, and failure states
|
|
9
|
+
- **Finalizers**: Built-in cleanup for resources and event listeners
|
|
10
|
+
- **Families**: Dynamic atom creation for per-entity state
|
|
11
|
+
|
|
12
|
+
## Creating Atoms
|
|
13
|
+
|
|
14
|
+
### Basic Atoms
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Atom } from "@effect-atom/atom-react"
|
|
18
|
+
|
|
19
|
+
// Simple value atom
|
|
20
|
+
const countAtom = Atom.make(0)
|
|
21
|
+
|
|
22
|
+
// With keepAlive - persists when no components subscribe
|
|
23
|
+
const persistentCountAtom = Atom.make(0).pipe(Atom.keepAlive)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Rule:** Use `Atom.keepAlive` for global state that should persist across component unmounts.
|
|
27
|
+
|
|
28
|
+
### Derived Atoms
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const countAtom = Atom.make(0)
|
|
32
|
+
|
|
33
|
+
// Derived using get function
|
|
34
|
+
const doubleCountAtom = Atom.make((get) => get(countAtom) * 2)
|
|
35
|
+
|
|
36
|
+
// Derived using Atom.map
|
|
37
|
+
const tripleCountAtom = Atom.map(countAtom, (count) => count * 3)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Atoms with Side Effects
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Track window scroll position
|
|
44
|
+
const scrollYAtom = Atom.make((get) => {
|
|
45
|
+
const onScroll = () => get.setSelf(window.scrollY)
|
|
46
|
+
|
|
47
|
+
window.addEventListener("scroll", onScroll)
|
|
48
|
+
get.addFinalizer(() => window.removeEventListener("scroll", onScroll))
|
|
49
|
+
|
|
50
|
+
return window.scrollY
|
|
51
|
+
}).pipe(Atom.keepAlive)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Critical:**
|
|
55
|
+
- Use `get.setSelf` to update the atom's own value
|
|
56
|
+
- Always add finalizers with `get.addFinalizer()` to clean up side effects
|
|
57
|
+
- Finalizers run when the atom is rebuilt or disposed
|
|
58
|
+
|
|
59
|
+
### Atom.transform for Self-Updating Derived State
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const resolvedThemeAtom = Atom.transform(themeAtom, (get) => {
|
|
63
|
+
const theme = get(themeAtom)
|
|
64
|
+
if (theme !== "system") return theme
|
|
65
|
+
|
|
66
|
+
const matcher = window.matchMedia("(prefers-color-scheme: dark)")
|
|
67
|
+
|
|
68
|
+
const onChange = () => get.setSelf(matcher.matches ? "dark" : "light")
|
|
69
|
+
|
|
70
|
+
matcher.addEventListener("change", onChange)
|
|
71
|
+
get.addFinalizer(() => matcher.removeEventListener("change", onChange))
|
|
72
|
+
|
|
73
|
+
return matcher.matches ? "dark" : "light"
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Atom Families
|
|
78
|
+
|
|
79
|
+
Use `Atom.family` for per-entity state:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { Atom } from "@effect-atom/atom-react"
|
|
83
|
+
|
|
84
|
+
// Create a family of atoms - one per channelId
|
|
85
|
+
const replyToMessageAtomFamily = Atom.family((channelId: string) =>
|
|
86
|
+
Atom.make<string | null>(null).pipe(Atom.keepAlive)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
// Modal state family
|
|
90
|
+
type ModalType = "settings" | "confirm" | "create"
|
|
91
|
+
|
|
92
|
+
interface ModalState {
|
|
93
|
+
type: ModalType
|
|
94
|
+
isOpen: boolean
|
|
95
|
+
metadata?: Record<string, unknown>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const modalAtomFamily = Atom.family((type: ModalType) =>
|
|
99
|
+
Atom.make<ModalState>({
|
|
100
|
+
type,
|
|
101
|
+
isOpen: false,
|
|
102
|
+
metadata: undefined,
|
|
103
|
+
}).pipe(Atom.keepAlive)
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Use families for:**
|
|
108
|
+
- Per-resource state (users, channels, documents)
|
|
109
|
+
- Modal instances
|
|
110
|
+
- Form state per entity
|
|
111
|
+
- Any parameterized state
|
|
112
|
+
|
|
113
|
+
## React Integration
|
|
114
|
+
|
|
115
|
+
### Reading Atom Values
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { useAtomValue } from "@effect-atom/atom-react"
|
|
119
|
+
|
|
120
|
+
function Counter() {
|
|
121
|
+
const count = useAtomValue(countAtom)
|
|
122
|
+
return <span>{count}</span>
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Updating Atom Values
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { useAtomSet } from "@effect-atom/atom-react"
|
|
130
|
+
|
|
131
|
+
function IncrementButton() {
|
|
132
|
+
const setCount = useAtomSet(countAtom)
|
|
133
|
+
return (
|
|
134
|
+
<button onClick={() => setCount((c) => c + 1)}>
|
|
135
|
+
Increment
|
|
136
|
+
</button>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Reading and Writing Together
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { useAtom } from "@effect-atom/atom-react"
|
|
145
|
+
|
|
146
|
+
function CounterControl() {
|
|
147
|
+
const [count, setCount] = useAtom(countAtom)
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
<span>{count}</span>
|
|
151
|
+
<button onClick={() => setCount(count + 1)}>+1</button>
|
|
152
|
+
</div>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Mounting Side-Effect Atoms
|
|
158
|
+
|
|
159
|
+
Use `useAtomMount` to activate atoms without reading their value:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { useAtomMount } from "@effect-atom/atom-react"
|
|
163
|
+
|
|
164
|
+
function App() {
|
|
165
|
+
// Activate side effects without subscribing to value
|
|
166
|
+
useAtomMount(keyboardShortcutsAtom)
|
|
167
|
+
useAtomMount(presenceTrackingAtom)
|
|
168
|
+
useAtomMount(themeApplierAtom)
|
|
169
|
+
|
|
170
|
+
return <>{children}</>
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## React Mutation Patterns
|
|
175
|
+
|
|
176
|
+
### Deriving Loading State from result.waiting
|
|
177
|
+
|
|
178
|
+
When using mutation atoms with `mode: "promise"`, derive loading state from `result.waiting` instead of managing separate `useState`:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const [result, mutate] = useAtom(myMutation, { mode: "promise" })
|
|
182
|
+
const isLoading = result.waiting // No useState needed
|
|
183
|
+
|
|
184
|
+
const handleSubmit = async () => {
|
|
185
|
+
try {
|
|
186
|
+
await mutate(payload)
|
|
187
|
+
onSuccess?.()
|
|
188
|
+
} catch (err) {
|
|
189
|
+
showError(err)
|
|
190
|
+
}
|
|
191
|
+
// No finally - result.waiting updates automatically
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
<Button disabled={isLoading}>{isLoading ? "Loading..." : "Submit"}</Button>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Why this is preferred:**
|
|
198
|
+
- Single source of truth — loading state lives on the Result
|
|
199
|
+
- No `finally` blocks or manual state resets
|
|
200
|
+
- Automatically synchronized with the mutation lifecycle
|
|
201
|
+
|
|
202
|
+
### Dialog Components Own Their Mutations
|
|
203
|
+
|
|
204
|
+
Move mutation logic INTO dialog components rather than keeping it in page components.
|
|
205
|
+
|
|
206
|
+
**Dialog owns:** mutation hook, loading state, toast notifications
|
|
207
|
+
**Parent provides:** data props, `onSuccess` callback
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// CORRECT - dialog owns its mutation
|
|
211
|
+
function ArchivePaywallDialog({
|
|
212
|
+
paywall,
|
|
213
|
+
onSuccess,
|
|
214
|
+
}: {
|
|
215
|
+
paywall: Paywall
|
|
216
|
+
onSuccess?: () => void
|
|
217
|
+
}) {
|
|
218
|
+
const [result, archivePaywall] = useAtom(archivePaywallMutation, { mode: "promise" })
|
|
219
|
+
const isLoading = result.waiting
|
|
220
|
+
|
|
221
|
+
const handleArchive = async () => {
|
|
222
|
+
try {
|
|
223
|
+
await archivePaywall({ paywallId: paywall.id })
|
|
224
|
+
toast.success("Paywall archived")
|
|
225
|
+
onSuccess?.()
|
|
226
|
+
} catch (err) {
|
|
227
|
+
toast.error("Failed to archive paywall")
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<AlertDialog>
|
|
233
|
+
<AlertDialogContent>
|
|
234
|
+
<AlertDialogTitle>Archive "{paywall.name}"?</AlertDialogTitle>
|
|
235
|
+
<AlertDialogFooter>
|
|
236
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
237
|
+
<Button onClick={handleArchive} disabled={isLoading}>
|
|
238
|
+
{isLoading ? "Archiving..." : "Archive"}
|
|
239
|
+
</Button>
|
|
240
|
+
</AlertDialogFooter>
|
|
241
|
+
</AlertDialogContent>
|
|
242
|
+
</AlertDialog>
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Parent just passes data and reacts to success
|
|
247
|
+
function PaywallPage() {
|
|
248
|
+
return <ArchivePaywallDialog paywall={paywall} onSuccess={() => navigate("/paywalls")} />
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### reactivityKeys for Cache Invalidation
|
|
253
|
+
|
|
254
|
+
Mutations can specify `reactivityKeys` to automatically invalidate queries that share the same keys — no manual `refresh()` calls needed.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// Mutation atom with reactivityKeys
|
|
258
|
+
const archivePaywallMutation = Atom.make(
|
|
259
|
+
Effect.fn(function* (payload: { paywallId: string }) {
|
|
260
|
+
yield* paywallService.archive(payload.paywallId)
|
|
261
|
+
}),
|
|
262
|
+
{ reactivityKeys: ["paywalls"] }
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
// Query atom with matching reactivityKeys — auto-invalidated after mutation
|
|
266
|
+
const paywallsAtom = Atom.make(
|
|
267
|
+
Effect.fn(function* () {
|
|
268
|
+
return yield* paywallService.list()
|
|
269
|
+
}),
|
|
270
|
+
{ reactivityKeys: ["paywalls"] }
|
|
271
|
+
)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Rules:**
|
|
275
|
+
- Both the mutation and query must share at least one matching key
|
|
276
|
+
- After the mutation succeeds, all atoms with matching keys re-execute
|
|
277
|
+
- Replaces manual patterns like calling `refreshPaywalls()` after mutations
|
|
278
|
+
|
|
279
|
+
## Working with Effects and Results
|
|
280
|
+
|
|
281
|
+
### Effectful Atoms Return Result
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import { Atom, Result } from "@effect-atom/atom-react"
|
|
285
|
+
import { Effect } from "effect"
|
|
286
|
+
|
|
287
|
+
const userAtom = Atom.make(
|
|
288
|
+
Effect.gen(function* () {
|
|
289
|
+
const response = yield* fetchUser()
|
|
290
|
+
return response
|
|
291
|
+
})
|
|
292
|
+
) // Type: Atom<Result<User, Error>>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Handling Results with Result.builder (Recommended)
|
|
296
|
+
|
|
297
|
+
**Use `Result.builder`** for rendering Result types. It provides a chainable API with granular error handling and type narrowing.
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { Result, useAtomValue } from "@effect-atom/atom-react"
|
|
301
|
+
|
|
302
|
+
function UserProfile() {
|
|
303
|
+
const userResult = useAtomValue(userAtom)
|
|
304
|
+
|
|
305
|
+
return Result.builder(userResult)
|
|
306
|
+
.onInitial(() => <div>Loading...</div>)
|
|
307
|
+
.onError((error) => <div>Error: {error.message}</div>)
|
|
308
|
+
.onSuccess((user) => <div>Hello, {user.name}!</div>)
|
|
309
|
+
.render()
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Result.builder with Tagged Errors
|
|
314
|
+
|
|
315
|
+
**Key advantage**: Handle specific error types with `onErrorTag`:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
function ResourceEmbed({ url }: { url: string }) {
|
|
319
|
+
const resourceResult = useAtomValue(resourceAtom)
|
|
320
|
+
|
|
321
|
+
return Result.builder(resourceResult)
|
|
322
|
+
.onInitial(() => <Skeleton />)
|
|
323
|
+
.onErrorTag("NotFoundError", (error) => (
|
|
324
|
+
<ErrorCard message={error.message} />
|
|
325
|
+
))
|
|
326
|
+
.onErrorTag("UnauthorizedError", () => (
|
|
327
|
+
<ConnectPrompt provider="GitHub" />
|
|
328
|
+
))
|
|
329
|
+
.onErrorTag("RateLimitError", (error) => (
|
|
330
|
+
<RetryCard retryAfter={error.retryAfter} />
|
|
331
|
+
))
|
|
332
|
+
.onError((error) => (
|
|
333
|
+
// Fallback for any other errors
|
|
334
|
+
<ErrorCard message="Something went wrong" />
|
|
335
|
+
))
|
|
336
|
+
.onSuccess((data) => <ResourceCard data={data} />)
|
|
337
|
+
.render()
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Result.builder Methods
|
|
342
|
+
|
|
343
|
+
| Method | Purpose |
|
|
344
|
+
|--------|---------|
|
|
345
|
+
| `onInitial(fn)` | Handle initial/loading state |
|
|
346
|
+
| `onInitialOrWaiting(fn)` | Handle both initial and waiting states |
|
|
347
|
+
| `onWaiting(fn)` | Handle waiting/refetching state |
|
|
348
|
+
| `onSuccess(fn)` | Handle success with value |
|
|
349
|
+
| `onError(fn)` | Handle any error |
|
|
350
|
+
| `onErrorTag(tag, fn)` | Handle specific tagged error (removes from type) |
|
|
351
|
+
| `onErrorIf(predicate, fn)` | Handle errors matching predicate |
|
|
352
|
+
| `onFailure(fn)` | Handle failure with full Cause |
|
|
353
|
+
| `onDefect(fn)` | Handle unexpected defects |
|
|
354
|
+
| `render()` | Return result (null if unhandled initial) |
|
|
355
|
+
| `orElse(fn)` | Provide fallback value |
|
|
356
|
+
| `orNull()` | Return null for unhandled cases |
|
|
357
|
+
|
|
358
|
+
### Extracting Values with orElse
|
|
359
|
+
|
|
360
|
+
For non-rendering use cases, extract values with `orElse`:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
function useRepositories() {
|
|
364
|
+
const reposResult = useAtomValue(repositoriesAtom)
|
|
365
|
+
|
|
366
|
+
// Extract array or empty fallback
|
|
367
|
+
const repositories = Result.builder(reposResult)
|
|
368
|
+
.onSuccess((data) => data.repositories)
|
|
369
|
+
.orElse(() => [])
|
|
370
|
+
|
|
371
|
+
return repositories
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Result.getOrElse for Simple Extraction
|
|
376
|
+
|
|
377
|
+
For simple value extraction without error handling:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
function UserName() {
|
|
381
|
+
const userResult = useAtomValue(userAtom)
|
|
382
|
+
const user = Result.getOrElse(userResult, () => null)
|
|
383
|
+
|
|
384
|
+
if (!user) return <span>Loading...</span>
|
|
385
|
+
return <span>{user.name}</span>
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### When to Use Each Pattern
|
|
390
|
+
|
|
391
|
+
| Pattern | Use Case |
|
|
392
|
+
|---------|----------|
|
|
393
|
+
| `Result.builder` | UI rendering with multiple error types |
|
|
394
|
+
| `Result.builder + onErrorTag` | APIs with tagged errors (HttpApi, RPC) |
|
|
395
|
+
| `Result.builder + orElse` | Extracting values with fallback |
|
|
396
|
+
| `Result.getOrElse` | Simple value extraction |
|
|
397
|
+
| `Result.match` | Simple 3-case exhaustive matching |
|
|
398
|
+
|
|
399
|
+
### Accessing Results in Derived Atoms
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
const userProfileAtom = Atom.make(
|
|
403
|
+
Effect.fnUntraced(function* (get: Atom.Context) {
|
|
404
|
+
// Unwrap Result to get the value (waits for success)
|
|
405
|
+
const user = yield* get.result(userAtom)
|
|
406
|
+
const posts = yield* fetchUserPosts(user.id)
|
|
407
|
+
return { user, posts }
|
|
408
|
+
})
|
|
409
|
+
)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Batching Updates
|
|
413
|
+
|
|
414
|
+
Use `Atom.batch` for multiple updates:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
const openModal = (type: ModalType, metadata?: Record<string, unknown>) => {
|
|
418
|
+
Atom.batch(() => {
|
|
419
|
+
Atom.update(modalAtomFamily(type), (state) => ({
|
|
420
|
+
...state,
|
|
421
|
+
isOpen: true,
|
|
422
|
+
metadata,
|
|
423
|
+
}))
|
|
424
|
+
})
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## localStorage Persistence
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { BrowserKeyValueStore } from "@effect/platform-browser"
|
|
432
|
+
import { Atom } from "@effect-atom/atom-react"
|
|
433
|
+
import { Schema } from "effect"
|
|
434
|
+
|
|
435
|
+
// Create runtime with localStorage
|
|
436
|
+
const localStorageRuntime = Atom.runtime(BrowserKeyValueStore.layerLocalStorage)
|
|
437
|
+
|
|
438
|
+
// Persisted atom with schema validation
|
|
439
|
+
const themeAtom = Atom.kvs({
|
|
440
|
+
runtime: localStorageRuntime,
|
|
441
|
+
key: "app-theme",
|
|
442
|
+
schema: Schema.Literal("dark", "light", "system"),
|
|
443
|
+
defaultValue: () => "system" as const,
|
|
444
|
+
})
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Anti-Patterns
|
|
448
|
+
|
|
449
|
+
### FORBIDDEN: Creating Atoms Inside Components
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// WRONG - creates new atom on every render
|
|
453
|
+
function Counter() {
|
|
454
|
+
const countAtom = Atom.make(0) // New atom each render!
|
|
455
|
+
const count = useAtomValue(countAtom)
|
|
456
|
+
return <div>{count}</div>
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// CORRECT - define atoms outside components
|
|
460
|
+
const countAtom = Atom.make(0)
|
|
461
|
+
|
|
462
|
+
function Counter() {
|
|
463
|
+
const count = useAtomValue(countAtom)
|
|
464
|
+
return <div>{count}</div>
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### FORBIDDEN: Imperative Updates from React Components
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
// WRONG - doesn't trigger React re-renders
|
|
472
|
+
export const openModal = (type: string) => {
|
|
473
|
+
Atom.batch(() => {
|
|
474
|
+
Atom.update(modalAtomFamily(type), (s) => ({ ...s, isOpen: true }))
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function Component() {
|
|
479
|
+
return <button onClick={() => openModal("settings")}>Open</button>
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// CORRECT - use hooks for React integration
|
|
483
|
+
export const useModal = (type: string) => {
|
|
484
|
+
const state = useAtomValue(modalAtomFamily(type))
|
|
485
|
+
const setState = useAtomSet(modalAtomFamily(type))
|
|
486
|
+
|
|
487
|
+
const open = useCallback(() => {
|
|
488
|
+
setState((prev) => ({ ...prev, isOpen: true }))
|
|
489
|
+
}, [setState])
|
|
490
|
+
|
|
491
|
+
const close = useCallback(() => {
|
|
492
|
+
setState((prev) => ({ ...prev, isOpen: false }))
|
|
493
|
+
}, [setState])
|
|
494
|
+
|
|
495
|
+
return { isOpen: state.isOpen, open, close }
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**When imperative updates ARE acceptable:**
|
|
500
|
+
- Event listeners outside React (keyboard shortcuts)
|
|
501
|
+
- Effects running on atom changes
|
|
502
|
+
- Non-UI state (analytics, logging)
|
|
503
|
+
|
|
504
|
+
### FORBIDDEN: Missing Finalizers
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// WRONG - memory leak!
|
|
508
|
+
const scrollAtom = Atom.make((get) => {
|
|
509
|
+
const onScroll = () => get.setSelf(window.scrollY)
|
|
510
|
+
window.addEventListener("scroll", onScroll)
|
|
511
|
+
return window.scrollY
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
// CORRECT - cleanup registered
|
|
515
|
+
const scrollAtom = Atom.make((get) => {
|
|
516
|
+
const onScroll = () => get.setSelf(window.scrollY)
|
|
517
|
+
window.addEventListener("scroll", onScroll)
|
|
518
|
+
get.addFinalizer(() => window.removeEventListener("scroll", onScroll))
|
|
519
|
+
return window.scrollY
|
|
520
|
+
})
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### FORBIDDEN: Missing keepAlive for Global State
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
// WRONG - state resets when component unmounts
|
|
527
|
+
export const modalStateAtom = Atom.make({ isOpen: false })
|
|
528
|
+
|
|
529
|
+
// CORRECT - state persists
|
|
530
|
+
export const modalStateAtom = Atom.make({ isOpen: false }).pipe(Atom.keepAlive)
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### FORBIDDEN: Ignoring Result Types
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
// WRONG - doesn't handle loading/error states
|
|
537
|
+
const userResult = useAtomValue(userAtom)
|
|
538
|
+
return <div>Hello, {userResult.name}</div> // Type error!
|
|
539
|
+
|
|
540
|
+
// CORRECT - use Result.builder to handle all states
|
|
541
|
+
const userResult = useAtomValue(userAtom)
|
|
542
|
+
return Result.builder(userResult)
|
|
543
|
+
.onInitial(() => <div>Loading...</div>)
|
|
544
|
+
.onError((error) => <div>Error: {error.message}</div>)
|
|
545
|
+
.onSuccess((user) => <div>Hello, {user.name}</div>)
|
|
546
|
+
.render()
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### FORBIDDEN: Updating State During Render
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
// WRONG - side effect during render
|
|
553
|
+
function Component() {
|
|
554
|
+
const count = useAtomValue(countAtom)
|
|
555
|
+
Atom.set(countAtom, count + 1) // Never do this!
|
|
556
|
+
return <div>{count}</div>
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// CORRECT - use effects or event handlers
|
|
560
|
+
function Component() {
|
|
561
|
+
const count = useAtomValue(countAtom)
|
|
562
|
+
const setCount = useAtomSet(countAtom)
|
|
563
|
+
|
|
564
|
+
useEffect(() => {
|
|
565
|
+
setCount((c) => c + 1)
|
|
566
|
+
}, [])
|
|
567
|
+
|
|
568
|
+
return <div>{count}</div>
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### FORBIDDEN: useState for Mutation Loading State
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
// WRONG - manual loading state management
|
|
576
|
+
function DeleteDialog({ id }: { id: string }) {
|
|
577
|
+
const [, deleteThing] = useAtom(deleteMutation, { mode: "promise" })
|
|
578
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
579
|
+
|
|
580
|
+
const handleDelete = async () => {
|
|
581
|
+
setIsLoading(true)
|
|
582
|
+
try {
|
|
583
|
+
await deleteThing({ id })
|
|
584
|
+
} finally {
|
|
585
|
+
setIsLoading(false) // Unnecessary boilerplate
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// CORRECT - derive from result.waiting
|
|
591
|
+
function DeleteDialog({ id }: { id: string }) {
|
|
592
|
+
const [result, deleteThing] = useAtom(deleteMutation, { mode: "promise" })
|
|
593
|
+
const isLoading = result.waiting
|
|
594
|
+
|
|
595
|
+
const handleDelete = async () => {
|
|
596
|
+
try {
|
|
597
|
+
await deleteThing({ id })
|
|
598
|
+
} catch (err) {
|
|
599
|
+
showError(err)
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### FORBIDDEN: Mutations in Parent Components
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
// WRONG - parent manages the mutation
|
|
609
|
+
function PaywallPage() {
|
|
610
|
+
const [result, archivePaywall] = useAtom(archivePaywallMutation, { mode: "promise" })
|
|
611
|
+
|
|
612
|
+
const handleArchive = async () => {
|
|
613
|
+
await archivePaywall({ paywallId })
|
|
614
|
+
toast.success("Archived")
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return <ConfirmDialog onConfirm={handleArchive} loading={result.waiting} />
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// CORRECT - dialog owns its mutation
|
|
621
|
+
function PaywallPage() {
|
|
622
|
+
return <ArchivePaywallDialog paywall={paywall} onSuccess={() => navigate("/paywalls")} />
|
|
623
|
+
}
|
|
624
|
+
// ArchivePaywallDialog internally uses useAtom(archivePaywallMutation, { mode: "promise" })
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## Performance Tips
|
|
628
|
+
|
|
629
|
+
### Selective Re-rendering
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
// WRONG - subscribes to entire state
|
|
633
|
+
const state = useAtomValue(appStateAtom)
|
|
634
|
+
const userName = state.user.name
|
|
635
|
+
|
|
636
|
+
// CORRECT - derive focused atom
|
|
637
|
+
const userNameAtom = Atom.map(appStateAtom, (state) => state.user.name)
|
|
638
|
+
const userName = useAtomValue(userNameAtom)
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### When to Use keepAlive
|
|
642
|
+
|
|
643
|
+
Use `Atom.keepAlive` for:
|
|
644
|
+
- Global application state
|
|
645
|
+
- Modal/dialog state
|
|
646
|
+
- User preferences
|
|
647
|
+
- Authentication state
|
|
648
|
+
- Frequently accessed derived state
|
|
649
|
+
|
|
650
|
+
Skip `keepAlive` for:
|
|
651
|
+
- Component-local state that should reset
|
|
652
|
+
- Temporary form state
|
|
653
|
+
- State tied to component lifecycle
|