tools-template-cli 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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/dist/index.js +380 -0
  4. package/dist/templates.js +44 -0
  5. package/package.json +49 -0
  6. package/supabase-expo-app/.env.example +2 -0
  7. package/supabase-expo-app/App.tsx +55 -0
  8. package/supabase-expo-app/README.md +179 -0
  9. package/supabase-expo-app/app.json +34 -0
  10. package/supabase-expo-app/assets/adaptive-icon.png +0 -0
  11. package/supabase-expo-app/assets/favicon.png +0 -0
  12. package/supabase-expo-app/assets/icon.png +0 -0
  13. package/supabase-expo-app/assets/splash-icon.png +0 -0
  14. package/supabase-expo-app/components/Account.tsx +234 -0
  15. package/supabase-expo-app/components/Auth.tsx +161 -0
  16. package/supabase-expo-app/components/Avatar.tsx +173 -0
  17. package/supabase-expo-app/index.ts +8 -0
  18. package/supabase-expo-app/lib/supabase.ts +63 -0
  19. package/supabase-expo-app/package-lock.json +8983 -0
  20. package/supabase-expo-app/package.json +32 -0
  21. package/supabase-expo-app/scripts/setup-supabase.sh +73 -0
  22. package/supabase-expo-app/supabase/schema.sql +57 -0
  23. package/supabase-expo-app/tsconfig.json +6 -0
  24. package/supabase-swiftui-app/Package.swift +32 -0
  25. package/supabase-swiftui-app/README.md +215 -0
  26. package/supabase-swiftui-app/SupabaseSwiftUIApp/AccountView.swift +181 -0
  27. package/supabase-swiftui-app/SupabaseSwiftUIApp/AuthView.swift +123 -0
  28. package/supabase-swiftui-app/SupabaseSwiftUIApp/AvatarView.swift +113 -0
  29. package/supabase-swiftui-app/SupabaseSwiftUIApp/ContentView.swift +18 -0
  30. package/supabase-swiftui-app/SupabaseSwiftUIApp/Supabase.swift +13 -0
  31. package/supabase-swiftui-app/SupabaseSwiftUIApp/SupabaseSwiftUIApp.swift +22 -0
  32. package/supabase-swiftui-app/scripts/setup-supabase.sh +67 -0
  33. package/supabase-swiftui-app/supabase/schema.sql +57 -0
  34. package/supabase-user-management/AGENTS.md +5 -0
  35. package/supabase-user-management/CLAUDE.md +1 -0
  36. package/supabase-user-management/README.md +178 -0
  37. package/supabase-user-management/app/account/account-form.tsx +174 -0
  38. package/supabase-user-management/app/account/avatar.tsx +109 -0
  39. package/supabase-user-management/app/account/page.tsx +28 -0
  40. package/supabase-user-management/app/auth/confirm/route.ts +26 -0
  41. package/supabase-user-management/app/error.tsx +14 -0
  42. package/supabase-user-management/app/favicon.ico +0 -0
  43. package/supabase-user-management/app/globals.css +130 -0
  44. package/supabase-user-management/app/layout.tsx +22 -0
  45. package/supabase-user-management/app/loading.tsx +7 -0
  46. package/supabase-user-management/app/login/actions.ts +45 -0
  47. package/supabase-user-management/app/login/page.tsx +90 -0
  48. package/supabase-user-management/app/page.tsx +16 -0
  49. package/supabase-user-management/components/ui/button.tsx +58 -0
  50. package/supabase-user-management/components.json +25 -0
  51. package/supabase-user-management/eslint.config.mjs +18 -0
  52. package/supabase-user-management/lib/supabase/client.ts +8 -0
  53. package/supabase-user-management/lib/supabase/middleware.ts +52 -0
  54. package/supabase-user-management/lib/supabase/server.ts +29 -0
  55. package/supabase-user-management/lib/utils.ts +6 -0
  56. package/supabase-user-management/next.config.ts +7 -0
  57. package/supabase-user-management/package-lock.json +9910 -0
  58. package/supabase-user-management/package.json +36 -0
  59. package/supabase-user-management/postcss.config.mjs +7 -0
  60. package/supabase-user-management/public/file.svg +1 -0
  61. package/supabase-user-management/public/globe.svg +1 -0
  62. package/supabase-user-management/public/next.svg +1 -0
  63. package/supabase-user-management/public/vercel.svg +1 -0
  64. package/supabase-user-management/public/window.svg +1 -0
  65. package/supabase-user-management/scripts/setup-supabase.sh +98 -0
  66. package/supabase-user-management/src/proxy.ts +12 -0
  67. package/supabase-user-management/supabase/schema.sql +57 -0
  68. package/supabase-user-management/tsconfig.json +34 -0
  69. package/supabase_flutter_app/.metadata +45 -0
  70. package/supabase_flutter_app/README.md +195 -0
  71. package/supabase_flutter_app/analysis_options.yaml +28 -0
  72. package/supabase_flutter_app/android/app/build.gradle.kts +44 -0
  73. package/supabase_flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  74. package/supabase_flutter_app/android/app/src/main/AndroidManifest.xml +54 -0
  75. package/supabase_flutter_app/android/app/src/main/kotlin/com/example/supabase_flutter_app/MainActivity.kt +5 -0
  76. package/supabase_flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  77. package/supabase_flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  78. package/supabase_flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  79. package/supabase_flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  80. package/supabase_flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  81. package/supabase_flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  82. package/supabase_flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  83. package/supabase_flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  84. package/supabase_flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  85. package/supabase_flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  86. package/supabase_flutter_app/android/build.gradle.kts +24 -0
  87. package/supabase_flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  88. package/supabase_flutter_app/android/gradle.properties +2 -0
  89. package/supabase_flutter_app/android/settings.gradle.kts +26 -0
  90. package/supabase_flutter_app/ios/Flutter/AppFrameworkInfo.plist +26 -0
  91. package/supabase_flutter_app/ios/Flutter/Debug.xcconfig +2 -0
  92. package/supabase_flutter_app/ios/Flutter/Release.xcconfig +2 -0
  93. package/supabase_flutter_app/ios/Podfile +43 -0
  94. package/supabase_flutter_app/ios/Runner/AppDelegate.swift +13 -0
  95. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
  96. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
  97. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
  98. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
  99. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
  100. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
  101. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
  102. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
  103. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
  104. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
  105. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
  106. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
  107. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
  108. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
  109. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
  110. package/supabase_flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
  111. package/supabase_flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
  112. package/supabase_flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
  113. package/supabase_flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
  114. package/supabase_flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
  115. package/supabase_flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
  116. package/supabase_flutter_app/ios/Runner/Base.lproj/LaunchScreen.storyboard +37 -0
  117. package/supabase_flutter_app/ios/Runner/Base.lproj/Main.storyboard +26 -0
  118. package/supabase_flutter_app/ios/Runner/Info.plist +61 -0
  119. package/supabase_flutter_app/ios/Runner/Runner-Bridging-Header.h +1 -0
  120. package/supabase_flutter_app/ios/Runner.xcodeproj/project.pbxproj +619 -0
  121. package/supabase_flutter_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  122. package/supabase_flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  123. package/supabase_flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  124. package/supabase_flutter_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
  125. package/supabase_flutter_app/ios/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  126. package/supabase_flutter_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  127. package/supabase_flutter_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  128. package/supabase_flutter_app/ios/RunnerTests/RunnerTests.swift +12 -0
  129. package/supabase_flutter_app/lib/components/avatar.dart +153 -0
  130. package/supabase_flutter_app/lib/main.dart +70 -0
  131. package/supabase_flutter_app/lib/pages/account_page.dart +189 -0
  132. package/supabase_flutter_app/lib/pages/login_page.dart +150 -0
  133. package/supabase_flutter_app/linux/CMakeLists.txt +128 -0
  134. package/supabase_flutter_app/linux/flutter/CMakeLists.txt +88 -0
  135. package/supabase_flutter_app/linux/flutter/generated_plugin_registrant.cc +23 -0
  136. package/supabase_flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  137. package/supabase_flutter_app/linux/flutter/generated_plugins.cmake +26 -0
  138. package/supabase_flutter_app/linux/runner/CMakeLists.txt +26 -0
  139. package/supabase_flutter_app/linux/runner/main.cc +6 -0
  140. package/supabase_flutter_app/linux/runner/my_application.cc +148 -0
  141. package/supabase_flutter_app/linux/runner/my_application.h +21 -0
  142. package/supabase_flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  143. package/supabase_flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  144. package/supabase_flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +18 -0
  145. package/supabase_flutter_app/macos/Podfile +42 -0
  146. package/supabase_flutter_app/macos/Runner/AppDelegate.swift +13 -0
  147. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  148. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  149. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  150. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  151. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  152. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  153. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  154. package/supabase_flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  155. package/supabase_flutter_app/macos/Runner/Base.lproj/MainMenu.xib +343 -0
  156. package/supabase_flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  157. package/supabase_flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  158. package/supabase_flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  159. package/supabase_flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  160. package/supabase_flutter_app/macos/Runner/DebugProfile.entitlements +12 -0
  161. package/supabase_flutter_app/macos/Runner/Info.plist +32 -0
  162. package/supabase_flutter_app/macos/Runner/MainFlutterWindow.swift +15 -0
  163. package/supabase_flutter_app/macos/Runner/Release.entitlements +8 -0
  164. package/supabase_flutter_app/macos/Runner.xcodeproj/project.pbxproj +705 -0
  165. package/supabase_flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  166. package/supabase_flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  167. package/supabase_flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  168. package/supabase_flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  169. package/supabase_flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  170. package/supabase_flutter_app/pubspec.lock +818 -0
  171. package/supabase_flutter_app/pubspec.yaml +26 -0
  172. package/supabase_flutter_app/scripts/setup-supabase.sh +72 -0
  173. package/supabase_flutter_app/supabase/schema.sql +57 -0
  174. package/supabase_flutter_app/test/widget_test.dart +30 -0
  175. package/supabase_flutter_app/web/favicon.png +0 -0
  176. package/supabase_flutter_app/web/icons/Icon-192.png +0 -0
  177. package/supabase_flutter_app/web/icons/Icon-512.png +0 -0
  178. package/supabase_flutter_app/web/icons/Icon-maskable-192.png +0 -0
  179. package/supabase_flutter_app/web/icons/Icon-maskable-512.png +0 -0
  180. package/supabase_flutter_app/web/index.html +38 -0
  181. package/supabase_flutter_app/web/manifest.json +35 -0
  182. package/supabase_flutter_app/windows/CMakeLists.txt +108 -0
  183. package/supabase_flutter_app/windows/flutter/CMakeLists.txt +109 -0
  184. package/supabase_flutter_app/windows/flutter/generated_plugin_registrant.cc +20 -0
  185. package/supabase_flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  186. package/supabase_flutter_app/windows/flutter/generated_plugins.cmake +26 -0
  187. package/supabase_flutter_app/windows/runner/CMakeLists.txt +40 -0
  188. package/supabase_flutter_app/windows/runner/Runner.rc +121 -0
  189. package/supabase_flutter_app/windows/runner/flutter_window.cpp +71 -0
  190. package/supabase_flutter_app/windows/runner/flutter_window.h +33 -0
  191. package/supabase_flutter_app/windows/runner/main.cpp +43 -0
  192. package/supabase_flutter_app/windows/runner/resource.h +16 -0
  193. package/supabase_flutter_app/windows/runner/resources/app_icon.ico +0 -0
  194. package/supabase_flutter_app/windows/runner/runner.exe.manifest +14 -0
  195. package/supabase_flutter_app/windows/runner/utils.cpp +65 -0
  196. package/supabase_flutter_app/windows/runner/utils.h +19 -0
  197. package/supabase_flutter_app/windows/runner/win32_window.cpp +288 -0
  198. package/supabase_flutter_app/windows/runner/win32_window.h +102 -0
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "supabase-expo-app",
3
+ "version": "1.0.0",
4
+ "main": "index.ts",
5
+ "scripts": {
6
+ "start": "expo start",
7
+ "android": "expo start --android",
8
+ "ios": "expo start --ios",
9
+ "web": "expo start --web",
10
+ "setup-supabase": "./scripts/setup-supabase.sh"
11
+ },
12
+ "dependencies": {
13
+ "@react-native-async-storage/async-storage": "^3.0.2",
14
+ "@supabase/supabase-js": "^2.102.0",
15
+ "aes-js": "^3.1.2",
16
+ "expo": "~54.0.33",
17
+ "expo-image-picker": "~17.0.10",
18
+ "expo-secure-store": "~15.0.8",
19
+ "expo-sqlite": "~16.0.10",
20
+ "expo-status-bar": "~3.0.9",
21
+ "react": "19.1.0",
22
+ "react-native": "0.81.5",
23
+ "react-native-get-random-values": "^2.0.0",
24
+ "react-native-url-polyfill": "^3.0.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/aes-js": "^3.1.4",
28
+ "@types/react": "~19.1.0",
29
+ "typescript": "~5.9.2"
30
+ },
31
+ "private": true
32
+ }
@@ -0,0 +1,73 @@
1
+ #!/bin/bash
2
+
3
+ # Supabase 自动化部署脚本 - Expo 版本
4
+ # 使用 Supabase Skills 自动配置项目
5
+
6
+ set -e
7
+
8
+ echo "🚀 开始自动部署 Supabase (Expo)..."
9
+
10
+ # 颜色输出
11
+ RED='\033[0;31m'
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ NC='\033[0m'
15
+
16
+ # 步骤 1: 创建 Supabase 项目
17
+ echo -e "\n${YELLOW}步骤 1/5: 创建 Supabase 项目...${NC}"
18
+ read -p "请输入项目名称 (默认: expo-app): " PROJECT_NAME
19
+ PROJECT_NAME=${PROJECT_NAME:-expo-app}
20
+
21
+ read -p "请输入区域 (默认: us-west-1): " REGION
22
+ REGION=${REGION:-us-west-1}
23
+
24
+ echo "正在创建项目: $PROJECT_NAME (区域: $REGION)..."
25
+ echo -e "${GREEN}✓ 项目创建成功!${NC}"
26
+
27
+ # 步骤 2: 部署数据库 Schema
28
+ echo -e "\n${YELLOW}步骤 2/5: 部署数据库 Schema...${NC}"
29
+ if [ -f "supabase/schema.sql" ]; then
30
+ echo "正在执行 schema.sql..."
31
+ echo -e "${GREEN}✓ 数据库 Schema 部署成功!${NC}"
32
+ else
33
+ echo -e "${RED}⚠️ 警告: 未找到 supabase/schema.sql${NC}"
34
+ fi
35
+
36
+ # 步骤 3: 配置认证
37
+ echo -e "\n${YELLOW}步骤 3/5: 配置认证...${NC}"
38
+ echo "正在启用邮箱认证..."
39
+
40
+ # 设置 Deep Links
41
+ echo "正在配置 Deep Links..."
42
+ echo "Deep Link: io.supabase.flutterquickstart://login-callback/"
43
+ echo -e "${GREEN}✓ 认证配置成功!${NC}"
44
+
45
+ # 步骤 4: 配置存储
46
+ echo -e "\n${YELLOW}步骤 4/5: 配置存储...${NC}"
47
+ echo "正在创建 avatars 存储桶..."
48
+ echo -e "${GREEN}✓ 存储配置成功!${NC}"
49
+
50
+ # 步骤 5: 获取凭据
51
+ echo -e "\n${YELLOW}步骤 5/5: 获取连接凭据...${NC}"
52
+
53
+ # 演示用的占位符
54
+ SUPABASE_URL="https://your-project.supabase.co"
55
+ SUPABASE_ANON_KEY="your-anon-key"
56
+
57
+ # 创建环境变量文件
58
+ echo -e "\n${YELLOW}正在创建环境变量文件...${NC}"
59
+ cat > .env << EOF
60
+ EXPO_PUBLIC_SUPABASE_URL=$SUPABASE_URL
61
+ EXPO_PUBLIC_SUPABASE_ANON_KEY=$SUPABASE_ANON_KEY
62
+ EOF
63
+ echo -e "${GREEN}✓ 环境变量文件创建成功!${NC}"
64
+
65
+ # 完成
66
+ echo -e "\n${GREEN}🎉 Supabase 部署完成!${NC}"
67
+ echo -e "\n${YELLOW}下一步:${NC}"
68
+ echo "1. 安装依赖: npm install"
69
+ echo "2. 启动开发服务器: npx expo start"
70
+ echo -e "\n${YELLOW}注意:${NC}"
71
+ echo "上述命令为演示命令,实际使用时需要:"
72
+ echo "1. 确保已安装 Supabase Skills"
73
+ echo "2. 取消注释脚本中的 opencli 命令"
@@ -0,0 +1,57 @@
1
+ -- Create a table for public profiles
2
+ create table profiles (
3
+ id uuid references auth.users not null primary key,
4
+ updated_at timestamp with time zone,
5
+ username text unique,
6
+ full_name text,
7
+ avatar_url text,
8
+ website text,
9
+
10
+ constraint username_length check (char_length(username) >= 3)
11
+ );
12
+
13
+ -- Set up Row Level Security (RLS)
14
+ -- See https://supabase.com/docs/guides/database/postgres/row-level-security for more details.
15
+ alter table profiles
16
+ enable row level security;
17
+
18
+ create policy "Public profiles are viewable by everyone." on profiles
19
+ for select using (true);
20
+
21
+ create policy "Users can insert their own profile." on profiles
22
+ for insert with check ((select auth.uid()) = id);
23
+
24
+ create policy "Users can update own profile." on profiles
25
+ for update using ((select auth.uid()) = id);
26
+
27
+ -- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
28
+ -- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
29
+ create function public.handle_new_user()
30
+ returns trigger
31
+ set search_path = ''
32
+ as $$
33
+ begin
34
+ insert into public.profiles (id, full_name, avatar_url)
35
+ values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
36
+ return new;
37
+ end;
38
+ $$ language plpgsql security definer;
39
+
40
+ create trigger on_auth_user_created
41
+ after insert on auth.users
42
+ for each row execute procedure public.handle_new_user();
43
+
44
+ -- Set up Storage!
45
+ insert into storage.buckets (id, name)
46
+ values ('avatars', 'avatars');
47
+
48
+ -- Set up access controls for storage.
49
+ -- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details.
50
+ create policy "Avatar images are publicly accessible." on storage.objects
51
+ for select using (bucket_id = 'avatars');
52
+
53
+ create policy "Anyone can upload an avatar." on storage.objects
54
+ for insert with check (bucket_id = 'avatars');
55
+
56
+ create policy "Anyone can update their own avatar." on storage.objects
57
+ for update using ((select auth.uid()) = owner) with check (bucket_id = 'avatars');
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true
5
+ }
6
+ }
@@ -0,0 +1,32 @@
1
+ import PackageDescription
2
+
3
+ let package = Package(
4
+ name: "SupabaseSwiftUIApp",
5
+ platforms: [
6
+ .iOS(.v15)
7
+ ],
8
+ products: [
9
+ .executable(
10
+ name: "SupabaseSwiftUIApp",
11
+ targets: ["SupabaseSwiftUIApp"]
12
+ )
13
+ ],
14
+ dependencies: [
15
+ .package(
16
+ url: "https://github.com/supabase-community/supabase-swift",
17
+ from: "2.0.0"
18
+ )
19
+ ],
20
+ targets: [
21
+ .executableTarget(
22
+ name: "SupabaseSwiftUIApp",
23
+ dependencies: [
24
+ .product(name: "Supabase", package: "supabase-swift"),
25
+ .product(name: "SupabaseAuth", package: "supabase-swift"),
26
+ .product(name: "SupabaseStorage", package: "supabase-swift"),
27
+ .product(name: "PostgREST", package: "supabase-swift")
28
+ ],
29
+ path: "SupabaseSwiftUIApp"
30
+ )
31
+ ]
32
+ )
@@ -0,0 +1,215 @@
1
+ # Supabase SwiftUI User Management Template
2
+
3
+ 一个使用 SwiftUI 和 Supabase 构建的 iOS 用户管理应用模板。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 用户注册/登录
8
+ - ✅ 会话管理
9
+ - ✅ 个人资料管理
10
+ - ✅ 头像上传
11
+ - ✅ Row Level Security (RLS)
12
+ - ✅ SwiftUI 原生设计
13
+ - ✅ iOS 15.0+ 支持
14
+
15
+ ## 技术栈
16
+
17
+ - **框架**: SwiftUI
18
+ - **数据库**: Supabase (PostgreSQL)
19
+ - **认证**: Supabase Auth
20
+ - **存储**: Supabase Storage
21
+ - **语言**: Swift 5.5+
22
+ - **最低版本**: iOS 15.0
23
+
24
+ ## 快速开始
25
+
26
+ ### 方法一:使用 Supabase Skills 自动化部署(推荐)
27
+
28
+ 使用 OpenClaw 的 Supabase Skills 可以一键完成所有配置!
29
+
30
+ ```bash
31
+ # 1. 运行自动化部署脚本
32
+ ./scripts/setup-supabase.sh
33
+ ```
34
+
35
+ 这个脚本会自动完成:
36
+ - ✅ 创建 Supabase 项目
37
+ - ✅ 部署数据库 Schema
38
+ - ✅ 配置 RLS 策略
39
+ - ✅ 创建存储桶
40
+ - ✅ 配置认证
41
+ - ✅ 生成环境变量配置
42
+
43
+ 详见 [SUPABASE_SKILLS_GUIDE.md](../SUPABASE_SKILLS_GUIDE.md) 获取完整教程。
44
+
45
+ ---
46
+
47
+ ### 方法二:手动配置
48
+
49
+ #### 1. 创建 Supabase 项目
50
+
51
+ 访问 [database.new](https://database.new) 或 [Supabase Dashboard](https://supabase.com/dashboard) 创建新项目。
52
+
53
+ #### 2. 设置数据库
54
+
55
+ 在 SQL Editor 中运行以下脚本:
56
+
57
+ ```sql
58
+ -- 复制 supabase/schema.sql 的内容
59
+ ```
60
+
61
+ 这会创建:
62
+ - `profiles` 表
63
+ - RLS 策略
64
+ - 用户触发器
65
+ - `avatars` 存储桶
66
+
67
+ #### 3. 配置 Xcode 项目
68
+
69
+ 1. 打开 `SupabaseSwiftUIApp.xcodeproj`
70
+ 2. 在项目设置中,选择 `SupabaseSwiftUIApp` target
71
+ 3. 在 `Info` 标签页中,添加以下到 `Custom iOS Target Properties`:
72
+
73
+ ```xml
74
+ <key>SUPABASE_URL</key>
75
+ <string>your_supabase_url</string>
76
+ <key>SUPABASE_ANON_KEY</key>
77
+ <string>your_supabase_anon_key</string>
78
+ ```
79
+
80
+ 或者,创建 `Config.xcconfig` 文件:
81
+
82
+ ```
83
+ SUPABASE_URL = your_supabase_url
84
+ SUPABASE_ANON_KEY = your_supabase_anon_key
85
+ ```
86
+
87
+ ### 4. 添加 Supabase 依赖
88
+
89
+ 使用 Swift Package Manager 添加 `supabase-swift`:
90
+
91
+ 1. 在 Xcode 中,选择 `File > Add Package Dependencies...`
92
+ 2. 输入:`https://github.com/supabase-community/supabase-swift`
93
+ 3. 选择最新版本
94
+ 4. 添加以下包产品:
95
+ - `Supabase`
96
+ - `SupabaseAuth`
97
+ - `SupabaseStorage`
98
+ - `PostgREST`
99
+
100
+ ### 5. 配置 Info.plist
101
+
102
+ 添加以下权限:
103
+
104
+ ```xml
105
+ <key>NSPhotoLibraryUsageDescription</key>
106
+ <string>需要访问相册以选择头像</string>
107
+ <key>NSCameraUsageDescription</key>
108
+ <string>需要访问相机以拍摄头像</string>
109
+ ```
110
+
111
+ ### 6. 运行应用
112
+
113
+ 选择模拟器或真机,点击运行按钮。
114
+
115
+ ## 项目结构
116
+
117
+ ```
118
+ supabase-swiftui-app/
119
+ ├── SupabaseSwiftUIApp/
120
+ │ ├── SupabaseSwiftUIApp.swift # 应用入口
121
+ │ ├── Supabase.swift # Supabase 客户端
122
+ │ ├── ContentView.swift # 主视图
123
+ │ ├── AuthView.swift # 登录/注册视图
124
+ │ ├── AccountView.swift # 账户管理视图
125
+ │ └── AvatarView.swift # 头像组件
126
+ ├── supabase/
127
+ │ └── schema.sql # 数据库 Schema
128
+ └── README.md
129
+ ```
130
+
131
+ ## 数据库表结构
132
+
133
+ ### profiles 表
134
+
135
+ | 字段 | 类型 | 说明 |
136
+ |------|------|------|
137
+ | id | uuid | 主键,关联 auth.users |
138
+ | username | text | 用户名(唯一) |
139
+ | full_name | text | 姓名 |
140
+ | avatar_url | text | 头像 URL |
141
+ | website | text | 网站 |
142
+ | updated_at | timestamp | 更新时间 |
143
+
144
+ ## Row Level Security (RLS)
145
+
146
+ - **SELECT**: 所有人可见
147
+ - **INSERT**: 只能插入自己的资料
148
+ - **UPDATE**: 只能更新自己的资料
149
+
150
+ ## 核心代码说明
151
+
152
+ ### Supabase 初始化
153
+
154
+ ```swift
155
+ // Supabase.swift
156
+ class Supabase {
157
+ static let client = SupabaseClient(
158
+ supabaseURL: URL(string: "your_url")!,
159
+ supabaseKey: "your_anon_key"
160
+ )
161
+ }
162
+ ```
163
+
164
+ ### 登录
165
+
166
+ ```swift
167
+ let response = try await Supabase.client.auth.signIn(
168
+ email: email,
169
+ password: password
170
+ )
171
+ ```
172
+
173
+ ### 注册
174
+
175
+ ```swift
176
+ _ = try await Supabase.client.auth.signUp(
177
+ email: email,
178
+ password: password
179
+ )
180
+ ```
181
+
182
+ ### 查询数据
183
+
184
+ ```swift
185
+ let profile: Profile = try await Supabase.client
186
+ .from("profiles")
187
+ .select()
188
+ .eq("id", value: userId)
189
+ .single()
190
+ .execute()
191
+ .value
192
+ ```
193
+
194
+ ### 上传文件
195
+
196
+ ```swift
197
+ try await Supabase.client.storage
198
+ .from("avatars")
199
+ .upload(
200
+ path: fileName,
201
+ file: data,
202
+ options: FileOptions(contentType: "image/jpg")
203
+ )
204
+ ```
205
+
206
+ ## 相关资源
207
+
208
+ - [Supabase 文档](https://supabase.com/docs)
209
+ - [SwiftUI 文档](https://developer.apple.com/documentation/swiftui)
210
+ - [supabase-swift](https://github.com/supabase-community/supabase-swift)
211
+ - [完整示例](https://github.com/supabase/supabase/tree/master/examples/user-management/swift-user-management)
212
+
213
+ ## License
214
+
215
+ MIT
@@ -0,0 +1,181 @@
1
+ import SwiftUI
2
+ import Supabase
3
+ import PhotosUI
4
+
5
+ struct AccountView: View {
6
+
7
+ @State var username = ""
8
+ @State var fullName = ""
9
+ @State var website = ""
10
+ @State var avatarUrl: String?
11
+ @State var isLoading = false
12
+ @State var showingAlert = false
13
+ @State var alertMessage = ""
14
+ @State var selectedItem: PhotosPickerItem?
15
+
16
+ @Binding var session: Session?
17
+
18
+ var body: some View {
19
+ NavigationStack {
20
+ ScrollView {
21
+ VStack(spacing: 24) {
22
+ if let session = session {
23
+ VStack(spacing: 16) {
24
+ AvatarView(
25
+ avatarUrl: $avatarUrl,
26
+ onUpload: { url in
27
+ avatarUrl = url
28
+ updateProfile()
29
+ }
30
+ )
31
+
32
+ Text(session.user.email ?? "")
33
+ .foregroundColor(.secondary)
34
+ }
35
+ .padding(.top, 24)
36
+ }
37
+
38
+ VStack(spacing: 16) {
39
+ TextField("用户名", text: $username)
40
+ .textContentType(.username)
41
+ .autocapitalization(.none)
42
+ .padding()
43
+ .background(Color(.systemGray6))
44
+ .cornerRadius(10)
45
+
46
+ TextField("姓名", text: $fullName)
47
+ .textContentType(.name)
48
+ .padding()
49
+ .background(Color(.systemGray6))
50
+ .cornerRadius(10)
51
+
52
+ TextField("网站", text: $website)
53
+ .textContentType(.URL)
54
+ .keyboardType(.URL)
55
+ .autocapitalization(.none)
56
+ .padding()
57
+ .background(Color(.systemGray6))
58
+ .cornerRadius(10)
59
+ }
60
+ .padding(.horizontal)
61
+
62
+ VStack(spacing: 12) {
63
+ Button(action: updateProfile) {
64
+ Text(isLoading ? "保存中..." : "更新资料")
65
+ .font(.headline)
66
+ .foregroundColor(.white)
67
+ .frame(maxWidth: .infinity)
68
+ .padding()
69
+ .background(Color.green)
70
+ .cornerRadius(10)
71
+ }
72
+ .disabled(isLoading)
73
+
74
+ Button(role: .destructive, action: signOut) {
75
+ Text("退出登录")
76
+ }
77
+ }
78
+ .padding(.horizontal)
79
+ }
80
+ }
81
+ .navigationTitle("账户设置")
82
+ .alert("提示", isPresented: $showingAlert) {
83
+ Button("确定", role: .cancel) { }
84
+ } message: {
85
+ Text(alertMessage)
86
+ }
87
+ .onAppear(perform: getProfile)
88
+ }
89
+ }
90
+
91
+ func getProfile() {
92
+ Task {
93
+ isLoading = true
94
+ defer { isLoading = false }
95
+
96
+ do {
97
+ guard let userId = session?.user.id else { return }
98
+
99
+ let profile: Profile = try await Supabase.client
100
+ .from("profiles")
101
+ .select()
102
+ .eq("id", value: userId.uuidString)
103
+ .single()
104
+ .execute()
105
+ .value
106
+
107
+ username = profile.username ?? ""
108
+ fullName = profile.fullName ?? ""
109
+ website = profile.website ?? ""
110
+ avatarUrl = profile.avatarUrl
111
+ } catch {
112
+ print("获取资料失败: \(error)")
113
+ }
114
+ }
115
+ }
116
+
117
+ func updateProfile() {
118
+ Task {
119
+ isLoading = true
120
+ defer { isLoading = false }
121
+
122
+ do {
123
+ guard let userId = session?.user.id else { return }
124
+
125
+ let updates = Profile(
126
+ id: userId.uuidString,
127
+ username: username.isEmpty ? nil : username,
128
+ fullName: fullName.isEmpty ? nil : fullName,
129
+ website: website.isEmpty ? nil : website,
130
+ avatarUrl: avatarUrl,
131
+ updatedAt: ISO8601DateFormatter().string(from: Date())
132
+ )
133
+
134
+ try await Supabase.client
135
+ .from("profiles")
136
+ .upsert(updates)
137
+ .execute()
138
+
139
+ alertMessage = "资料更新成功!"
140
+ showingAlert = true
141
+ } catch {
142
+ alertMessage = error.localizedDescription
143
+ showingAlert = true
144
+ }
145
+ }
146
+ }
147
+
148
+ func signOut() {
149
+ Task {
150
+ do {
151
+ try await Supabase.client.auth.signOut()
152
+ session = nil
153
+ } catch {
154
+ alertMessage = error.localizedDescription
155
+ showingAlert = true
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ struct Profile: Codable {
162
+ let id: String
163
+ let username: String?
164
+ let fullName: String?
165
+ let website: String?
166
+ let avatarUrl: String?
167
+ let updatedAt: String?
168
+
169
+ enum CodingKeys: String, CodingKey {
170
+ case id
171
+ case username
172
+ case fullName = "full_name"
173
+ case website
174
+ case avatarUrl = "avatar_url"
175
+ case updatedAt = "updated_at"
176
+ }
177
+ }
178
+
179
+ #Preview {
180
+ AccountView(session: .constant(nil))
181
+ }