@codyswann/lisa 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/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-state
|
|
3
|
+
description: This skill should be used when implementing local state management in this React Native/Expo codebase. It covers Apollo Client Reactive Variables for in-memory reactive state and React Native AsyncStorage for persistent storage. Use this skill when creating feature flags, user preferences, session state, or any client-only state that needs to survive component unmounts or app restarts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Local State Management
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This skill provides best practices for local state management in this React Native/Expo codebase. Local state is managed using two complementary approaches:
|
|
11
|
+
|
|
12
|
+
1. **Apollo Client Reactive Variables** - In-memory reactive state for UI synchronization
|
|
13
|
+
2. **React Native AsyncStorage** - Persistent key-value storage for data that survives app restarts
|
|
14
|
+
|
|
15
|
+
## When to Use Each Approach
|
|
16
|
+
|
|
17
|
+
| Use Case | Approach | Example |
|
|
18
|
+
| ------------------------------- | -------------------------------- | ------------------------------ |
|
|
19
|
+
| UI state that resets on refresh | Reactive Variable only | Modal open state, form drafts |
|
|
20
|
+
| User preferences that persist | Reactive Variable + AsyncStorage | Theme, language, notifications |
|
|
21
|
+
| Feature flags | Reactive Variable + AsyncStorage | Beta features, profiler toggle |
|
|
22
|
+
| Session-scoped data | Reactive Variable only | Current filter selections |
|
|
23
|
+
| Cross-component communication | Reactive Variable | Selected player ID, active tab |
|
|
24
|
+
| Authentication tokens | `expo-secure-store` | Access tokens, refresh tokens |
|
|
25
|
+
|
|
26
|
+
## Quick Reference
|
|
27
|
+
|
|
28
|
+
### Creating a Reactive Variable
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { makeVar } from "@apollo/client";
|
|
32
|
+
|
|
33
|
+
interface IUserPreferences {
|
|
34
|
+
readonly theme: "light" | "dark";
|
|
35
|
+
readonly notifications: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DEFAULT_PREFERENCES: IUserPreferences = {
|
|
39
|
+
theme: "light",
|
|
40
|
+
notifications: true,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const userPreferencesVar =
|
|
44
|
+
makeVar<IUserPreferences>(DEFAULT_PREFERENCES);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Reading in Components (Reactive)
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { useReactiveVar } from "@apollo/client";
|
|
51
|
+
|
|
52
|
+
const MyComponent = () => {
|
|
53
|
+
const preferences = useReactiveVar(userPreferencesVar);
|
|
54
|
+
return <Text>{preferences.theme}</Text>;
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Updating Values (Immutably)
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Update with new object reference
|
|
62
|
+
userPreferencesVar({
|
|
63
|
+
...userPreferencesVar(),
|
|
64
|
+
theme: "dark",
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Persisting to AsyncStorage
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
72
|
+
|
|
73
|
+
const STORAGE_KEY = "@whatever:user-preferences";
|
|
74
|
+
|
|
75
|
+
export const savePreferences = async (
|
|
76
|
+
prefs: IUserPreferences
|
|
77
|
+
): Promise<void> => {
|
|
78
|
+
userPreferencesVar(prefs); // Update reactive variable first
|
|
79
|
+
try {
|
|
80
|
+
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
83
|
+
console.error("Failed to save preferences:", message);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const loadPreferences = async (): Promise<void> => {
|
|
88
|
+
try {
|
|
89
|
+
const stored = await AsyncStorage.getItem(STORAGE_KEY);
|
|
90
|
+
if (stored) {
|
|
91
|
+
const parsed = JSON.parse(stored) as IUserPreferences;
|
|
92
|
+
userPreferencesVar({ ...DEFAULT_PREFERENCES, ...parsed });
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
96
|
+
console.error("Failed to load preferences:", message);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Core Rules
|
|
102
|
+
|
|
103
|
+
### 1. Always Create New References
|
|
104
|
+
|
|
105
|
+
Never mutate existing objects or arrays. Create new references to trigger reactivity:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// CORRECT - creates new object
|
|
109
|
+
userPreferencesVar({
|
|
110
|
+
...userPreferencesVar(),
|
|
111
|
+
theme: "dark",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// INCORRECT - mutation does NOT trigger updates
|
|
115
|
+
const prefs = userPreferencesVar();
|
|
116
|
+
prefs.theme = "dark"; // This does nothing!
|
|
117
|
+
userPreferencesVar(prefs); // Same reference, no update
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. Use `useReactiveVar` for Reactive Components
|
|
121
|
+
|
|
122
|
+
Calling `myVar()` directly does NOT trigger re-renders. Always use the hook:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// CORRECT - component re-renders when variable changes
|
|
126
|
+
const theme = useReactiveVar(themeVar);
|
|
127
|
+
|
|
128
|
+
// INCORRECT - no re-renders on variable change
|
|
129
|
+
const theme = themeVar();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 3. Encapsulate Updates in Custom Hooks
|
|
133
|
+
|
|
134
|
+
Create custom hooks for testability and encapsulation:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
export const useTheme = () => {
|
|
138
|
+
const preferences = useReactiveVar(userPreferencesVar);
|
|
139
|
+
|
|
140
|
+
const setTheme = useCallback((theme: "light" | "dark") => {
|
|
141
|
+
savePreferences({ ...userPreferencesVar(), theme });
|
|
142
|
+
}, []);
|
|
143
|
+
|
|
144
|
+
return { theme: preferences.theme, setTheme };
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 4. Use Namespace Prefixes for Storage Keys
|
|
149
|
+
|
|
150
|
+
Prefix all AsyncStorage keys with the app namespace:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// CORRECT
|
|
154
|
+
const STORAGE_KEY = "@whatever:filter-values";
|
|
155
|
+
|
|
156
|
+
// INCORRECT - collision risk
|
|
157
|
+
const STORAGE_KEY = "filters";
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 5. Always Handle AsyncStorage Errors
|
|
161
|
+
|
|
162
|
+
AsyncStorage operations can fail. Always use try/catch:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// CORRECT
|
|
166
|
+
try {
|
|
167
|
+
await AsyncStorage.setItem(key, JSON.stringify(value));
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
170
|
+
console.error(`Failed to save ${key}:`, message);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// INCORRECT - silent failures
|
|
174
|
+
await AsyncStorage.setItem(key, JSON.stringify(value));
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 6. Never Store Sensitive Data in AsyncStorage
|
|
178
|
+
|
|
179
|
+
AsyncStorage is unencrypted. Use `expo-secure-store` for sensitive data:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// CORRECT - use secure store for tokens
|
|
183
|
+
import * as SecureStore from "expo-secure-store";
|
|
184
|
+
await SecureStore.setItemAsync("accessToken", token);
|
|
185
|
+
|
|
186
|
+
// INCORRECT - never store tokens in AsyncStorage
|
|
187
|
+
await AsyncStorage.setItem("accessToken", token);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 7. Load Persisted State on App Start
|
|
191
|
+
|
|
192
|
+
Initialize persisted state early in the app lifecycle:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// In root layout or app initialization
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
loadPreferences();
|
|
198
|
+
}, []);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## File Organization
|
|
202
|
+
|
|
203
|
+
Organize reactive variables and persistence logic in dedicated store files:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
features/
|
|
207
|
+
my-feature/
|
|
208
|
+
stores/
|
|
209
|
+
featureState.ts # Reactive variable + persistence logic
|
|
210
|
+
index.ts # Re-exports
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Example store file structure:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// stores/userPreferences.ts
|
|
217
|
+
import { makeVar, useReactiveVar } from "@apollo/client";
|
|
218
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
219
|
+
import { useCallback } from "react";
|
|
220
|
+
|
|
221
|
+
// Types
|
|
222
|
+
interface IUserPreferences {
|
|
223
|
+
readonly theme: "light" | "dark";
|
|
224
|
+
readonly language: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Constants
|
|
228
|
+
const STORAGE_KEY = "@whatever:user-preferences";
|
|
229
|
+
const DEFAULT_PREFERENCES: IUserPreferences = {
|
|
230
|
+
theme: "light",
|
|
231
|
+
language: "en",
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Reactive Variable
|
|
235
|
+
export const userPreferencesVar =
|
|
236
|
+
makeVar<IUserPreferences>(DEFAULT_PREFERENCES);
|
|
237
|
+
|
|
238
|
+
// Persistence Functions
|
|
239
|
+
export const loadUserPreferences = async (): Promise<void> => {
|
|
240
|
+
try {
|
|
241
|
+
const stored = await AsyncStorage.getItem(STORAGE_KEY);
|
|
242
|
+
if (stored) {
|
|
243
|
+
const parsed = JSON.parse(stored) as IUserPreferences;
|
|
244
|
+
userPreferencesVar({ ...DEFAULT_PREFERENCES, ...parsed });
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
248
|
+
console.error("Failed to load preferences:", message);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const saveUserPreferences = async (prefs: IUserPreferences): Promise<void> => {
|
|
253
|
+
userPreferencesVar(prefs);
|
|
254
|
+
try {
|
|
255
|
+
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
|
|
256
|
+
} catch (error) {
|
|
257
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
258
|
+
console.error("Failed to save preferences:", message);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Custom Hook
|
|
263
|
+
export const useUserPreferences = () => {
|
|
264
|
+
const preferences = useReactiveVar(userPreferencesVar);
|
|
265
|
+
|
|
266
|
+
const setTheme = useCallback((theme: "light" | "dark") => {
|
|
267
|
+
saveUserPreferences({ ...userPreferencesVar(), theme });
|
|
268
|
+
}, []);
|
|
269
|
+
|
|
270
|
+
const setLanguage = useCallback((language: string) => {
|
|
271
|
+
saveUserPreferences({ ...userPreferencesVar(), language });
|
|
272
|
+
}, []);
|
|
273
|
+
|
|
274
|
+
return { preferences, setTheme, setLanguage };
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Detailed Reference
|
|
279
|
+
|
|
280
|
+
For comprehensive patterns and examples, see the reference files:
|
|
281
|
+
|
|
282
|
+
- **[references/reactive-variables.md](references/reactive-variables.md)** - Complete reactive variable patterns including TypeScript types, cache integration, and advanced use cases
|
|
283
|
+
- **[references/async-storage.md](references/async-storage.md)** - AsyncStorage API patterns, error handling, and performance considerations
|
|
284
|
+
- **[references/persistence-patterns.md](references/persistence-patterns.md)** - Patterns for persisting reactive variables including AppState-based and immediate persistence
|
|
285
|
+
|
|
286
|
+
## Anti-Patterns to Avoid
|
|
287
|
+
|
|
288
|
+
### Never mutate reactive variable values
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// WRONG - mutation
|
|
292
|
+
const filters = filtersVar();
|
|
293
|
+
filters.minAge = 25;
|
|
294
|
+
filtersVar(filters);
|
|
295
|
+
|
|
296
|
+
// CORRECT - new reference
|
|
297
|
+
filtersVar({ ...filtersVar(), minAge: 25 });
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Never use `localStorage` in React Native
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
// WRONG - doesn't exist in React Native
|
|
304
|
+
localStorage.setItem("key", value);
|
|
305
|
+
|
|
306
|
+
// CORRECT - use AsyncStorage
|
|
307
|
+
await AsyncStorage.setItem("key", value);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Never call `myVar()` expecting re-renders
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// WRONG - no reactivity
|
|
314
|
+
const Component = () => {
|
|
315
|
+
const value = myVar(); // Does NOT trigger re-renders
|
|
316
|
+
return <Text>{value}</Text>;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// CORRECT - reactive
|
|
320
|
+
const Component = () => {
|
|
321
|
+
const value = useReactiveVar(myVar);
|
|
322
|
+
return <Text>{value}</Text>;
|
|
323
|
+
};
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Never store without serialization
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// WRONG - AsyncStorage only accepts strings
|
|
330
|
+
await AsyncStorage.setItem("key", { name: "John" });
|
|
331
|
+
|
|
332
|
+
// CORRECT - serialize first
|
|
333
|
+
await AsyncStorage.setItem("key", JSON.stringify({ name: "John" }));
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Never forget to load persisted state
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// WRONG - state resets on app restart
|
|
340
|
+
export const filtersVar = makeVar<Filters>(DEFAULT_FILTERS);
|
|
341
|
+
|
|
342
|
+
// CORRECT - load on app start
|
|
343
|
+
export const filtersVar = makeVar<Filters>(DEFAULT_FILTERS);
|
|
344
|
+
export const loadFilters = async () => {
|
|
345
|
+
/* ... */
|
|
346
|
+
};
|
|
347
|
+
// Call loadFilters() in app initialization
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Validation Checklist
|
|
351
|
+
|
|
352
|
+
When writing or reviewing local state code, verify:
|
|
353
|
+
|
|
354
|
+
- [ ] Reactive variables use TypeScript generics: `makeVar<Type>(default)`
|
|
355
|
+
- [ ] Components use `useReactiveVar()` hook, not direct `myVar()` calls
|
|
356
|
+
- [ ] Updates create new object/array references (spread operator)
|
|
357
|
+
- [ ] AsyncStorage keys use namespace prefix: `@whatever:`
|
|
358
|
+
- [ ] All AsyncStorage operations wrapped in try/catch
|
|
359
|
+
- [ ] Sensitive data uses `expo-secure-store`, not AsyncStorage
|
|
360
|
+
- [ ] Persisted state loaded on app initialization
|
|
361
|
+
- [ ] Custom hooks encapsulate update logic
|
|
362
|
+
- [ ] State stored in feature-specific `stores/` directory
|