@react-spa-scaffold/mcp 2.1.1 → 2.3.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 (168) hide show
  1. package/README.md +2 -1
  2. package/dist/constants.d.ts +4 -0
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +4 -0
  5. package/dist/constants.js.map +1 -1
  6. package/dist/features/definitions/auth.d.ts +3 -0
  7. package/dist/features/definitions/auth.d.ts.map +1 -0
  8. package/dist/features/definitions/auth.js +17 -0
  9. package/dist/features/definitions/auth.js.map +1 -0
  10. package/dist/features/definitions/core.d.ts.map +1 -1
  11. package/dist/features/definitions/core.js +16 -1
  12. package/dist/features/definitions/core.js.map +1 -1
  13. package/dist/features/definitions/database.d.ts +3 -0
  14. package/dist/features/definitions/database.d.ts.map +1 -0
  15. package/dist/features/definitions/database.js +45 -0
  16. package/dist/features/definitions/database.js.map +1 -0
  17. package/dist/features/definitions/deployment.d.ts +3 -0
  18. package/dist/features/definitions/deployment.d.ts.map +1 -0
  19. package/dist/features/definitions/deployment.js +14 -0
  20. package/dist/features/definitions/deployment.js.map +1 -0
  21. package/dist/features/definitions/forms.d.ts.map +1 -1
  22. package/dist/features/definitions/forms.js +4 -0
  23. package/dist/features/definitions/forms.js.map +1 -1
  24. package/dist/features/definitions/index.d.ts +3 -0
  25. package/dist/features/definitions/index.d.ts.map +1 -1
  26. package/dist/features/definitions/index.js +3 -0
  27. package/dist/features/definitions/index.js.map +1 -1
  28. package/dist/features/definitions/mobile.d.ts.map +1 -1
  29. package/dist/features/definitions/mobile.js +11 -2
  30. package/dist/features/definitions/mobile.js.map +1 -1
  31. package/dist/features/definitions/observability.js +1 -1
  32. package/dist/features/definitions/observability.js.map +1 -1
  33. package/dist/features/definitions/routing.d.ts.map +1 -1
  34. package/dist/features/definitions/routing.js +2 -1
  35. package/dist/features/definitions/routing.js.map +1 -1
  36. package/dist/features/definitions/state.d.ts.map +1 -1
  37. package/dist/features/definitions/state.js +9 -2
  38. package/dist/features/definitions/state.js.map +1 -1
  39. package/dist/features/definitions/testing.d.ts.map +1 -1
  40. package/dist/features/definitions/testing.js +4 -2
  41. package/dist/features/definitions/testing.js.map +1 -1
  42. package/dist/features/registry.d.ts.map +1 -1
  43. package/dist/features/registry.js +4 -1
  44. package/dist/features/registry.js.map +1 -1
  45. package/dist/features/types.test.js +6 -2
  46. package/dist/features/types.test.js.map +1 -1
  47. package/dist/resources/docs.d.ts.map +1 -1
  48. package/dist/resources/docs.js +5 -0
  49. package/dist/resources/docs.js.map +1 -1
  50. package/dist/tools/add-features.js +1 -1
  51. package/dist/tools/add-features.js.map +1 -1
  52. package/dist/utils/docs.d.ts.map +1 -1
  53. package/dist/utils/docs.js +2 -0
  54. package/dist/utils/docs.js.map +1 -1
  55. package/dist/utils/scaffold/claude-md/index.d.ts.map +1 -1
  56. package/dist/utils/scaffold/claude-md/index.js +3 -1
  57. package/dist/utils/scaffold/claude-md/index.js.map +1 -1
  58. package/dist/utils/scaffold/claude-md/sections.d.ts +2 -0
  59. package/dist/utils/scaffold/claude-md/sections.d.ts.map +1 -1
  60. package/dist/utils/scaffold/claude-md/sections.js +132 -2
  61. package/dist/utils/scaffold/claude-md/sections.js.map +1 -1
  62. package/dist/utils/scaffold/compute.js +1 -1
  63. package/dist/utils/scaffold/compute.js.map +1 -1
  64. package/dist/utils/scaffold/generators.d.ts +2 -2
  65. package/dist/utils/scaffold/generators.d.ts.map +1 -1
  66. package/dist/utils/scaffold/generators.js +64 -22
  67. package/dist/utils/scaffold/generators.js.map +1 -1
  68. package/package.json +1 -1
  69. package/templates/.env.example +44 -10
  70. package/templates/.github/workflows/ci.yml +12 -4
  71. package/templates/.github/workflows/deploy.yml +59 -0
  72. package/templates/CLAUDE.md +251 -2
  73. package/templates/docs/ARCHITECTURE.md +13 -12
  74. package/templates/docs/AUTHENTICATION.md +325 -0
  75. package/templates/docs/CODING_STANDARDS.md +65 -0
  76. package/templates/docs/DEPLOYMENT.md +268 -0
  77. package/templates/docs/E2E_TESTING.md +133 -11
  78. package/templates/docs/SUPABASE_INTEGRATION.md +310 -0
  79. package/templates/docs/TESTING.md +195 -77
  80. package/templates/e2e/auth/auth.setup.ts +60 -0
  81. package/templates/e2e/fixtures/index.ts +24 -2
  82. package/templates/e2e/tests/profile.auth.spec.ts +103 -0
  83. package/templates/e2e/tests/profile.spec.ts +64 -0
  84. package/templates/e2e/tests/register-form.spec.ts +38 -0
  85. package/templates/gitignore +5 -0
  86. package/templates/package.json +15 -3
  87. package/templates/playwright.config.ts +39 -4
  88. package/templates/src/App.tsx +32 -19
  89. package/templates/src/components/layout/Header.test.tsx +17 -1
  90. package/templates/src/components/layout/Header.tsx +13 -1
  91. package/templates/src/components/shared/AccountButton/AccountButton.test.tsx +30 -0
  92. package/templates/src/components/shared/AccountButton/AccountButton.tsx +38 -0
  93. package/templates/src/components/shared/AccountButton/index.ts +1 -0
  94. package/templates/src/components/shared/ErrorBoundary/ErrorBoundary.test.tsx +4 -4
  95. package/templates/src/components/shared/ErrorBoundary/ErrorBoundary.tsx +55 -53
  96. package/templates/src/components/shared/ProfileSync/ProfileSync.test.tsx +44 -0
  97. package/templates/src/components/shared/ProfileSync/ProfileSync.tsx +104 -0
  98. package/templates/src/components/shared/ProfileSync/index.ts +1 -0
  99. package/templates/src/components/shared/ProtectedRoute/ProtectedRoute.test.tsx +43 -0
  100. package/templates/src/components/shared/ProtectedRoute/ProtectedRoute.tsx +35 -0
  101. package/templates/src/components/shared/ProtectedRoute/index.ts +1 -0
  102. package/templates/src/components/shared/index.ts +5 -2
  103. package/templates/src/contexts/clerkContext.tsx +45 -0
  104. package/templates/src/contexts/performanceContext.tsx +3 -3
  105. package/templates/src/contexts/supabaseContext.test.tsx +59 -0
  106. package/templates/src/contexts/supabaseContext.tsx +87 -0
  107. package/templates/src/hooks/index.ts +40 -2
  108. package/templates/src/hooks/supabase/index.ts +12 -0
  109. package/templates/src/hooks/supabase/useProfiles.test.tsx +207 -0
  110. package/templates/src/hooks/supabase/useProfiles.ts +213 -0
  111. package/templates/src/hooks/supabase/useSupabaseQuery.test.tsx +150 -0
  112. package/templates/src/hooks/supabase/useSupabaseQuery.ts +91 -0
  113. package/templates/src/hooks/useCopyFeedback.test.ts +129 -0
  114. package/templates/src/hooks/useCopyFeedback.ts +41 -0
  115. package/templates/src/hooks/useDebouncedCallback.test.ts +164 -0
  116. package/templates/src/hooks/useDebouncedCallback.ts +47 -0
  117. package/templates/src/hooks/useDocumentTitle.test.ts +59 -0
  118. package/templates/src/hooks/useDocumentTitle.ts +31 -0
  119. package/templates/src/hooks/useIOSViewportReset.test.ts +58 -0
  120. package/templates/src/hooks/useIOSViewportReset.ts +18 -0
  121. package/templates/src/hooks/useKeyboardShortcut.test.ts +86 -0
  122. package/templates/src/hooks/useKeyboardShortcuts.ts +44 -0
  123. package/templates/src/hooks/useLocalStorage.test.ts +111 -0
  124. package/templates/src/hooks/useLocalStorage.ts +77 -0
  125. package/templates/src/hooks/useSyncedFormData.test.ts +75 -0
  126. package/templates/src/hooks/useSyncedFormData.ts +21 -0
  127. package/templates/src/hooks/useSyncedState.test.ts +119 -0
  128. package/templates/src/hooks/useSyncedState.ts +30 -0
  129. package/templates/src/index.css +1 -0
  130. package/templates/src/lib/api.test.ts +30 -38
  131. package/templates/src/lib/api.ts +1 -7
  132. package/templates/src/lib/config.ts +54 -4
  133. package/templates/src/lib/constants.ts +10 -0
  134. package/templates/src/lib/createSelectors.test.ts +136 -0
  135. package/templates/src/lib/createSelectors.ts +31 -0
  136. package/templates/src/lib/env.ts +36 -14
  137. package/templates/src/lib/index.ts +5 -2
  138. package/templates/src/lib/routes.ts +1 -0
  139. package/templates/src/lib/sentry.ts +58 -0
  140. package/templates/src/lib/storage.ts +6 -2
  141. package/templates/src/lib/supabase/client.ts +58 -0
  142. package/templates/src/lib/supabase/index.ts +5 -0
  143. package/templates/src/main.tsx +19 -31
  144. package/templates/src/mocks/constants.ts +31 -0
  145. package/templates/src/mocks/fixtures/index.ts +3 -1
  146. package/templates/src/mocks/fixtures/profiles.ts +55 -0
  147. package/templates/src/mocks/fixtures/users.ts +91 -0
  148. package/templates/src/mocks/handlers/index.ts +2 -1
  149. package/templates/src/mocks/handlers/supabase.ts +64 -0
  150. package/templates/src/mocks/handlers/todos.ts +1 -1
  151. package/templates/src/mocks/index.ts +6 -0
  152. package/templates/src/pages/Profile.test.tsx +263 -0
  153. package/templates/src/pages/Profile.tsx +171 -0
  154. package/templates/src/pages/index.ts +1 -0
  155. package/templates/src/stores/preferencesStore.ts +35 -9
  156. package/templates/src/test/clerkMock.tsx +137 -0
  157. package/templates/src/test/fetchMock.ts +58 -0
  158. package/templates/src/test/index.ts +51 -2
  159. package/templates/src/test/mocks.ts +128 -1
  160. package/templates/src/test/providers.tsx +10 -4
  161. package/templates/src/test/supabaseMock.ts +112 -0
  162. package/templates/src/test-setup.ts +42 -2
  163. package/templates/src/types/database.ts +46 -0
  164. package/templates/src/types/index.ts +1 -0
  165. package/templates/src/types/supabase.ts +167 -0
  166. package/templates/src/vite-env.d.ts +6 -0
  167. package/templates/supabase/migrations/20260104000000_create_profiles_table.sql +67 -0
  168. package/templates/vitest.config.ts +9 -1
@@ -0,0 +1,167 @@
1
+ export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
2
+
3
+ export type Database = {
4
+ // Allows to automatically instantiate createClient with right options
5
+ // instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY)
6
+ __InternalSupabase: {
7
+ PostgrestVersion: '14.1';
8
+ };
9
+ public: {
10
+ Tables: {
11
+ profiles: {
12
+ Row: {
13
+ avatar_url: string | null;
14
+ created_at: string | null;
15
+ email: string;
16
+ full_name: string | null;
17
+ id: string;
18
+ updated_at: string | null;
19
+ };
20
+ Insert: {
21
+ avatar_url?: string | null;
22
+ created_at?: string | null;
23
+ email: string;
24
+ full_name?: string | null;
25
+ id: string;
26
+ updated_at?: string | null;
27
+ };
28
+ Update: {
29
+ avatar_url?: string | null;
30
+ created_at?: string | null;
31
+ email?: string;
32
+ full_name?: string | null;
33
+ id?: string;
34
+ updated_at?: string | null;
35
+ };
36
+ Relationships: [];
37
+ };
38
+ };
39
+ Views: {
40
+ [_ in never]: never;
41
+ };
42
+ Functions: {
43
+ [_ in never]: never;
44
+ };
45
+ Enums: {
46
+ [_ in never]: never;
47
+ };
48
+ CompositeTypes: {
49
+ [_ in never]: never;
50
+ };
51
+ };
52
+ };
53
+
54
+ type DatabaseWithoutInternals = Omit<Database, '__InternalSupabase'>;
55
+
56
+ type DefaultSchema = DatabaseWithoutInternals[Extract<keyof Database, 'public'>];
57
+
58
+ export type Tables<
59
+ DefaultSchemaTableNameOrOptions extends
60
+ | keyof (DefaultSchema['Tables'] & DefaultSchema['Views'])
61
+ | { schema: keyof DatabaseWithoutInternals },
62
+ TableName extends DefaultSchemaTableNameOrOptions extends {
63
+ schema: keyof DatabaseWithoutInternals;
64
+ }
65
+ ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
66
+ DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views'])
67
+ : never = never,
68
+ > = DefaultSchemaTableNameOrOptions extends {
69
+ schema: keyof DatabaseWithoutInternals;
70
+ }
71
+ ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
72
+ DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends {
73
+ Row: infer R;
74
+ }
75
+ ? R
76
+ : never
77
+ : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] & DefaultSchema['Views'])
78
+ ? (DefaultSchema['Tables'] & DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends {
79
+ Row: infer R;
80
+ }
81
+ ? R
82
+ : never
83
+ : never;
84
+
85
+ export type TablesInsert<
86
+ DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] | { schema: keyof DatabaseWithoutInternals },
87
+ TableName extends DefaultSchemaTableNameOrOptions extends {
88
+ schema: keyof DatabaseWithoutInternals;
89
+ }
90
+ ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables']
91
+ : never = never,
92
+ > = DefaultSchemaTableNameOrOptions extends {
93
+ schema: keyof DatabaseWithoutInternals;
94
+ }
95
+ ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
96
+ Insert: infer I;
97
+ }
98
+ ? I
99
+ : never
100
+ : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
101
+ ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
102
+ Insert: infer I;
103
+ }
104
+ ? I
105
+ : never
106
+ : never;
107
+
108
+ export type TablesUpdate<
109
+ DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] | { schema: keyof DatabaseWithoutInternals },
110
+ TableName extends DefaultSchemaTableNameOrOptions extends {
111
+ schema: keyof DatabaseWithoutInternals;
112
+ }
113
+ ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables']
114
+ : never = never,
115
+ > = DefaultSchemaTableNameOrOptions extends {
116
+ schema: keyof DatabaseWithoutInternals;
117
+ }
118
+ ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
119
+ Update: infer U;
120
+ }
121
+ ? U
122
+ : never
123
+ : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
124
+ ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
125
+ Update: infer U;
126
+ }
127
+ ? U
128
+ : never
129
+ : never;
130
+
131
+ export type Enums<
132
+ DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums'] | { schema: keyof DatabaseWithoutInternals },
133
+ EnumName extends DefaultSchemaEnumNameOrOptions extends {
134
+ schema: keyof DatabaseWithoutInternals;
135
+ }
136
+ ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums']
137
+ : never = never,
138
+ > = DefaultSchemaEnumNameOrOptions extends {
139
+ schema: keyof DatabaseWithoutInternals;
140
+ }
141
+ ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName]
142
+ : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums']
143
+ ? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions]
144
+ : never;
145
+
146
+ export type CompositeTypes<
147
+ PublicCompositeTypeNameOrOptions extends
148
+ | keyof DefaultSchema['CompositeTypes']
149
+ | { schema: keyof DatabaseWithoutInternals },
150
+ CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
151
+ schema: keyof DatabaseWithoutInternals;
152
+ }
153
+ ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes']
154
+ : never = never,
155
+ > = PublicCompositeTypeNameOrOptions extends {
156
+ schema: keyof DatabaseWithoutInternals;
157
+ }
158
+ ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName]
159
+ : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes']
160
+ ? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions]
161
+ : never;
162
+
163
+ export const Constants = {
164
+ public: {
165
+ Enums: {},
166
+ },
167
+ } as const;
@@ -3,6 +3,12 @@
3
3
  interface ImportMetaEnv {
4
4
  readonly VITE_APP_NAME: string;
5
5
  readonly VITE_APP_URL: string;
6
+ readonly VITE_API_URL?: string;
7
+ readonly VITE_SENTRY_DSN?: string;
8
+ readonly VITE_CLERK_PUBLISHABLE_KEY?: string;
9
+ readonly MODE: 'development' | 'production' | 'test';
10
+ readonly DEV: boolean;
11
+ readonly PROD: boolean;
6
12
  }
7
13
 
8
14
  interface ImportMeta {
@@ -0,0 +1,67 @@
1
+ -- ============================================================
2
+ -- PROFILES TABLE (linked to Clerk user_id)
3
+ -- ============================================================
4
+
5
+ -- Create the table
6
+ CREATE TABLE IF NOT EXISTS profiles (
7
+ id TEXT PRIMARY KEY, -- Clerk user_id (from auth.uid())
8
+ email TEXT NOT NULL,
9
+ full_name TEXT,
10
+ avatar_url TEXT,
11
+ created_at TIMESTAMPTZ DEFAULT NOW(),
12
+ updated_at TIMESTAMPTZ DEFAULT NOW()
13
+ );
14
+
15
+ -- Enable Row Level Security
16
+ ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
17
+
18
+ -- ============================================================
19
+ -- RLS POLICIES
20
+ -- Using auth.jwt()->>'sub' for Clerk compatibility (string IDs)
21
+ -- ============================================================
22
+
23
+ -- Users can view their own profile
24
+ -- NOTE: Using auth.jwt()->>'sub' instead of auth.uid() because
25
+ -- Clerk user IDs are strings (e.g., user_xxx), not UUIDs
26
+ CREATE POLICY "Users can view own profile"
27
+ ON profiles FOR SELECT TO authenticated
28
+ USING (id = (select auth.jwt()->>'sub'));
29
+
30
+ -- Users can insert their own profile (first login)
31
+ CREATE POLICY "Users can insert own profile"
32
+ ON profiles FOR INSERT TO authenticated
33
+ WITH CHECK (id = (select auth.jwt()->>'sub'));
34
+
35
+ -- Users can update their own profile
36
+ CREATE POLICY "Users can update own profile"
37
+ ON profiles FOR UPDATE TO authenticated
38
+ USING (id = (select auth.jwt()->>'sub'))
39
+ WITH CHECK (id = (select auth.jwt()->>'sub'));
40
+
41
+ -- Users can delete their own profile
42
+ CREATE POLICY "Users can delete own profile"
43
+ ON profiles FOR DELETE TO authenticated
44
+ USING (id = (select auth.jwt()->>'sub'));
45
+
46
+ -- ============================================================
47
+ -- AUTO-UPDATE TIMESTAMP TRIGGER
48
+ -- ============================================================
49
+
50
+ -- Function to update updated_at (with secure search_path)
51
+ CREATE OR REPLACE FUNCTION public.update_updated_at()
52
+ RETURNS TRIGGER
53
+ LANGUAGE plpgsql
54
+ SECURITY DEFINER
55
+ SET search_path = ''
56
+ AS $$
57
+ BEGIN
58
+ NEW.updated_at = NOW();
59
+ RETURN NEW;
60
+ END;
61
+ $$;
62
+
63
+ -- Trigger for profiles
64
+ CREATE TRIGGER profiles_updated_at
65
+ BEFORE UPDATE ON profiles
66
+ FOR EACH ROW
67
+ EXECUTE FUNCTION update_updated_at();
@@ -21,7 +21,15 @@ export default defineConfig({
21
21
  coverage: {
22
22
  provider: 'v8',
23
23
  reporter: ['text', 'json', 'html', 'lcov'],
24
- exclude: ['**/*.test.{ts,tsx}', '**/index.ts', 'src/types/**', 'src/components/ui/**', 'src/mocks/**'],
24
+ exclude: [
25
+ '**/*.test.{ts,tsx}',
26
+ '**/index.ts',
27
+ 'src/types/**',
28
+ 'src/components/ui/**',
29
+ 'src/mocks/**',
30
+ 'src/test/**', // Test utilities and mocks
31
+ 'src/lib/sentry.ts', // Production-only, lazily loaded
32
+ ],
25
33
  thresholds: {
26
34
  lines: 80,
27
35
  functions: 80,