@codyswann/lisa 1.47.0 → 1.48.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/all/copy-overwrite/.claude/rules/lisa.md +23 -10
- package/all/copy-overwrite/.claude/settings.json +10 -230
- package/all/deletions.json +67 -1
- package/cdk/copy-overwrite/.claude/settings.json +80 -0
- package/cdk/create-only/.github/workflows/ci.yml +1 -1
- package/cdk/create-only/.github/workflows/deploy.yml +1 -1
- package/dist/core/lisa.d.ts +14 -0
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +47 -0
- package/dist/core/lisa.js.map +1 -1
- package/expo/copy-overwrite/.claude/settings.json +80 -0
- package/expo/copy-overwrite/eslint.expo.ts +2 -2
- package/expo/create-only/.github/workflows/ci.yml +1 -1
- package/expo/create-only/.github/workflows/deploy.yml +1 -1
- package/expo/deletions.json +33 -0
- package/expo/package-lisa/package.lisa.json +2 -2
- package/nestjs/copy-overwrite/.claude/settings.json +80 -0
- package/nestjs/create-only/.github/workflows/ci.yml +1 -1
- package/nestjs/create-only/.github/workflows/deploy.yml +1 -1
- package/nestjs/deletions.json +8 -0
- package/package.json +8 -4
- package/rails/copy-overwrite/.claude/settings.json +80 -0
- package/rails/create-only/.github/workflows/ci.yml +1 -1
- package/rails/deletions.json +11 -1
- package/typescript/copy-overwrite/.claude/settings.json +13 -231
- package/typescript/copy-overwrite/.github/workflows/claude-ci-auto-fix.yml +1 -0
- package/typescript/copy-overwrite/.github/workflows/claude-code-review-response.yml +11 -10
- package/typescript/copy-overwrite/.github/workflows/claude-deploy-auto-fix.yml +1 -0
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-code-complexity.yml +1 -0
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-coverage.yml +1 -0
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-improvement.yml +2 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +1 -0
- package/typescript/copy-overwrite/eslint.typescript.ts +1 -1
- package/typescript/create-only/.github/workflows/ci.yml +1 -1
- package/typescript/deletions.json +12 -1
- package/typescript/package-lisa/package.lisa.json +1 -1
- package/all/copy-overwrite/.claude/agents/agent-architect.md +0 -310
- package/all/copy-overwrite/.claude/agents/architecture-specialist.md +0 -53
- package/all/copy-overwrite/.claude/agents/debug-specialist.md +0 -204
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +0 -183
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +0 -74
- package/all/copy-overwrite/.claude/agents/implementer.md +0 -54
- package/all/copy-overwrite/.claude/agents/learner.md +0 -44
- package/all/copy-overwrite/.claude/agents/performance-specialist.md +0 -95
- package/all/copy-overwrite/.claude/agents/product-specialist.md +0 -72
- package/all/copy-overwrite/.claude/agents/quality-specialist.md +0 -55
- package/all/copy-overwrite/.claude/agents/security-specialist.md +0 -58
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +0 -246
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +0 -87
- package/all/copy-overwrite/.claude/agents/test-specialist.md +0 -64
- package/all/copy-overwrite/.claude/agents/verification-specialist.md +0 -189
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +0 -112
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +0 -7
- package/all/copy-overwrite/.claude/commands/git/commit-submit-pr-and-verify.md +0 -7
- package/all/copy-overwrite/.claude/commands/git/commit-submit-pr-deploy-and-verify.md +0 -7
- package/all/copy-overwrite/.claude/commands/git/commit.md +0 -7
- package/all/copy-overwrite/.claude/commands/git/prune.md +0 -6
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +0 -7
- package/all/copy-overwrite/.claude/commands/jira/create.md +0 -7
- package/all/copy-overwrite/.claude/commands/jira/sync.md +0 -7
- package/all/copy-overwrite/.claude/commands/jira/verify.md +0 -7
- package/all/copy-overwrite/.claude/commands/lisa/review-implementation.md +0 -7
- package/all/copy-overwrite/.claude/commands/plan/add-test-coverage.md +0 -7
- package/all/copy-overwrite/.claude/commands/plan/create.md +0 -6
- package/all/copy-overwrite/.claude/commands/plan/execute.md +0 -7
- package/all/copy-overwrite/.claude/commands/plan/fix-linter-error.md +0 -7
- package/all/copy-overwrite/.claude/commands/plan/local-code-review.md +0 -6
- package/all/copy-overwrite/.claude/commands/plan/lower-code-complexity.md +0 -6
- package/all/copy-overwrite/.claude/commands/plan/reduce-max-lines-per-function.md +0 -7
- package/all/copy-overwrite/.claude/commands/plan/reduce-max-lines.md +0 -7
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +0 -7
- package/all/copy-overwrite/.claude/commands/security/zap-scan.md +0 -6
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +0 -6
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +0 -6
- package/all/copy-overwrite/.claude/commands/tasks/load.md +0 -7
- package/all/copy-overwrite/.claude/commands/tasks/sync.md +0 -7
- package/all/copy-overwrite/.claude/hooks/check-tired-boss.sh +0 -61
- package/all/copy-overwrite/.claude/hooks/debug-hook.sh +0 -47
- package/all/copy-overwrite/.claude/hooks/enforce-plan-rules.sh +0 -15
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +0 -183
- package/all/copy-overwrite/.claude/hooks/setup-jira-cli.sh +0 -52
- package/all/copy-overwrite/.claude/hooks/sync-tasks.sh +0 -107
- package/all/copy-overwrite/.claude/hooks/ticket-sync-reminder.sh +0 -23
- package/all/copy-overwrite/.claude/hooks/track-plan-sessions.sh +0 -164
- package/all/copy-overwrite/.claude/rules/coding-philosophy.md +0 -428
- package/all/copy-overwrite/.claude/rules/verfication.md +0 -541
- package/all/copy-overwrite/.claude/skills/agent-design-best-practices/SKILL.md +0 -219
- package/all/copy-overwrite/.claude/skills/git-commit/SKILL.md +0 -48
- package/all/copy-overwrite/.claude/skills/git-commit-and-submit-pr/SKILL.md +0 -8
- package/all/copy-overwrite/.claude/skills/git-commit-submit-pr-and-verify/SKILL.md +0 -7
- package/all/copy-overwrite/.claude/skills/git-commit-submit-pr-deploy-and-verify/SKILL.md +0 -7
- package/all/copy-overwrite/.claude/skills/git-prune/SKILL.md +0 -35
- package/all/copy-overwrite/.claude/skills/git-submit-pr/SKILL.md +0 -44
- package/all/copy-overwrite/.claude/skills/jira-create/SKILL.md +0 -41
- package/all/copy-overwrite/.claude/skills/jira-sync/SKILL.md +0 -63
- package/all/copy-overwrite/.claude/skills/jira-verify/SKILL.md +0 -29
- package/all/copy-overwrite/.claude/skills/lisa-review-implementation/SKILL.md +0 -209
- package/all/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +0 -44
- package/all/copy-overwrite/.claude/skills/plan-execute/SKILL.md +0 -89
- package/all/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +0 -45
- package/all/copy-overwrite/.claude/skills/plan-local-code-review/SKILL.md +0 -88
- package/all/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +0 -44
- package/all/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +0 -45
- package/all/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +0 -46
- package/all/copy-overwrite/.claude/skills/pull-request-review/SKILL.md +0 -68
- package/all/copy-overwrite/.claude/skills/security-zap-scan/SKILL.md +0 -33
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +0 -202
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +0 -210
- 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 +0 -305
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +0 -112
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +0 -67
- package/all/copy-overwrite/.claude/skills/sonarqube-check/SKILL.md +0 -11
- package/all/copy-overwrite/.claude/skills/sonarqube-fix/SKILL.md +0 -8
- package/all/copy-overwrite/.claude/skills/tasks-load/SKILL.md +0 -88
- package/all/copy-overwrite/.claude/skills/tasks-sync/SKILL.md +0 -108
- package/eslint-plugin-code-organization/README.md +0 -149
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +0 -473
- package/eslint-plugin-code-organization/index.js +0 -28
- package/eslint-plugin-code-organization/package.json +0 -10
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +0 -162
- package/expo/copy-overwrite/.claude/agents/ops-specialist.md +0 -124
- package/expo/copy-overwrite/.claude/rules/expo-verification.md +0 -261
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +0 -238
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +0 -360
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +0 -360
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +0 -417
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +0 -257
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +0 -233
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +0 -329
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +0 -299
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +0 -749
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +0 -318
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +0 -200
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +0 -209
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +0 -268
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +0 -619
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +0 -340
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +0 -276
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +0 -416
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +0 -202
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +0 -445
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +0 -309
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +0 -417
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +0 -431
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +0 -290
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +0 -171
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +0 -411
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +0 -343
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +0 -307
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +0 -300
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +0 -315
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +0 -362
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +0 -505
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +0 -711
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +0 -446
- package/expo/copy-overwrite/.claude/skills/ops-browser-uat/SKILL.md +0 -124
- package/expo/copy-overwrite/.claude/skills/ops-check-logs/SKILL.md +0 -211
- package/expo/copy-overwrite/.claude/skills/ops-db-ops/SKILL.md +0 -119
- package/expo/copy-overwrite/.claude/skills/ops-deploy/SKILL.md +0 -119
- package/expo/copy-overwrite/.claude/skills/ops-monitor-errors/SKILL.md +0 -99
- package/expo/copy-overwrite/.claude/skills/ops-performance/SKILL.md +0 -165
- package/expo/copy-overwrite/.claude/skills/ops-run-local/SKILL.md +0 -166
- package/expo/copy-overwrite/.claude/skills/ops-verify-health/SKILL.md +0 -101
- package/expo/copy-overwrite/.claude/skills/owasp-zap/SKILL.md +0 -56
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +0 -223
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +0 -314
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +0 -420
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +0 -556
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +0 -590
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +0 -291
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +0 -234
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +0 -89
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +0 -201
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +0 -294
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +0 -37
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +0 -10
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +0 -235
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +0 -96
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +0 -183
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +0 -243
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +0 -192
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +0 -31
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +0 -10
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +0 -56
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +0 -60
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +0 -176
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +0 -527
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +0 -483
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +0 -257
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +0 -413
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +0 -513
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +0 -536
- package/nestjs/copy-overwrite/.claude/skills/security-zap-scan/SKILL.md +0 -33
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +0 -275
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +0 -487
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +0 -450
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +0 -536
- package/rails/copy-overwrite/.claude/skills/action-controller-best-practices/SKILL.md +0 -374
- package/rails/copy-overwrite/.claude/skills/action-view-best-practices/SKILL.md +0 -335
- package/rails/copy-overwrite/.claude/skills/active-record-model-best-practices/SKILL.md +0 -166
- package/rails/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +0 -45
- package/rails/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +0 -45
- package/rails/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +0 -48
- package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +0 -46
- package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +0 -46
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +0 -76
- package/typescript/copy-overwrite/.claude/hooks/install-pkgs.sh +0 -64
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +0 -105
- package/typescript/copy-overwrite/.claude/hooks/sg-scan-on-edit.sh +0 -68
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +0 -432
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +0 -149
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +0 -473
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +0 -28
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +0 -10
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +0 -162
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: apollo-client
|
|
3
|
-
description: This skill should be used when writing or modifying GraphQL operations, hooks, or mutations using Apollo Client 3.10. It enforces best practices for optimistic responses, cache updates, and TypeScript type generation. Use this skill when creating new queries/mutations, reviewing Apollo code, or troubleshooting cache issues.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Apollo Client 3.10
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
This skill provides best practices for Apollo Client 3.10 in this codebase, ensuring consistent patterns for GraphQL operations, optimistic UI updates, cache management, and TypeScript type safety.
|
|
11
|
-
|
|
12
|
-
## Quick Reference
|
|
13
|
-
|
|
14
|
-
### Generator Commands
|
|
15
|
-
|
|
16
|
-
After modifying any `operations.graphql` file, run the appropriate generator:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
bun run generate:types:dev # Development environment
|
|
20
|
-
bun run generate:types:staging # Staging environment
|
|
21
|
-
bun run generate:types:production # Production environment
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
> **Note:** Replace `bun` with your project's package manager (`npm`, `yarn`, `pnpm`) as needed.
|
|
25
|
-
|
|
26
|
-
### Import Pattern
|
|
27
|
-
|
|
28
|
-
All GraphQL types, hooks, and documents must come from generated types:
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import {
|
|
32
|
-
useGetPlayerQuery,
|
|
33
|
-
useUpdatePlayerMutation,
|
|
34
|
-
GetPlayerQuery,
|
|
35
|
-
PlayerFragment,
|
|
36
|
-
ListPlayersDocument,
|
|
37
|
-
} from "@/generated/graphql";
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Core Rules
|
|
41
|
-
|
|
42
|
-
### 1. Only Use Generated Types
|
|
43
|
-
|
|
44
|
-
Import all GraphQL-related types from `@/generated/graphql`. Never define manual TypeScript types for GraphQL entities.
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
// CORRECT
|
|
48
|
-
import { PlayerFragment, useUpdatePlayerMutation } from "@/generated/graphql";
|
|
49
|
-
|
|
50
|
-
// INCORRECT - Never do this
|
|
51
|
-
type Player = { id: string; name: string };
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2. Never Modify Generated Files
|
|
55
|
-
|
|
56
|
-
The `generated/graphql.ts` file is auto-generated by codegen. To change types:
|
|
57
|
-
|
|
58
|
-
1. Edit the appropriate `operations.graphql` file in the feature directory
|
|
59
|
-
2. Run `bun run generate:types:dev`
|
|
60
|
-
3. Import the newly generated types
|
|
61
|
-
|
|
62
|
-
### 3. Always Run Generator After Schema Changes
|
|
63
|
-
|
|
64
|
-
After modifying any `operations.graphql` file, immediately run the generator before committing. Verify changes compile with `bun run typecheck`.
|
|
65
|
-
|
|
66
|
-
### 4. Always Include Optimistic Response
|
|
67
|
-
|
|
68
|
-
Every mutation must include an `optimisticResponse` for instant UI feedback:
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
const [updatePlayer] = useUpdatePlayerMutation({
|
|
72
|
-
optimisticResponse: variables => ({
|
|
73
|
-
__typename: "Mutation",
|
|
74
|
-
updatePlayer: {
|
|
75
|
-
__typename: "Player",
|
|
76
|
-
id: variables.id,
|
|
77
|
-
name: variables.input.name,
|
|
78
|
-
updatedAt: new Date().toISOString(),
|
|
79
|
-
},
|
|
80
|
-
}),
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Key requirements:
|
|
85
|
-
|
|
86
|
-
- Always include `__typename` for every object in the response
|
|
87
|
-
- Always include `id` for cache normalization
|
|
88
|
-
- Use temporary IDs for new objects (e.g., `crypto.randomUUID()`)
|
|
89
|
-
- Include all fields that the mutation returns
|
|
90
|
-
|
|
91
|
-
### 5. Always Update Cache
|
|
92
|
-
|
|
93
|
-
Every mutation must handle cache updates using one of these strategies:
|
|
94
|
-
|
|
95
|
-
**Automatic Updates** - When mutation returns the full entity with `id` and `__typename`, Apollo updates automatically. No extra code needed.
|
|
96
|
-
|
|
97
|
-
**cache.modify** - For adding/removing items from lists:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
const [addPlayer] = useAddPlayerMutation({
|
|
101
|
-
optimisticResponse: {
|
|
102
|
-
/* ... */
|
|
103
|
-
},
|
|
104
|
-
update(cache, { data }) {
|
|
105
|
-
cache.modify({
|
|
106
|
-
fields: {
|
|
107
|
-
players(existingPlayers = [], { readField }) {
|
|
108
|
-
const newRef = cache.writeFragment({
|
|
109
|
-
data: data.addPlayer,
|
|
110
|
-
fragment: PlayerFragmentDoc,
|
|
111
|
-
});
|
|
112
|
-
return [...existingPlayers, newRef];
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
**refetchQueries** - Fallback for complex scenarios:
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
const [complexMutation] = useComplexMutation({
|
|
124
|
-
refetchQueries: ["ListPlayers"],
|
|
125
|
-
awaitRefetchQueries: true,
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Operations.graphql Structure
|
|
130
|
-
|
|
131
|
-
### Fragment-First Pattern
|
|
132
|
-
|
|
133
|
-
Define fragments before queries/mutations that use them:
|
|
134
|
-
|
|
135
|
-
```graphql
|
|
136
|
-
# 1. Fragments first
|
|
137
|
-
fragment PlayerFragment on Player {
|
|
138
|
-
id
|
|
139
|
-
knownName
|
|
140
|
-
firstName
|
|
141
|
-
lastName
|
|
142
|
-
team {
|
|
143
|
-
id
|
|
144
|
-
name
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
# 2. Queries second
|
|
149
|
-
query GetPlayer($id: ID!) {
|
|
150
|
-
player(id: $id) {
|
|
151
|
-
...PlayerFragment
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
# 3. Mutations last
|
|
156
|
-
mutation UpdatePlayer($id: ID!, $input: UpdatePlayerInput!) {
|
|
157
|
-
updatePlayer(id: $id, input: $input) {
|
|
158
|
-
...PlayerFragment
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Include Required Fields
|
|
164
|
-
|
|
165
|
-
Mutations must return all fields needed for cache updates:
|
|
166
|
-
|
|
167
|
-
```graphql
|
|
168
|
-
mutation AddPlayerToKanban($input: AddPlayerToKanbanInput!) {
|
|
169
|
-
addPlayerToKanban(input: $input) {
|
|
170
|
-
id # Required for cache normalization
|
|
171
|
-
position
|
|
172
|
-
notes
|
|
173
|
-
kanbanPhaseId
|
|
174
|
-
kanbanPhase {
|
|
175
|
-
# Include related objects
|
|
176
|
-
id
|
|
177
|
-
name
|
|
178
|
-
}
|
|
179
|
-
createdAt
|
|
180
|
-
updatedAt
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## Query Best Practices
|
|
186
|
-
|
|
187
|
-
### Fetch Policies
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
// Frequently changing data - balance speed and freshness
|
|
191
|
-
fetchPolicy: "cache-and-network";
|
|
192
|
-
|
|
193
|
-
// Stable reference data - prioritize cache
|
|
194
|
-
fetchPolicy: "cache-first";
|
|
195
|
-
|
|
196
|
-
// Always-fresh data - skip cache
|
|
197
|
-
fetchPolicy: "network-only";
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Skip When Variables Undefined
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
const { data } = useGetPlayerQuery({
|
|
204
|
-
variables: { id: playerId! },
|
|
205
|
-
skip: !playerId,
|
|
206
|
-
});
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Error Handling
|
|
210
|
-
|
|
211
|
-
Use `onError` callback instead of try/catch with console.log:
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
const [mutation] = useMutation(MUTATION, {
|
|
215
|
-
onError: error => {
|
|
216
|
-
setErrorState("Failed to update. Please try again.");
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## Complete Mutation Pattern
|
|
222
|
-
|
|
223
|
-
Reference `references/mutation-patterns.md` for comprehensive examples of the complete mutation pattern including optimistic responses, cache updates, and error handling.
|
|
224
|
-
|
|
225
|
-
## Validation Checklist
|
|
226
|
-
|
|
227
|
-
When writing or reviewing Apollo code, verify:
|
|
228
|
-
|
|
229
|
-
- [ ] All types imported from `@/generated/graphql`
|
|
230
|
-
- [ ] No manual type definitions for GraphQL entities
|
|
231
|
-
- [ ] Every mutation has `optimisticResponse`
|
|
232
|
-
- [ ] Every mutation has cache update strategy
|
|
233
|
-
- [ ] `__typename` included in all optimistic response objects
|
|
234
|
-
- [ ] `id` included in all optimistic response objects
|
|
235
|
-
- [ ] Queries use appropriate `fetchPolicy`
|
|
236
|
-
- [ ] Queries use `skip` when variables may be undefined
|
|
237
|
-
- [ ] Error handling via `onError` callback
|
|
238
|
-
- [ ] Generator was run after operations.graphql changes
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
# Apollo Client Mutation Patterns
|
|
2
|
-
|
|
3
|
-
This reference provides comprehensive examples of mutation patterns for Apollo Client 3.10.
|
|
4
|
-
|
|
5
|
-
## Complete Mutation Hook Pattern
|
|
6
|
-
|
|
7
|
-
Every custom mutation hook should follow this structure:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { useCallback } from "react";
|
|
11
|
-
import {
|
|
12
|
-
useUpdateKanbanCardMutation,
|
|
13
|
-
KanbanCardFragment,
|
|
14
|
-
KanbanCardFragmentDoc,
|
|
15
|
-
} from "@/generated/graphql";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Hook for updating kanban card with optimistic UI
|
|
19
|
-
* @param boardId - The board ID for context
|
|
20
|
-
* @returns Object containing update function and loading state
|
|
21
|
-
*/
|
|
22
|
-
export const useUpdateCard = (boardId: string) => {
|
|
23
|
-
const [updateCardMutation, { loading }] = useUpdateKanbanCardMutation({
|
|
24
|
-
// 1. OPTIMISTIC RESPONSE - Provides instant UI feedback
|
|
25
|
-
optimisticResponse: variables => ({
|
|
26
|
-
__typename: "Mutation",
|
|
27
|
-
updateKanbanCard: {
|
|
28
|
-
__typename: "KanbanCard",
|
|
29
|
-
id: variables.id,
|
|
30
|
-
notes: variables.input.notes ?? null,
|
|
31
|
-
position: variables.input.position ?? 0,
|
|
32
|
-
kanbanPhaseId: variables.input.kanbanPhaseId ?? "",
|
|
33
|
-
kanbanPhase: {
|
|
34
|
-
__typename: "KanbanPhase",
|
|
35
|
-
id: variables.input.kanbanPhaseId ?? "",
|
|
36
|
-
name: "", // Will be updated by server response
|
|
37
|
-
},
|
|
38
|
-
createdAt: new Date().toISOString(),
|
|
39
|
-
updatedAt: new Date().toISOString(),
|
|
40
|
-
},
|
|
41
|
-
}),
|
|
42
|
-
|
|
43
|
-
// 2. CACHE UPDATE - Ensures UI stays in sync
|
|
44
|
-
update(cache, { data }) {
|
|
45
|
-
if (!data?.updateKanbanCard) return;
|
|
46
|
-
|
|
47
|
-
// For simple field updates, Apollo handles automatically
|
|
48
|
-
// For complex scenarios, use cache.modify:
|
|
49
|
-
cache.modify({
|
|
50
|
-
id: cache.identify({
|
|
51
|
-
__typename: "KanbanCard",
|
|
52
|
-
id: data.updateKanbanCard.id,
|
|
53
|
-
}),
|
|
54
|
-
fields: {
|
|
55
|
-
notes: () => data.updateKanbanCard.notes,
|
|
56
|
-
position: () => data.updateKanbanCard.position,
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
// 3. ERROR HANDLING - Never pollutes console
|
|
62
|
-
onError: () => {
|
|
63
|
-
// Set error state in UI, don't console.log
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// 4. WRAPPED CALLBACK - Proper memoization
|
|
68
|
-
const updateCard = useCallback(
|
|
69
|
-
async (cardId: string, notes: string) => {
|
|
70
|
-
await updateCardMutation({
|
|
71
|
-
variables: {
|
|
72
|
-
id: cardId,
|
|
73
|
-
input: { notes },
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
[updateCardMutation]
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
return { updateCard, isUpdating: loading };
|
|
81
|
-
};
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Adding Items to a List
|
|
85
|
-
|
|
86
|
-
When creating new items that need to appear in a list:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
const [addPlayerMutation] = useAddPlayerToKanbanMutation({
|
|
90
|
-
optimisticResponse: variables => ({
|
|
91
|
-
__typename: "Mutation",
|
|
92
|
-
addPlayerToKanban: {
|
|
93
|
-
__typename: "KanbanCard",
|
|
94
|
-
id: crypto.randomUUID(), // Temporary ID for new items
|
|
95
|
-
position: 0,
|
|
96
|
-
notes: variables.input.notes ?? null,
|
|
97
|
-
kanbanPhaseId: variables.input.kanbanPhaseId,
|
|
98
|
-
kanbanPhase: {
|
|
99
|
-
__typename: "KanbanPhase",
|
|
100
|
-
id: variables.input.kanbanPhaseId,
|
|
101
|
-
name: "", // Will be replaced by server
|
|
102
|
-
},
|
|
103
|
-
createdAt: new Date().toISOString(),
|
|
104
|
-
updatedAt: new Date().toISOString(),
|
|
105
|
-
},
|
|
106
|
-
}),
|
|
107
|
-
|
|
108
|
-
update(cache, { data }) {
|
|
109
|
-
if (!data?.addPlayerToKanban) return;
|
|
110
|
-
|
|
111
|
-
cache.modify({
|
|
112
|
-
fields: {
|
|
113
|
-
listKanbanCards(existingCards = { edges: [] }) {
|
|
114
|
-
const newCardRef = cache.writeFragment({
|
|
115
|
-
data: data.addPlayerToKanban,
|
|
116
|
-
fragment: KanbanCardFragmentDoc,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
...existingCards,
|
|
121
|
-
edges: [
|
|
122
|
-
...existingCards.edges,
|
|
123
|
-
{
|
|
124
|
-
__typename: "KanbanCardEdge",
|
|
125
|
-
cursor: "",
|
|
126
|
-
node: { __ref: newCardRef.__ref },
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
onError: () => {
|
|
136
|
-
// Handle error in UI state
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Removing Items from a List
|
|
142
|
-
|
|
143
|
-
When deleting items that should disappear from a list:
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
const [removePlayerMutation] = useRemovePlayerFromKanbanMutation({
|
|
147
|
-
optimisticResponse: variables => ({
|
|
148
|
-
__typename: "Mutation",
|
|
149
|
-
removePlayerFromKanban: {
|
|
150
|
-
__typename: "KanbanCard",
|
|
151
|
-
id: variables.cardId,
|
|
152
|
-
position: 0,
|
|
153
|
-
notes: null,
|
|
154
|
-
kanbanPhaseId: "",
|
|
155
|
-
kanbanPhase: {
|
|
156
|
-
__typename: "KanbanPhase",
|
|
157
|
-
id: "",
|
|
158
|
-
name: "",
|
|
159
|
-
},
|
|
160
|
-
createdAt: new Date().toISOString(),
|
|
161
|
-
updatedAt: new Date().toISOString(),
|
|
162
|
-
},
|
|
163
|
-
}),
|
|
164
|
-
|
|
165
|
-
update(cache, { data }) {
|
|
166
|
-
if (!data?.removePlayerFromKanban) return;
|
|
167
|
-
|
|
168
|
-
const removedId = data.removePlayerFromKanban.id;
|
|
169
|
-
|
|
170
|
-
cache.modify({
|
|
171
|
-
fields: {
|
|
172
|
-
listKanbanCards(existingCards = { edges: [] }, { readField }) {
|
|
173
|
-
return {
|
|
174
|
-
...existingCards,
|
|
175
|
-
edges: existingCards.edges.filter(
|
|
176
|
-
(edge: { node: { __ref: string } }) => {
|
|
177
|
-
const cardRef = edge.node.__ref;
|
|
178
|
-
return readField("id", { __ref: cardRef }) !== removedId;
|
|
179
|
-
}
|
|
180
|
-
),
|
|
181
|
-
};
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// Evict the removed item from cache entirely
|
|
187
|
-
cache.evict({
|
|
188
|
-
id: cache.identify({
|
|
189
|
-
__typename: "KanbanCard",
|
|
190
|
-
id: removedId,
|
|
191
|
-
}),
|
|
192
|
-
});
|
|
193
|
-
cache.gc();
|
|
194
|
-
},
|
|
195
|
-
|
|
196
|
-
onError: () => {
|
|
197
|
-
// Handle error in UI state
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Moving Items Between Lists
|
|
203
|
-
|
|
204
|
-
When an item moves from one parent to another:
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
const [moveCardMutation] = useMoveKanbanCardMutation({
|
|
208
|
-
optimisticResponse: variables => ({
|
|
209
|
-
__typename: "Mutation",
|
|
210
|
-
moveKanbanCard: {
|
|
211
|
-
__typename: "KanbanCard",
|
|
212
|
-
id: variables.input.cardId,
|
|
213
|
-
position: variables.input.targetPosition,
|
|
214
|
-
notes: null, // Preserve from existing cache
|
|
215
|
-
kanbanPhaseId: variables.input.targetPhaseId,
|
|
216
|
-
kanbanPhase: {
|
|
217
|
-
__typename: "KanbanPhase",
|
|
218
|
-
id: variables.input.targetPhaseId,
|
|
219
|
-
name: "", // Will be updated by server
|
|
220
|
-
},
|
|
221
|
-
createdAt: new Date().toISOString(),
|
|
222
|
-
updatedAt: new Date().toISOString(),
|
|
223
|
-
},
|
|
224
|
-
}),
|
|
225
|
-
|
|
226
|
-
// For moves, refetchQueries is often cleaner than manual cache updates
|
|
227
|
-
refetchQueries: ["ListKanbanCards"],
|
|
228
|
-
awaitRefetchQueries: false, // Don't block UI
|
|
229
|
-
|
|
230
|
-
onError: () => {
|
|
231
|
-
// Handle error in UI state
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
## Batch Updates with Reordering
|
|
237
|
-
|
|
238
|
-
When updating positions of multiple items:
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
const [updatePositionsMutation] = useUpdateKanbanPhasePositionsMutation({
|
|
242
|
-
optimisticResponse: variables => ({
|
|
243
|
-
__typename: "Mutation",
|
|
244
|
-
updateKanbanPhasePositions: variables.input.phasePositions.map(pp => ({
|
|
245
|
-
__typename: "KanbanPhase",
|
|
246
|
-
id: pp.phaseId,
|
|
247
|
-
position: pp.position,
|
|
248
|
-
name: "", // Preserve from cache
|
|
249
|
-
kanbanBoardId: variables.input.kanbanBoardId,
|
|
250
|
-
createdAt: new Date().toISOString(),
|
|
251
|
-
updatedAt: new Date().toISOString(),
|
|
252
|
-
})),
|
|
253
|
-
}),
|
|
254
|
-
|
|
255
|
-
refetchQueries: ["ListKanbanPhases"],
|
|
256
|
-
awaitRefetchQueries: false,
|
|
257
|
-
|
|
258
|
-
onError: () => {
|
|
259
|
-
// Handle error in UI state
|
|
260
|
-
},
|
|
261
|
-
});
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Conditional Optimistic Updates
|
|
265
|
-
|
|
266
|
-
Skip optimistic updates when conditions aren't met:
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
const [updateMutation] = useUpdateMutation({
|
|
270
|
-
optimisticResponse: (variables, { IGNORE }) => {
|
|
271
|
-
// Skip optimistic update if we don't have enough data
|
|
272
|
-
if (!variables.input.name) {
|
|
273
|
-
return IGNORE;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return {
|
|
277
|
-
__typename: "Mutation",
|
|
278
|
-
update: {
|
|
279
|
-
__typename: "Entity",
|
|
280
|
-
id: variables.id,
|
|
281
|
-
name: variables.input.name,
|
|
282
|
-
updatedAt: new Date().toISOString(),
|
|
283
|
-
},
|
|
284
|
-
};
|
|
285
|
-
},
|
|
286
|
-
});
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Cache Update with cache.identify
|
|
290
|
-
|
|
291
|
-
Use `cache.identify` to get the correct cache key:
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
update(cache, { data }) {
|
|
295
|
-
if (!data?.updatePlayer) return;
|
|
296
|
-
|
|
297
|
-
const cacheId = cache.identify({
|
|
298
|
-
__typename: "Player",
|
|
299
|
-
id: data.updatePlayer.id,
|
|
300
|
-
});
|
|
301
|
-
// cacheId = "Player:abc-123"
|
|
302
|
-
|
|
303
|
-
cache.modify({
|
|
304
|
-
id: cacheId,
|
|
305
|
-
fields: {
|
|
306
|
-
isActive: () => true,
|
|
307
|
-
updatedAt: () => new Date().toISOString(),
|
|
308
|
-
},
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
## Using readonly Types for Cache Modifiers
|
|
314
|
-
|
|
315
|
-
Apollo cache data is readonly. Use proper typing:
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
cache.modify({
|
|
319
|
-
fields: {
|
|
320
|
-
players(existingPlayers: readonly { __ref: string }[] = [], { readField }) {
|
|
321
|
-
return existingPlayers.filter(ref => readField("id", ref) !== removedId);
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
## Decision Tree: Cache Update Strategy
|
|
328
|
-
|
|
329
|
-
```
|
|
330
|
-
Mutation creates/updates/deletes entity
|
|
331
|
-
│
|
|
332
|
-
▼
|
|
333
|
-
┌───────────────────────────────┐
|
|
334
|
-
│ Does mutation return entity │
|
|
335
|
-
│ with id and __typename? │
|
|
336
|
-
└───────────────────────────────┘
|
|
337
|
-
│
|
|
338
|
-
┌──────┴──────┐
|
|
339
|
-
│ YES │ NO
|
|
340
|
-
▼ ▼
|
|
341
|
-
┌─────────┐ ┌─────────────────┐
|
|
342
|
-
│Automatic│ │ Use │
|
|
343
|
-
│ Update │ │ refetchQueries │
|
|
344
|
-
└─────────┘ └─────────────────┘
|
|
345
|
-
│
|
|
346
|
-
▼
|
|
347
|
-
┌───────────────────────────────┐
|
|
348
|
-
│ Does entity need to appear │
|
|
349
|
-
│ in or disappear from a list? │
|
|
350
|
-
└───────────────────────────────┘
|
|
351
|
-
│
|
|
352
|
-
┌──────┴──────┐
|
|
353
|
-
│ YES │ NO
|
|
354
|
-
▼ ▼
|
|
355
|
-
┌─────────────┐ ┌─────────────┐
|
|
356
|
-
│cache.modify │ │ Automatic │
|
|
357
|
-
│ with list │ │ is enough │
|
|
358
|
-
│ manipulation│ │ │
|
|
359
|
-
└─────────────┘ └─────────────┘
|
|
360
|
-
```
|