@mr.dj2u/knowledge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/content/checklists/ship-test-loop.md +16 -0
  2. package/dist/content/checklists/unified-agent-bundle-validation.md +8 -0
  3. package/dist/content/examples/ship-test-loop.md +13 -0
  4. package/dist/content/examples/unified-agent-bundle-bootstrap.md +8 -0
  5. package/dist/content/guides/animation-performance.md +30 -0
  6. package/dist/content/guides/post-create-onboarding.md +113 -0
  7. package/dist/content/patterns/api/api-routes.md +314 -0
  8. package/dist/content/patterns/api/error-handling.md +311 -0
  9. package/dist/content/patterns/database/drizzle-schema.md +280 -0
  10. package/dist/content/patterns/database/migrations.md +365 -0
  11. package/dist/content/patterns/database/query-organization.md +537 -0
  12. package/dist/content/patterns/database/relations.md +450 -0
  13. package/dist/content/patterns/deployment/build-configuration.md +452 -0
  14. package/dist/content/patterns/deployment/ci-cd-patterns.md +448 -0
  15. package/dist/content/patterns/deployment/environment-config.md +380 -0
  16. package/dist/content/patterns/deployment/hosting-setup.md +425 -0
  17. package/dist/content/patterns/project/configuration-patterns.md +459 -0
  18. package/dist/content/patterns/project/documentation-org.md +506 -0
  19. package/dist/content/patterns/project/folder-structure.md +398 -0
  20. package/dist/content/patterns/project/library-exports.md +465 -0
  21. package/dist/content/patterns/project/monorepo-structure.md +500 -0
  22. package/dist/content/patterns/routing/dynamic-routes.md +221 -0
  23. package/dist/content/patterns/routing/file-based-routing.md +186 -0
  24. package/dist/content/patterns/routing/route-groups.md +429 -0
  25. package/dist/content/patterns/state/persistence-middleware.md +521 -0
  26. package/dist/content/patterns/state/selector-hooks.md +538 -0
  27. package/dist/content/patterns/state/store-organization.md +539 -0
  28. package/dist/content/patterns/state/zustand-patterns.md +348 -0
  29. package/dist/content/patterns/styling/component-styling.md +468 -0
  30. package/dist/content/patterns/styling/responsive-patterns.md +398 -0
  31. package/dist/content/patterns/styling/theme-configuration.md +426 -0
  32. package/dist/content/patterns/styling/uniwind-setup.md +412 -0
  33. package/dist/content/prompts/continue-development.md +27 -0
  34. package/dist/content/prompts/create-expo-super-stack.md +29 -0
  35. package/dist/content/prompts/fix-seo.md +29 -0
  36. package/dist/content/prompts/onboard-new-expo-app.md +11 -0
  37. package/dist/content/prompts/prepare-deploy.md +29 -0
  38. package/dist/content/prompts/project-research-plan.md +29 -0
  39. package/dist/content/prompts/review-expo-project.md +29 -0
  40. package/dist/content/prompts/run-doctor.md +30 -0
  41. package/dist/content/prompts/ship-test-loop.md +24 -0
  42. package/dist/content/reference/create-expo-stack-uniwind.md +29 -0
  43. package/dist/content/reference/doctor-dogfood.md +42 -0
  44. package/dist/content/reference/mcp-sdk-transport.md +30 -0
  45. package/dist/content/reference/package-ci-patterns.md +24 -0
  46. package/dist/content/reference/reference-repo-evacuation.md +31 -0
  47. package/dist/content/resource-index.json +67 -0
  48. package/dist/content/rules/app-folder-architecture.md +13 -0
  49. package/dist/content/rules/env-hygiene.md +9 -0
  50. package/dist/content/rules/seo-metadata.md +7 -0
  51. package/dist/content/rules/ssr-safety.md +9 -0
  52. package/dist/content/skills/api-routes.md +33 -0
  53. package/dist/content/skills/continue-development.md +31 -0
  54. package/dist/content/skills/debugging.md +31 -0
  55. package/dist/content/skills/deployment.md +32 -0
  56. package/dist/content/skills/dev-server-management.md +31 -0
  57. package/dist/content/skills/env-vars.md +32 -0
  58. package/dist/content/skills/expo-router-architecture.md +33 -0
  59. package/dist/content/skills/expo-ssr-safety.md +32 -0
  60. package/dist/content/skills/plugin-creation.md +41 -0
  61. package/dist/content/skills/production-server-patterns.md +31 -0
  62. package/dist/content/skills/project-onboarding.md +31 -0
  63. package/dist/content/skills/research-plan-intake.md +31 -0
  64. package/dist/content/skills/seo-metadata.md +31 -0
  65. package/dist/content/skills/super-stack-startup.md +31 -0
  66. package/dist/content/skills/uniwind-theming.md +32 -0
  67. package/dist/index.d.ts +46 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +369 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/patterns/index.d.ts +78 -0
  72. package/dist/patterns/index.d.ts.map +1 -0
  73. package/dist/patterns/index.js +264 -0
  74. package/dist/patterns/index.js.map +1 -0
  75. package/dist/prompts/index.d.ts +35 -0
  76. package/dist/prompts/index.d.ts.map +1 -0
  77. package/dist/prompts/index.js +270 -0
  78. package/dist/prompts/index.js.map +1 -0
  79. package/dist/skills/index.d.ts +3 -0
  80. package/dist/skills/index.d.ts.map +1 -0
  81. package/dist/skills/index.js +2 -0
  82. package/dist/skills/index.js.map +1 -0
  83. package/package.json +50 -0
@@ -0,0 +1,521 @@
1
+ # Persistence Middleware Pattern
2
+
3
+ ## Description
4
+
5
+ Persistence middleware enables Zustand stores to automatically save state to AsyncStorage (mobile) or localStorage (web), with automatic hydration on app startup. This pattern provides offline-first state management where user data persists across app sessions and devices.
6
+
7
+ ## When to Use
8
+
9
+ **Use persistence middleware** for:
10
+ - ✅ User authentication (sessions, tokens, profiles)
11
+ - ✅ User preferences and settings
12
+ - ✅ Feature state (favorites, tracking, progress)
13
+ - ✅ Feature flags and configuration
14
+ - ✅ Offline-first user data
15
+ - ✅ Quick app resumption (instant state restoration)
16
+
17
+ **Don't persist:**
18
+ - ❌ Transient loading/error states
19
+ - ❌ Real-time data (scores, counts from API)
20
+ - ❌ Sensitive data (without encryption)
21
+ - ❌ Temporary UI state (modal visibility)
22
+
23
+ ## Core Concepts
24
+
25
+ **Persist middleware workflow:**
26
+ 1. **Initialize**: App loads, hydrate stored state from storage
27
+ 2. **Use**: Normal store operations, state updates automatically
28
+ 3. **Save**: Middleware detects changes, writes to storage
29
+ 4. **Restore**: User reopens app, stored state automatically loaded
30
+
31
+ **Storage options:**
32
+ - Mobile (React Native): `@react-native-async-storage/async-storage`
33
+ - Web: Built-in `localStorage`
34
+ - Cross-platform: Conditional import via platform detection
35
+
36
+ ## Code Example
37
+
38
+ ### Basic Persistence Setup
39
+
40
+ ```typescript
41
+ // File: src/store/authStore.ts
42
+ import { create } from 'zustand';
43
+ import { persist, createJSONStorage } from 'zustand/middleware';
44
+ import AsyncStorage from '@react-native-async-storage/async-storage';
45
+
46
+ interface AuthState {
47
+ user: User | null;
48
+ profile: Profile | null;
49
+ session: Session | null;
50
+ isLoggedIn: boolean;
51
+ loading: boolean;
52
+ error: string | null;
53
+
54
+ setUser: (user: User | null) => void;
55
+ signOut: () => Promise<void>;
56
+ }
57
+
58
+ export const useAuthStore = create<AuthState>()(
59
+ persist(
60
+ (set, get) => ({
61
+ // State and actions
62
+ user: null,
63
+ profile: null,
64
+ session: null,
65
+ isLoggedIn: false,
66
+ loading: true,
67
+ error: null,
68
+
69
+ setUser: (user) => set({ user, isLoggedIn: !!user }),
70
+
71
+ signOut: async () => {
72
+ await supabase.auth.signOut();
73
+ set({
74
+ user: null,
75
+ profile: null,
76
+ session: null,
77
+ isLoggedIn: false,
78
+ });
79
+ },
80
+ }),
81
+ {
82
+ // Persistence configuration
83
+ name: 'auth-storage', // Storage key
84
+ storage: createJSONStorage(() => AsyncStorage), // Storage adapter
85
+ partialize: (state) => ({ // Partial persistence
86
+ user: state.user,
87
+ profile: state.profile,
88
+ session: state.session,
89
+ // NOT persisted: loading, error (transient)
90
+ }),
91
+ }
92
+ )
93
+ );
94
+ ```
95
+
96
+ ### Cross-Platform Storage
97
+
98
+ ```typescript
99
+ // File: src/utils/storage.ts
100
+ import { Platform } from 'react-native';
101
+ import AsyncStorage from '@react-native-async-storage/async-storage';
102
+ import { StorageValue } from 'zustand/middleware';
103
+
104
+ /**
105
+ * Cross-platform storage adapter
106
+ * Mobile: AsyncStorage
107
+ * Web: localStorage
108
+ */
109
+ export const createCrossPlatformStorage = () => {
110
+ if (Platform.OS === 'web') {
111
+ return {
112
+ getItem: (name: string): StorageValue | null => {
113
+ const value = localStorage.getItem(name);
114
+ return value ? JSON.parse(value) : null;
115
+ },
116
+ setItem: (name: string, value: StorageValue): void => {
117
+ localStorage.setItem(name, JSON.stringify(value));
118
+ },
119
+ removeItem: (name: string): void => {
120
+ localStorage.removeItem(name);
121
+ },
122
+ };
123
+ }
124
+
125
+ return {
126
+ getItem: async (name: string): Promise<StorageValue | null> => {
127
+ const value = await AsyncStorage.getItem(name);
128
+ return value ? JSON.parse(value) : null;
129
+ },
130
+ setItem: async (name: string, value: StorageValue): Promise<void> => {
131
+ await AsyncStorage.setItem(name, JSON.stringify(value));
132
+ },
133
+ removeItem: async (name: string): Promise<void> => {
134
+ await AsyncStorage.removeItem(name);
135
+ },
136
+ };
137
+ };
138
+
139
+ // Usage
140
+ const storage = createCrossPlatformStorage();
141
+ ```
142
+
143
+ ### Partial Persistence Pattern
144
+
145
+ ```typescript
146
+ // File: src/store/settingsStore.ts
147
+ import { create } from 'zustand';
148
+ import { persist, createJSONStorage } from 'zustand/middleware';
149
+ import AsyncStorage from '@react-native-async-storage/async-storage';
150
+
151
+ interface SettingsState {
152
+ // User preferences (PERSIST these)
153
+ theme: 'light' | 'dark' | 'auto';
154
+ language: string;
155
+ notifications: boolean;
156
+ compactMode: boolean;
157
+
158
+ // Transient UI state (DON'T persist)
159
+ loading: boolean;
160
+ error: string | null;
161
+ syncInProgress: boolean;
162
+
163
+ // Actions
164
+ setTheme: (theme: 'light' | 'dark' | 'auto') => void;
165
+ setLanguage: (language: string) => void;
166
+ toggleNotifications: () => void;
167
+ setSyncInProgress: (inProgress: boolean) => void;
168
+ resetSettings: () => void;
169
+ }
170
+
171
+ const initialState: Pick<
172
+ SettingsState,
173
+ 'theme' | 'language' | 'notifications' | 'compactMode'
174
+ > = {
175
+ theme: 'auto',
176
+ language: 'en',
177
+ notifications: true,
178
+ compactMode: false,
179
+ };
180
+
181
+ export const useSettingsStore = create<SettingsState>()(
182
+ persist(
183
+ (set) => ({
184
+ ...initialState,
185
+
186
+ // Transient state
187
+ loading: false,
188
+ error: null,
189
+ syncInProgress: false,
190
+
191
+ // Actions
192
+ setTheme: (theme) => set({ theme }),
193
+ setLanguage: (language) => set({ language }),
194
+ toggleNotifications: () =>
195
+ set((state) => ({ notifications: !state.notifications })),
196
+ setSyncInProgress: (inProgress) => set({ syncInProgress: inProgress }),
197
+
198
+ resetSettings: () => set(initialState),
199
+ }),
200
+ {
201
+ name: 'settings-storage',
202
+ storage: createJSONStorage(() => AsyncStorage),
203
+
204
+ // Key pattern: Only persist user preferences, not transient state
205
+ partialize: (state) => ({
206
+ theme: state.theme,
207
+ language: state.language,
208
+ notifications: state.notifications,
209
+ compactMode: state.compactMode,
210
+ // Excluded: loading, error, syncInProgress
211
+ }),
212
+ }
213
+ )
214
+ );
215
+ ```
216
+
217
+ ### Middleware Composition
218
+
219
+ ```typescript
220
+ // File: src/store/appStore.ts
221
+ import { create } from 'zustand';
222
+ import { persist, createJSONStorage, devtools } from 'zustand/middleware';
223
+ import AsyncStorage from '@react-native-async-storage/async-storage';
224
+
225
+ interface AppState {
226
+ appVersion: string;
227
+ lastOpenedAt: number;
228
+ userPreferences: Record<string, any>;
229
+
230
+ setAppVersion: (version: string) => void;
231
+ updatePreference: (key: string, value: any) => void;
232
+ }
233
+
234
+ export const useAppStore = create<AppState>()(
235
+ devtools( // Dev tools wrapper (outer)
236
+ persist( // Persistence middleware (middle)
237
+ (set) => ({
238
+ appVersion: '1.0.0',
239
+ lastOpenedAt: Date.now(),
240
+ userPreferences: {},
241
+
242
+ setAppVersion: (version) => set({ appVersion: version }),
243
+
244
+ updatePreference: (key, value) =>
245
+ set((state) => ({
246
+ userPreferences: {
247
+ ...state.userPreferences,
248
+ [key]: value,
249
+ },
250
+ })),
251
+ }),
252
+ {
253
+ name: 'app-storage',
254
+ storage: createJSONStorage(() => AsyncStorage),
255
+ }
256
+ ),
257
+ { name: 'AppStore' }
258
+ )
259
+ );
260
+ ```
261
+
262
+ ### State Hydration & Initialization
263
+
264
+ ```typescript
265
+ // File: src/hooks/useAppInitialization.ts
266
+ import { useEffect, useState } from 'react';
267
+ import { useAuthStore } from '@/store/authStore';
268
+ import { useDexTrackerStore } from '@/store/dexTrackerStore';
269
+
270
+ /**
271
+ * Initialize app state on startup
272
+ * Hydrates persisted stores and performs async initialization
273
+ */
274
+ export function useAppInitialization() {
275
+ const [isReady, setIsReady] = useState(false);
276
+ const authStore = useAuthStore();
277
+ const dexStore = useDexTrackerStore();
278
+
279
+ useEffect(() => {
280
+ const initializeApp = async () => {
281
+ try {
282
+ // Stores auto-hydrate from storage (middleware)
283
+ // Do any async initialization after hydration
284
+ if (authStore.isLoggedIn && authStore.user) {
285
+ // Verify session is still valid
286
+ // Sync user data from API if needed
287
+ await authStore.initializeAuth();
288
+ }
289
+
290
+ // Other initialization tasks
291
+ // ...
292
+ } catch (error) {
293
+ console.error('App initialization error:', error);
294
+ } finally {
295
+ setIsReady(true);
296
+ }
297
+ };
298
+
299
+ initializeApp();
300
+ }, []);
301
+
302
+ return { isReady };
303
+ }
304
+
305
+ // Usage in root component
306
+ export function App() {
307
+ const { isReady } = useAppInitialization();
308
+
309
+ if (!isReady) {
310
+ return <SplashScreen />;
311
+ }
312
+
313
+ return <RootLayout />;
314
+ }
315
+ ```
316
+
317
+ ### Storage Migration Pattern
318
+
319
+ ```typescript
320
+ // File: src/utils/storageMigration.ts
321
+ import AsyncStorage from '@react-native-async-storage/async-storage';
322
+
323
+ /**
324
+ * Migrate persisted state when schema changes
325
+ * Called before store initialization
326
+ */
327
+ export async function migrateStorage() {
328
+ try {
329
+ const authData = await AsyncStorage.getItem('auth-storage');
330
+ if (!authData) return;
331
+
332
+ const state = JSON.parse(authData);
333
+
334
+ // Migrate from v1 to v2
335
+ if (state.version === 1) {
336
+ // Transform old structure to new structure
337
+ const migratedState = {
338
+ ...state,
339
+ version: 2,
340
+ // Add new fields with defaults
341
+ profile: state.profile || null,
342
+ // Remove deprecated fields
343
+ };
344
+
345
+ delete migratedState.oldField;
346
+
347
+ await AsyncStorage.setItem('auth-storage', JSON.stringify(migratedState));
348
+ }
349
+ } catch (error) {
350
+ console.error('Storage migration error:', error);
351
+ }
352
+ }
353
+
354
+ // Call during app initialization
355
+ export function App() {
356
+ useEffect(() => {
357
+ migrateStorage().then(() => {
358
+ // Initialize stores
359
+ });
360
+ }, []);
361
+ }
362
+ ```
363
+
364
+ ### Error Handling & Recovery
365
+
366
+ ```typescript
367
+ // File: src/store/withPersistenceError.ts
368
+ import { create } from 'zustand';
369
+ import { persist, createJSONStorage } from 'zustand/middleware';
370
+ import AsyncStorage from '@react-native-async-storage/async-storage';
371
+
372
+ interface SafeStorageState {
373
+ data: any;
374
+ storageError: string | null;
375
+ clearStorage: () => Promise<void>;
376
+ }
377
+
378
+ /**
379
+ * Storage adapter with error handling and recovery
380
+ */
381
+ const safeStorage = createJSONStorage(() => AsyncStorage);
382
+
383
+ const originalGetItem = safeStorage.getItem;
384
+ const originalSetItem = safeStorage.setItem;
385
+
386
+ const SafeJSONStorage = {
387
+ ...safeStorage,
388
+
389
+ getItem: async (name: string) => {
390
+ try {
391
+ return await originalGetItem(name);
392
+ } catch (error) {
393
+ console.error(`Error reading from storage (${name}):`, error);
394
+ // Return null on error - store will use defaults
395
+ return null;
396
+ }
397
+ },
398
+
399
+ setItem: async (name: string, value: any) => {
400
+ try {
401
+ await originalSetItem(name, value);
402
+ } catch (error) {
403
+ console.error(`Error writing to storage (${name}):`, error);
404
+ // Continue - store remains in memory even if storage fails
405
+ }
406
+ },
407
+
408
+ removeItem: async (name: string) => {
409
+ try {
410
+ await safeStorage.removeItem(name);
411
+ } catch (error) {
412
+ console.error(`Error removing storage (${name}):`, error);
413
+ }
414
+ },
415
+ };
416
+
417
+ // Use in store
418
+ export const useSafeStore = create<SafeStorageState>()(
419
+ persist(
420
+ (set) => ({
421
+ data: null,
422
+ storageError: null,
423
+
424
+ clearStorage: async () => {
425
+ try {
426
+ await AsyncStorage.removeItem('safe-storage');
427
+ set({ data: null });
428
+ } catch (error) {
429
+ set({
430
+ storageError: error instanceof Error ? error.message : 'Unknown error',
431
+ });
432
+ }
433
+ },
434
+ }),
435
+ {
436
+ name: 'safe-storage',
437
+ storage: SafeJSONStorage,
438
+ }
439
+ )
440
+ );
441
+ ```
442
+
443
+ ## Persistence Best Practices
444
+
445
+ ### ✅ DO
446
+
447
+ 1. **Partition persistent vs transient state**
448
+ ```typescript
449
+ partialize: (state) => ({
450
+ user: state.user, // ✅ Persist
451
+ preferences: state.preferences,
452
+ isLoggedIn: state.isLoggedIn,
453
+ // NOT included: loading, error (transient)
454
+ })
455
+ ```
456
+
457
+ 2. **Use reasonable storage keys**
458
+ ```typescript
459
+ {
460
+ name: 'auth-storage', // ✅ Descriptive
461
+ // NOT 'store1', 'store-2', etc.
462
+ }
463
+ ```
464
+
465
+ 3. **Handle storage errors gracefully**
466
+ ```typescript
467
+ try {
468
+ await AsyncStorage.setItem(key, value);
469
+ } catch (error) {
470
+ // Log but continue - state still in memory
471
+ console.error('Storage write failed:', error);
472
+ }
473
+ ```
474
+
475
+ ### ❌ DON'T
476
+
477
+ 1. **Don't persist sensitive data without encryption**
478
+ ```typescript
479
+ // ❌ WRONG
480
+ partialize: (state) => ({
481
+ apiKey: state.apiKey, // Never persist secrets!
482
+ password: state.password,
483
+ })
484
+
485
+ // ✅ RIGHT
486
+ // Store sensitive data in secure storage (expo-secure-store, etc.)
487
+ ```
488
+
489
+ 2. **Don't create too many storage keys**
490
+ ```typescript
491
+ // ❌ WRONG - Storage bloat
492
+ persist((set) => ({...}), { name: 'store1' })
493
+ persist((set) => ({...}), { name: 'store2' })
494
+ persist((set) => ({...}), { name: 'store3' })
495
+
496
+ // ✅ RIGHT - Organized stores with clear names
497
+ persist((set) => ({...}), { name: 'auth-storage' })
498
+ persist((set) => ({...}), { name: 'settings-storage' })
499
+ ```
500
+
501
+ 3. **Don't forget migration strategy**
502
+ ```typescript
503
+ // ✅ Always include version field
504
+ partialize: (state) => ({
505
+ version: 1,
506
+ user: state.user,
507
+ })
508
+
509
+ // Then check version on init and migrate if needed
510
+ ```
511
+
512
+ ## Related Patterns
513
+
514
+ - [Store Organization](./store-organization.md) — Multi-store architecture
515
+ - [Selector Hooks](./selector-hooks.md) — Performance optimization
516
+ - [Zustand Patterns](./zustand-patterns.md) — Zustand fundamentals
517
+
518
+ ---
519
+
520
+ *Pattern extracted from production repositories: core-monorepo, PokePages, DJsPortfolio*
521
+ *Files: src/store/ directory with persist middleware*