botrun-horse 2.29.2 → 2.30.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/botrun-c/.claude/skills/DOCX/351/226/261/350/256/200/346/212/200/350/203/275/SKILL.md +103 -0
- package/botrun-c/.claude/skills/DOCX/351/226/261/350/256/200/346/212/200/350/203/275/scripts/docx-to-markdown.mjs +206 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/SKILL.md +1093 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branch.mjs +73 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branches.mjs +77 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-checkout.mjs +72 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-clone.mjs +72 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-commit.mjs +75 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-branch.mjs +75 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-file.mjs +72 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-diff.mjs +80 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list-tree.mjs +336 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list.mjs +199 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-merge.mjs +86 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-move.mjs +75 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-create.mjs +81 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-list.mjs +74 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-merge.mjs +83 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-view.mjs +71 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-push.mjs +71 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-read.mjs +277 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-search.mjs +370 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-stash.mjs +116 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-sync.mjs +71 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-write.mjs +74 -0
- package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/lib/path-validator.mjs +167 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/SKILL.md +605 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-create.mjs +127 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-delete.mjs +77 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-diff.mjs +87 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-history.mjs +99 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-list.mjs +174 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-read.mjs +214 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-restore.mjs +75 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-search.mjs +270 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-sync-back.mjs +155 -0
- package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-update.mjs +100 -0
- package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/SKILL.md +414 -0
- package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/create-project.mjs +91 -0
- package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/finalize-project.mjs +162 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/SKILL.md +206 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/package.json +19 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-analyze.mjs +309 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-compress.mjs +315 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-split.mjs +275 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-to-text.mjs +336 -0
- package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/test-pdf-scripts.mjs +491 -0
- package/botrun-c/.claude/skills/docx-to-markdown/SKILL.md +76 -0
- package/botrun-c/.claude/skills/docx-to-markdown/scripts/convert_docx.py +183 -0
- package/botrun-c/.claude/skills/gcp-coord-ml-ocr/SKILL.md +133 -0
- package/botrun-c/.claude/skills/gcp-coord-ml-ocr/scripts/ocr_processor.py +381 -0
- package/botrun-c/.claude/skills/gemini-transcribe/SKILL.md +115 -0
- package/botrun-c/.claude/skills/gemini-transcribe/scripts/transcribe.py +499 -0
- package/botrun-c/.claude/skills/nchc-transcribe/SKILL.md +131 -0
- package/botrun-c/.claude/skills/nchc-transcribe/scripts/transcribe.py +522 -0
- package/botrun-c/.claude/skills/p320-moj-review/SKILL.md +200 -0
- package/botrun-c/.claude/skills/p320-moj-review/references/guideline.md +118 -0
- package/botrun-c/.claude/skills/pdf-multimodal-processor/SKILL.md +186 -0
- package/botrun-c/.claude/skills/pdf-multimodal-processor/scripts/process_pdf.py +515 -0
- package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/SKILL.md +81 -0
- package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/package.json +13 -0
- package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/secure-search.mjs +232 -0
- package/botrun-c/.claude/skills/top100/351/240/230/350/242/226/351/240/220/346/270/254/346/212/200/350/203/275/SKILL.md +518 -0
- package/botrun-c/.claude/skills//345/216/273/350/255/230/345/210/245/346/212/200/350/203/275/SKILL.md +125 -0
- package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/SKILL.md +123 -0
- package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/scripts/recall.mjs +339 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/SKILL.md +156 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/__tests__/utils.test.mjs +139 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/constants.mjs +40 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/gcs-uploader.mjs +195 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/gemini-image-client.mjs +307 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/generate-image.mjs +103 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/image-session-manager.mjs +219 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/output-formatter.mjs +209 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/package.json +20 -0
- package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/utils.mjs +115 -0
- package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/SKILL.md +86 -0
- package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/scripts/multimodal-read.mjs +304 -0
- package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/scripts/package.json +17 -0
- package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/SKILL.md +131 -0
- package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/scripts/skill-manager.mjs +542 -0
- package/botrun-c/.claude/skills//346/234/203/350/255/260/350/250/230/351/214/204/346/212/200/350/203/275/SKILL.md +127 -0
- package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/SKILL.md +53 -0
- package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/scripts/package.json +13 -0
- package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/scripts/tree-view.mjs +149 -0
- package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/SKILL.md +82 -0
- package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/scripts/package.json +16 -0
- package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/scripts/secure-read.mjs +260 -0
- package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/SKILL.md +156 -0
- package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/package.json +16 -0
- package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.js +139 -0
- package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.mjs +272 -0
- package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.ts +166 -0
- package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/SKILL.md +114 -0
- package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/remember.mjs +159 -0
- package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test-advanced.mjs +342 -0
- package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test.mjs +430 -0
- package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/SKILL.md +30 -0
- package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/scripts/package.json +13 -0
- package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/scripts/transcribe.mjs +294 -0
- package/botrun-c/.claude/skills//351/233/266/345/271/273/350/246/272/350/255/211/346/230/216/346/212/200/350/203/275/SKILL.md +338 -0
- package/botrun-c/.dockerignore +131 -0
- package/botrun-c/.dockeroptimize +13 -0
- package/botrun-c/.firebase/hosting.b3V0.cache +30 -0
- package/botrun-c/.firebaserc +5 -0
- package/botrun-c/.gcloudignore +56 -0
- package/botrun-c/.ruby-version +1 -0
- package/botrun-c/CHANGELOG.md +224 -0
- package/botrun-c/Dockerfile.gcp +365 -0
- package/botrun-c/Dockerfile.slim +195 -0
- package/botrun-c/Gemfile +8 -0
- package/botrun-c/Gemfile.lock +233 -0
- package/botrun-c/LOCAL-DEVELOPMENT-GUIDE.md +393 -0
- package/botrun-c/PLAN.md +131 -0
- package/botrun-c/README.md +129 -0
- package/botrun-c/TODO-CAPACITOR-INTEGRATION.md +482 -0
- package/botrun-c/VERIFICATION.md +121 -0
- package/botrun-c/admin/RATE_LIMIT_MANAGEMENT.md +312 -0
- package/botrun-c/admin/README.md +338 -0
- package/botrun-c/admin/botrun-billing-report-1765235244038.csv +22 -0
- package/botrun-c/admin/botrun-billing-report-1765235323089.csv +22 -0
- package/botrun-c/admin/botrun-dashboard-1765235244039.html +278 -0
- package/botrun-c/admin/botrun-dashboard-1765235323089.html +278 -0
- package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235244039.html +161 -0
- package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235323090.html +161 -0
- package/botrun-c/admin/check-billing.ts +48 -0
- package/botrun-c/admin/count-all-users.ts +65 -0
- package/botrun-c/admin/generate-analytics-report.ts +188 -0
- package/botrun-c/admin/jest.config.ts +43 -0
- package/botrun-c/admin/lib/__tests__/formatters.test.ts +264 -0
- package/botrun-c/admin/lib/__tests__/mocks/firebase.mock.ts +112 -0
- package/botrun-c/admin/lib/__tests__/services/UserService.test.ts +83 -0
- package/botrun-c/admin/lib/__tests__/user-resolver.test.ts +439 -0
- package/botrun-c/admin/lib/analyzers/BillingAnalyticsService.ts +242 -0
- package/botrun-c/admin/lib/analyzers/CsvExporter.ts +263 -0
- package/botrun-c/admin/lib/analyzers/HtmlChartGenerator.ts +530 -0
- package/botrun-c/admin/lib/analyzers/SpikeAnalyzer.ts +608 -0
- package/botrun-c/admin/lib/analyzers/TimeSeriesAnalyzer.ts +344 -0
- package/botrun-c/admin/lib/cli/CLIBootstrapper.ts +40 -0
- package/botrun-c/admin/lib/commands/AbstractCommand.ts +69 -0
- package/botrun-c/admin/lib/commands/AnalyticsCommand.ts +215 -0
- package/botrun-c/admin/lib/commands/ListCommand.ts +85 -0
- package/botrun-c/admin/lib/commands/QueryCommand.ts +81 -0
- package/botrun-c/admin/lib/commands/SpikeCommand.ts +83 -0
- package/botrun-c/admin/lib/domain/User.ts +38 -0
- package/botrun-c/admin/lib/firebase.ts +92 -0
- package/botrun-c/admin/lib/firestore-safe.ts +105 -0
- package/botrun-c/admin/lib/formatters.ts +154 -0
- package/botrun-c/admin/lib/rate-limit-detailed.ts +355 -0
- package/botrun-c/admin/lib/rate-limit.ts +286 -0
- package/botrun-c/admin/lib/repositories/UserRepository.ts +104 -0
- package/botrun-c/admin/lib/services/UserService.ts +108 -0
- package/botrun-c/admin/lib/types.ts +56 -0
- package/botrun-c/admin/lib/user-resolver.ts +275 -0
- package/botrun-c/admin/manage-auth-domains.js +178 -0
- package/botrun-c/admin/migrate-plan-free.sh +64 -0
- package/botrun-c/admin/package-lock.json +5656 -0
- package/botrun-c/admin/package.json +28 -0
- package/botrun-c/admin/rate-limit.sh +55 -0
- package/botrun-c/admin/remove-custom-limits.ts +75 -0
- package/botrun-c/admin/reset-rate.sh +70 -0
- package/botrun-c/admin/reset-trial.sh +68 -0
- package/botrun-c/admin/seed-trial-data.sh +38 -0
- package/botrun-c/admin/trial.sh +55 -0
- package/botrun-c/admin/tsconfig.json +20 -0
- package/botrun-c/admin/users-cli.py +298 -0
- package/botrun-c/admin/users.sh +12 -0
- package/botrun-c/admin/users.ts +1321 -0
- package/botrun-c/api/admin-tools/check-whitelist.mjs.migration-bak +74 -0
- package/botrun-c/api/admin-tools/create-user.mjs +92 -0
- package/botrun-c/api/admin-tools/create-user.mjs.migration-bak +92 -0
- package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py +287 -0
- package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py.migration-bak +287 -0
- package/botrun-c/api/admin-tools/init-firestore.mjs +75 -0
- package/botrun-c/api/admin-tools/init-firestore.mjs.migration-bak +101 -0
- package/botrun-c/api/admin-tools/list-users.mjs +43 -0
- package/botrun-c/api/admin-tools/list-users.mjs.migration-bak +43 -0
- package/botrun-c/api/admin-tools/manage-authorized-domains.ts +255 -0
- package/botrun-c/api/admin-tools/manage-authorized-domains.ts.migration-bak +255 -0
- package/botrun-c/api/admin-tools/setup-custom-claims.ts.migration-bak +155 -0
- package/botrun-c/api/admin-tools/test-claims.mjs +69 -0
- package/botrun-c/api/admin-tools/test-claims.mjs.migration-bak +69 -0
- package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs +72 -0
- package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs.migration-bak +72 -0
- package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs +159 -0
- package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs.migration-bak +159 -0
- package/botrun-c/api/admin-tools/update-service-urls.mjs +82 -0
- package/botrun-c/api/admin-tools/update-service-urls.mjs.migration-bak +82 -0
- package/botrun-c/api/package-lock.json +5031 -0
- package/botrun-c/api/package.json +63 -0
- package/botrun-c/api/pnpm-lock.yaml +4157 -0
- package/botrun-c/api/rate-limit-export-1763620678737.csv +79 -0
- package/botrun-c/api/scripts/README-migrate-plan-free.md +197 -0
- package/botrun-c/api/scripts/check-users.ts +45 -0
- package/botrun-c/api/scripts/delete-firestore-docs.js +43 -0
- package/botrun-c/api/scripts/dump-subscriptions.ts +395 -0
- package/botrun-c/api/scripts/list-all-users.ts +65 -0
- package/botrun-c/api/scripts/migrate-plan-free-rpd-16to32.ts +262 -0
- package/botrun-c/api/scripts/migrate-plan-names-to-lite-max.ts +269 -0
- package/botrun-c/api/scripts/query-user-info.ts +304 -0
- package/botrun-c/api/scripts/reset-rate-limit.ts +206 -0
- package/botrun-c/api/scripts/reset-trial-subscription.ts +166 -0
- package/botrun-c/api/scripts/rollback-plan-names-from-lite-max.ts +139 -0
- package/botrun-c/api/scripts/seed-rate-limit-test-data.ts +114 -0
- package/botrun-c/api/scripts/seed-subscription-test-data.ts +173 -0
- package/botrun-c/api/scripts/test-rate-limit-message.ts +108 -0
- package/botrun-c/api/test-billing-write.ts +103 -0
- package/botrun-c/api/test-billing.ts +81 -0
- package/botrun-c/api/test-chat-upload.sh +162 -0
- package/botrun-c/api/test-nchc-whisper.ts +87 -0
- package/botrun-c/api/test-skills-loading.js +77 -0
- package/botrun-c/api/test-skills-symlink.js +118 -0
- package/botrun-c/api/test-upload-multimodal.sh +167 -0
- package/botrun-c/api/tsconfig.json +27 -0
- package/botrun-c/api/verify-form-2-1.mjs +229 -0
- package/botrun-c/api/vitest.config.ts +9 -0
- package/botrun-c/appium-capabilities.json +20 -0
- package/botrun-c/cors.json +26 -0
- package/botrun-c/delete-old.sh +44 -0
- package/botrun-c/design/google-drive/01-architecture.md +186 -0
- package/botrun-c/design/google-drive/02-api-design.md +314 -0
- package/botrun-c/design/google-drive/03-frontend-design.md +278 -0
- package/botrun-c/design/google-drive/04-skill-design.md +384 -0
- package/botrun-c/design/google-drive/05-test-plan.md +507 -0
- package/botrun-c/design/google-drive/README.md +32 -0
- package/botrun-c/dev/mcp-token-calculator/README.md +92 -0
- package/botrun-c/dev/mcp-token-calculator/RESULTS.md +188 -0
- package/botrun-c/dev/mcp-token-calculator/calculate-current-tokens.ts +369 -0
- package/botrun-c/dev/mcp-token-calculator/calculate-mcp-tokens.ts +464 -0
- package/botrun-c/dev/mcp-token-calculator/optimization-proposals.ts +316 -0
- package/botrun-c/dev/mcp-token-calculator/package-lock.json +599 -0
- package/botrun-c/dev/mcp-token-calculator/package.json +22 -0
- package/botrun-c/dev/mcp-token-calculator/test-all-schemas.ts +314 -0
- package/botrun-c/dev/mcp-token-calculator/test-schema-correctness.ts +221 -0
- package/botrun-c/dev/mcp-token-calculator/verify-optimization.ts +159 -0
- package/botrun-c/fastlane/ANDROID-DEPLOYMENT-SETUP.md +825 -0
- package/botrun-c/fastlane/IOS-DEPLOYMENT-SETUP.md +431 -0
- package/botrun-c/fastlane/Pluginfile +5 -0
- package/botrun-c/fastlane/QUICK-START.md +133 -0
- package/botrun-c/fastlane/README.md +424 -0
- package/botrun-c/fastlane/RUBY-SETUP.md +449 -0
- package/botrun-c/fastlane/android/Appfile +11 -0
- package/botrun-c/fastlane/android/Fastfile +240 -0
- package/botrun-c/firebase.json +46 -0
- package/botrun-c/firestore-init-data.json +40 -0
- package/botrun-c/firestore.indexes.json +55 -0
- package/botrun-c/firestore.rules +53 -0
- package/botrun-c/fix-codex-permissions.sh +56 -0
- package/botrun-c/gcs-lifecycle-30day-retention.json +12 -0
- package/botrun-c/html-architecture/architecture/deployment.html +664 -0
- package/botrun-c/html-architecture/architecture/index.html +309 -0
- package/botrun-c/html-architecture/architecture/styles.css +500 -0
- package/botrun-c/html-architecture/architecture/system-components.html +538 -0
- package/botrun-c/html-architecture/architecture/user-flow.html +370 -0
- package/botrun-c/mobile-android/FIREBASE-AUTH-SETUP.md +302 -0
- package/botrun-c/mobile-android/WSL-ANDROID-SETUP.md +252 -0
- package/botrun-c/mobile-android/android/app/build.gradle +75 -0
- package/botrun-c/mobile-android/android/app/capacitor.build.gradle +31 -0
- package/botrun-c/mobile-android/android/app/proguard-rules.pro +21 -0
- package/botrun-c/mobile-android/android/build.gradle +29 -0
- package/botrun-c/mobile-android/android/capacitor.settings.gradle +42 -0
- package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/botrun-c/mobile-android/android/gradle.properties +22 -0
- package/botrun-c/mobile-android/android/gradlew +252 -0
- package/botrun-c/mobile-android/android/gradlew.bat +94 -0
- package/botrun-c/mobile-android/android/settings.gradle +5 -0
- package/botrun-c/mobile-android/android/variables.gradle +16 -0
- package/botrun-c/mobile-android/capacitor.config.ts +44 -0
- package/botrun-c/mobile-android/fastlane/Appfile +11 -0
- package/botrun-c/mobile-android/fastlane/Fastfile +202 -0
- package/botrun-c/mobile-android/fastlane/README.md +96 -0
- package/botrun-c/mobile-android/google-services.json.template +39 -0
- package/botrun-c/mobile-android/package.json +32 -0
- package/botrun-c/mobile-android/resources/icon.png +0 -0
- package/botrun-c/mobile-android/tsconfig.json +15 -0
- package/botrun-c/mobile-ios/.ruby-version +1 -0
- package/botrun-c/mobile-ios/BUILD-LOG.md +82 -0
- package/botrun-c/mobile-ios/Gemfile +4 -0
- package/botrun-c/mobile-ios/Gemfile.lock +299 -0
- package/botrun-c/mobile-ios/GoogleService-Info.plist.template +34 -0
- package/botrun-c/mobile-ios/IOS-PERMISSIONS.md +80 -0
- package/botrun-c/mobile-ios/QUICK-START.md +189 -0
- package/botrun-c/mobile-ios/README.md +231 -0
- package/botrun-c/mobile-ios/capacitor.config.ts +46 -0
- package/botrun-c/mobile-ios/fastlane/Fastfile +326 -0
- package/botrun-c/mobile-ios/fastlane/README.md +88 -0
- package/botrun-c/mobile-ios/ios/App/App/App.entitlements +10 -0
- package/botrun-c/mobile-ios/ios/App/App/AppDelegate.swift +49 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Contents.json +6 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +56 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
- package/botrun-c/mobile-ios/ios/App/App/Base.lproj/LaunchScreen.storyboard +32 -0
- package/botrun-c/mobile-ios/ios/App/App/Base.lproj/Main.storyboard +19 -0
- package/botrun-c/mobile-ios/ios/App/App/Info.plist +72 -0
- package/botrun-c/mobile-ios/ios/App/App.xcodeproj/project.pbxproj +446 -0
- package/botrun-c/mobile-ios/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme +78 -0
- package/botrun-c/mobile-ios/ios/App/App.xcworkspace/contents.xcworkspacedata +10 -0
- package/botrun-c/mobile-ios/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/botrun-c/mobile-ios/ios/App/Podfile +52 -0
- package/botrun-c/mobile-ios/ios/App/Podfile.lock +205 -0
- package/botrun-c/mobile-ios/ios/App/add_plist.rb +30 -0
- package/botrun-c/mobile-ios/ios/App/fix_plist_path.rb +22 -0
- package/botrun-c/mobile-ios/package.json +29 -0
- package/botrun-c/mobile-ios/resources/icon.png +0 -0
- package/botrun-c/mobile-ios/run-simulator.sh +34 -0
- package/botrun-c/mobile-ios/screenshot-after-clean-rebuild.png +0 -0
- package/botrun-c/mobile-ios/screenshot-final-version.png +0 -0
- package/botrun-c/mobile-ios/screenshot-simulator.png +0 -0
- package/botrun-c/mobile-ios/screenshot-version-1009.png +0 -0
- package/botrun-c/mobile-ios/screenshot-with-version.png +0 -0
- package/botrun-c/mobile-ios/screenshot-working.png +0 -0
- package/botrun-c/mobile-ios/setup-ios.sh +106 -0
- package/botrun-c/mobile-ios/tsconfig.json +16 -0
- package/botrun-c/org-policy-allow-all-users.yaml +3 -0
- package/botrun-c/package.json +68 -0
- package/botrun-c/pnpm-lock.yaml +10198 -0
- package/botrun-c/pnpm-workspace.yaml +6 -0
- package/botrun-c/prompts/BOTRUN-1.md +13 -0
- package/botrun-c/prompts/BOTRUN-2.md +70 -0
- package/botrun-c/prompts/BOTRUN-3.md +139 -0
- package/botrun-c/prototypes/firestore-gax-debug/package-lock.json +1204 -0
- package/botrun-c/prototypes/firestore-gax-debug/package.json +12 -0
- package/botrun-c/prototypes/firestore-gax-debug/pnpm-workspace.yaml +2 -0
- package/botrun-c/prototypes/firestore-gax-debug/test.js +98 -0
- package/botrun-c/prototypes/taiwan-haiku/README.md +93 -0
- package/botrun-c/prototypes/taiwan-haiku/index.ts +139 -0
- package/botrun-c/prototypes/taiwan-haiku/package.json +23 -0
- package/botrun-c/prototypes/taiwan-haiku/pnpm-lock.yaml +730 -0
- package/botrun-c/prototypes/taiwan-haiku/test-vertex-direct.ts +83 -0
- package/botrun-c/prototypes/taiwan-haiku/tsconfig.json +18 -0
- package/botrun-c/prototypes/web-search/FINDINGS-STAGE-1.md +48 -0
- package/botrun-c/prototypes/web-search/README.md +46 -0
- package/botrun-c/prototypes/web-search/VERIFICATION-REPORT.md +310 -0
- package/botrun-c/prototypes/web-search/package-lock.json +595 -0
- package/botrun-c/prototypes/web-search/package.json +18 -0
- package/botrun-c/prototypes/web-search/stage-1.1-basic-connection.js +123 -0
- package/botrun-c/prototypes/web-search/stage-1.2-with-websearch.js +154 -0
- package/botrun-c/prototypes/web-search/stage-1.3-search-query.js +192 -0
- package/botrun-c/prototypes/web-search/stage-2-agent-sdk-websearch.js +265 -0
- package/botrun-c/runtime-scripts/env-detect.sh +64 -0
- package/botrun-c/scripts/github-collaborator-manager.sh +297 -0
- package/botrun-c/scripts/github-collaborator-manager.ts +325 -0
- package/botrun-c/scripts/manage-collaborators.sh +91 -0
- package/botrun-c/scripts/setup-secrets.sh +202 -0
- package/botrun-c/scripts/stress-test-17-users.sh +113 -0
- package/botrun-c/scripts/stress-test-api.sh +119 -0
- package/botrun-c/scripts/stress-test-full-report.sh +385 -0
- package/botrun-c/specs/infra-vm/design.md +0 -0
- package/botrun-c/specs/share-skill/design.md +1146 -0
- package/botrun-c/specs/share-skill/tasks.md +444 -0
- package/botrun-c/stress-test-results/20260121-162630/config.json +7 -0
- package/botrun-c/stress-test-results/20260121-162630/user-1-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162630/user-1-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162630/user-1.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/config.json +7 -0
- package/botrun-c/stress-test-results/20260121-162646/user-1-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-1-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-1.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-10-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-10-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-10.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-11-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-11-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-11.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-12-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-12-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-12.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-13-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-13-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-13.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-14-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-14-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-14.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-15-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-15-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-15.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-16-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-16-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-16.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-17-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-17-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-17.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-2-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-2-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-2.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-3-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-3-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-3.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-4-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-4-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-4.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-5-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-5-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-5.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-6-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-6-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-6.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-7-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-7-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-7.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-8-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-8-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-8.json +2 -0
- package/botrun-c/stress-test-results/20260121-162646/user-9-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-9-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-162646/user-9.json +2 -0
- package/botrun-c/stress-test-results/20260121-163148/REPORT.html +344 -0
- package/botrun-c/stress-test-results/20260121-163148/REPORT.md +93 -0
- package/botrun-c/stress-test-results/20260121-163148/REPORT.pdf +0 -0
- package/botrun-c/stress-test-results/20260121-163148/config.json +7 -0
- package/botrun-c/stress-test-results/20260121-163148/summary.json +26 -0
- package/botrun-c/stress-test-results/20260121-163148/user-1-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-1-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-1.json +206 -0
- package/botrun-c/stress-test-results/20260121-163148/user-10-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-10-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-10.json +110 -0
- package/botrun-c/stress-test-results/20260121-163148/user-11-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-11-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-11.json +104 -0
- package/botrun-c/stress-test-results/20260121-163148/user-12-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-12-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-12.json +98 -0
- package/botrun-c/stress-test-results/20260121-163148/user-13-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-13-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-13.json +68 -0
- package/botrun-c/stress-test-results/20260121-163148/user-14-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-14-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-14.json +116 -0
- package/botrun-c/stress-test-results/20260121-163148/user-15-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-15-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-15.json +131 -0
- package/botrun-c/stress-test-results/20260121-163148/user-16-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-16-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-16.json +110 -0
- package/botrun-c/stress-test-results/20260121-163148/user-17-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-17-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-17.json +116 -0
- package/botrun-c/stress-test-results/20260121-163148/user-2-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-2-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-2.json +98 -0
- package/botrun-c/stress-test-results/20260121-163148/user-3-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-3-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-3.json +62 -0
- package/botrun-c/stress-test-results/20260121-163148/user-4-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-4-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-4.json +113 -0
- package/botrun-c/stress-test-results/20260121-163148/user-5-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-5-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-5.json +83 -0
- package/botrun-c/stress-test-results/20260121-163148/user-6-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-6-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-6.json +125 -0
- package/botrun-c/stress-test-results/20260121-163148/user-7-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-7-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-7.json +62 -0
- package/botrun-c/stress-test-results/20260121-163148/user-8-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-8-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-8.json +41 -0
- package/botrun-c/stress-test-results/20260121-163148/user-9-status.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-9-timing.txt +1 -0
- package/botrun-c/stress-test-results/20260121-163148/user-9.json +53 -0
- package/botrun-c/test-merge.md +1 -0
- package/botrun-c/version.txt +1 -0
- package/botrun-c/web/.version +1 -0
- package/botrun-c/web/ALLOW-PUBLIC-ACCESS.md +57 -0
- package/botrun-c/web/FINAL-SETUP-STEPS.md +71 -0
- package/botrun-c/web/FIREBASE-MANUAL-STEPS.md +41 -0
- package/botrun-c/web/QUICK-SETUP-HELPER.md +79 -0
- package/botrun-c/web/README.md +162 -0
- package/botrun-c/web/__tests__/image-extractor.test.ts +147 -0
- package/botrun-c/web/__tests__/useGitHub.test.ts +245 -0
- package/botrun-c/web/app/favicon.ico +0 -0
- package/botrun-c/web/app/globals.css +215 -0
- package/botrun-c/web/app/image-preview/page.tsx +213 -0
- package/botrun-c/web/app/layout.tsx +46 -0
- package/botrun-c/web/app/page.tsx +45 -0
- package/botrun-c/web/components/CapacitorProvider.tsx +43 -0
- package/botrun-c/web/components/ChatPage.tsx +1736 -0
- package/botrun-c/web/components/ConversationList.tsx +237 -0
- package/botrun-c/web/components/ConversationListItem.tsx +121 -0
- package/botrun-c/web/components/LoginPage.tsx +212 -0
- package/botrun-c/web/components/Providers.tsx +12 -0
- package/botrun-c/web/components/StatusBarProvider.tsx +16 -0
- package/botrun-c/web/components/attachment-preview.tsx +193 -0
- package/botrun-c/web/components/botrun-incubator/BotrunIncubator.tsx +266 -0
- package/botrun-c/web/components/botrun-incubator/index.ts +1 -0
- package/botrun-c/web/components/chat-input.tsx +1251 -0
- package/botrun-c/web/components/chat-message.tsx +598 -0
- package/botrun-c/web/components/drop-zone.tsx +143 -0
- package/botrun-c/web/components/gdrive/gdrive-add-dialog.tsx +254 -0
- package/botrun-c/web/components/gdrive/gdrive-drawer.tsx +236 -0
- package/botrun-c/web/components/gdrive/gdrive-selector.tsx +226 -0
- package/botrun-c/web/components/gdrive/index.ts +7 -0
- package/botrun-c/web/components/generated-image-card.tsx +363 -0
- package/botrun-c/web/components/github/GitHubConnect.tsx +366 -0
- package/botrun-c/web/components/github/index.ts +2 -0
- package/botrun-c/web/components/import-skill-dialog.tsx +208 -0
- package/botrun-c/web/components/scroll-to-bottom-button.tsx +90 -0
- package/botrun-c/web/components/share-skill-dialog.tsx +175 -0
- package/botrun-c/web/components/skills-editor.tsx +443 -0
- package/botrun-c/web/components/skills-manager-drawer.tsx +586 -0
- package/botrun-c/web/components/smart-button-group.tsx +132 -0
- package/botrun-c/web/config/smart-buttons.ts +295 -0
- package/botrun-c/web/config/welcome-messages.ts +29 -0
- package/botrun-c/web/contexts/AuthContext.tsx +220 -0
- package/botrun-c/web/hooks/use-toast.ts +187 -0
- package/botrun-c/web/hooks/useAppStoreUpdate.ts +356 -0
- package/botrun-c/web/hooks/useAppVersion.ts +113 -0
- package/botrun-c/web/hooks/useAttachments.ts +269 -0
- package/botrun-c/web/hooks/useAuthToken.ts +59 -0
- package/botrun-c/web/hooks/useAutoWelcome.ts +89 -0
- package/botrun-c/web/hooks/useCapacitorPlatform.ts +113 -0
- package/botrun-c/web/hooks/useCapawesomeLiveUpdate.ts +149 -0
- package/botrun-c/web/hooks/useClaudeModel.ts +118 -0
- package/botrun-c/web/hooks/useConversation.ts +115 -0
- package/botrun-c/web/hooks/useConversations.ts +235 -0
- package/botrun-c/web/hooks/useGdriveFolders.ts +199 -0
- package/botrun-c/web/hooks/useGdriveSync.ts +107 -0
- package/botrun-c/web/hooks/useGitHub.ts +409 -0
- package/botrun-c/web/hooks/useScrollToBottom.ts +150 -0
- package/botrun-c/web/hooks/useStatusBar.ts +42 -0
- package/botrun-c/web/hooks/useUserPlan.ts +153 -0
- package/botrun-c/web/lib/api-config.ts +162 -0
- package/botrun-c/web/lib/api-url.ts +62 -0
- package/botrun-c/web/lib/api.ts +105 -0
- package/botrun-c/web/lib/attachment-utils.ts +168 -0
- package/botrun-c/web/lib/build-version.ts +11 -0
- package/botrun-c/web/lib/clipboard-utils.ts +199 -0
- package/botrun-c/web/lib/constants.ts +62 -0
- package/botrun-c/web/lib/conversation-storage.ts +324 -0
- package/botrun-c/web/lib/firebase-capacitor.ts +135 -0
- package/botrun-c/web/lib/firebase.ts +137 -0
- package/botrun-c/web/lib/firestore-auth.ts +61 -0
- package/botrun-c/web/lib/firestore-auth.ts.migration-bak +319 -0
- package/botrun-c/web/lib/image-extractor.ts +156 -0
- package/botrun-c/web/lib/path-utils.ts +48 -0
- package/botrun-c/web/lib/rehype-del-to-mark.ts +19 -0
- package/botrun-c/web/lib/upload-service.ts +326 -0
- package/botrun-c/web/lib/utils.ts +6 -0
- package/botrun-c/web/next.config.js +49 -0
- package/botrun-c/web/package-lock.json +6711 -0
- package/botrun-c/web/package.json +63 -0
- package/botrun-c/web/postcss.config.js +6 -0
- package/botrun-c/web/public/apple_icon.png +0 -0
- package/botrun-c/web/public/google_icon.png +0 -0
- package/botrun-c/web/public/logo-48-small.png +0 -0
- package/botrun-c/web/public/logo-48.png +0 -0
- package/botrun-c/web/scripts/generate-version.js +36 -0
- package/botrun-c/web/scripts/update-build-version.js +41 -0
- package/botrun-c/web/tailwind.config.ts +80 -0
- package/botrun-c/web/test-welcome-message.mjs +115 -0
- package/botrun-c/web/tsconfig.json +42 -0
- package/botrun-c/web/types/agent.ts +6 -0
- package/botrun-c/web/types/attachment.ts +39 -0
- package/botrun-c/web/types/conversation.ts +68 -0
- package/botrun-c/web/types/flutter.d.ts +6 -0
- package/botrun-c/web/types/project.ts +41 -0
- package/botrun-c/web/types/skills.ts +13 -0
- package/botrun-c/web//350/250/272/346/226/267-Skills-/345/211/215/347/253/257/351/241/257/347/244/272/345/225/217/351/241/214.md +83 -0
- package/lib/prompt/prompts/zero-framework/fullstack.md +17 -0
- package/lib/prompt/prompts/zero-framework/segment.md +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Capacitor Firebase Authentication for iOS/Android
|
|
2
|
+
import { Capacitor } from '@capacitor/core';
|
|
3
|
+
import { FirebaseAuthentication } from '@capacitor-firebase/authentication';
|
|
4
|
+
import type { User } from 'firebase/auth';
|
|
5
|
+
|
|
6
|
+
// 版本號:用於確認更新是否生效
|
|
7
|
+
const FIREBASE_CAPACITOR_VERSION = '2.1.0-fix-getIdToken';
|
|
8
|
+
console.log(`[firebase-capacitor] 🔄 Module loaded - Version: ${FIREBASE_CAPACITOR_VERSION}`);
|
|
9
|
+
|
|
10
|
+
export const isNativePlatform = () => {
|
|
11
|
+
const isNative = Capacitor.isNativePlatform();
|
|
12
|
+
console.log('[Capacitor] Platform check:', {
|
|
13
|
+
isNative,
|
|
14
|
+
platform: Capacitor.getPlatform(),
|
|
15
|
+
});
|
|
16
|
+
return isNative;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const signInWithGoogleNative = async (): Promise<User | null> => {
|
|
20
|
+
try {
|
|
21
|
+
console.log(`[Firebase Capacitor] 🚀 Starting Google Sign-In - Version: ${FIREBASE_CAPACITOR_VERSION}`);
|
|
22
|
+
console.log('[Firebase Capacitor] Calling FirebaseAuthentication.signInWithGoogle()...');
|
|
23
|
+
|
|
24
|
+
const result = await FirebaseAuthentication.signInWithGoogle();
|
|
25
|
+
console.log('[Firebase Capacitor] signInWithGoogle returned:', result);
|
|
26
|
+
|
|
27
|
+
console.log('[Firebase Capacitor] ✅ Sign-In successful:', {
|
|
28
|
+
uid: result.user?.uid,
|
|
29
|
+
email: result.user?.email,
|
|
30
|
+
displayName: result.user?.displayName,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 轉換為 Firebase User 格式
|
|
34
|
+
const user: User = {
|
|
35
|
+
uid: result.user?.uid || '',
|
|
36
|
+
email: result.user?.email || null,
|
|
37
|
+
emailVerified: result.user?.emailVerified || false,
|
|
38
|
+
displayName: result.user?.displayName || null,
|
|
39
|
+
photoURL: result.user?.photoUrl || null,
|
|
40
|
+
phoneNumber: result.user?.phoneNumber || null,
|
|
41
|
+
isAnonymous: result.user?.isAnonymous || false,
|
|
42
|
+
tenantId: result.user?.tenantId || null,
|
|
43
|
+
providerData: [],
|
|
44
|
+
metadata: {} as any,
|
|
45
|
+
refreshToken: '',
|
|
46
|
+
providerId: 'google.com',
|
|
47
|
+
delete: async () => {},
|
|
48
|
+
getIdToken: async (forceRefresh?: boolean) => {
|
|
49
|
+
try {
|
|
50
|
+
console.log('[Firebase Capacitor] 🔐 Getting ID token...');
|
|
51
|
+
const tokenResult = await FirebaseAuthentication.getIdToken({ forceRefresh: forceRefresh || false });
|
|
52
|
+
console.log('[Firebase Capacitor] ✅ ID token obtained, length:', tokenResult.token?.length || 0);
|
|
53
|
+
return tokenResult.token || '';
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('[Firebase Capacitor] ❌ Failed to get ID token:', error);
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
getIdTokenResult: async () => ({} as any),
|
|
60
|
+
reload: async () => {},
|
|
61
|
+
toJSON: () => ({}),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return user;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('[Firebase Capacitor] ❌ Sign-In failed:', error);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const signOutNative = async (): Promise<void> => {
|
|
72
|
+
try {
|
|
73
|
+
console.log(`[Firebase Capacitor] 🚪 Signing out - Version: ${FIREBASE_CAPACITOR_VERSION}`);
|
|
74
|
+
await FirebaseAuthentication.signOut();
|
|
75
|
+
console.log('[Firebase Capacitor] ✅ Signed out successfully');
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('[Firebase Capacitor] ❌ Sign-Out failed:', error);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const getCurrentUserNative = async (): Promise<User | null> => {
|
|
83
|
+
try {
|
|
84
|
+
console.log(`[Firebase Capacitor] 🔍 Getting current user - Version: ${FIREBASE_CAPACITOR_VERSION}`);
|
|
85
|
+
|
|
86
|
+
const result = await FirebaseAuthentication.getCurrentUser();
|
|
87
|
+
console.log('[Firebase Capacitor] getCurrentUser returned:', result);
|
|
88
|
+
|
|
89
|
+
if (!result.user) {
|
|
90
|
+
console.log('[Firebase Capacitor] No current user');
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log('[Firebase Capacitor] Current user:', {
|
|
95
|
+
uid: result.user.uid,
|
|
96
|
+
email: result.user.email,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// 轉換為 Firebase User 格式
|
|
100
|
+
const user: User = {
|
|
101
|
+
uid: result.user.uid || '',
|
|
102
|
+
email: result.user.email || null,
|
|
103
|
+
emailVerified: result.user.emailVerified || false,
|
|
104
|
+
displayName: result.user.displayName || null,
|
|
105
|
+
photoURL: result.user.photoUrl || null,
|
|
106
|
+
phoneNumber: result.user.phoneNumber || null,
|
|
107
|
+
isAnonymous: result.user.isAnonymous || false,
|
|
108
|
+
tenantId: result.user.tenantId || null,
|
|
109
|
+
providerData: [],
|
|
110
|
+
metadata: {} as any,
|
|
111
|
+
refreshToken: '',
|
|
112
|
+
providerId: 'google.com',
|
|
113
|
+
delete: async () => {},
|
|
114
|
+
getIdToken: async (forceRefresh?: boolean) => {
|
|
115
|
+
try {
|
|
116
|
+
console.log('[Firebase Capacitor] 🔐 Getting ID token...');
|
|
117
|
+
const tokenResult = await FirebaseAuthentication.getIdToken({ forceRefresh: forceRefresh || false });
|
|
118
|
+
console.log('[Firebase Capacitor] ✅ ID token obtained, length:', tokenResult.token?.length || 0);
|
|
119
|
+
return tokenResult.token || '';
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('[Firebase Capacitor] ❌ Failed to get ID token:', error);
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
getIdTokenResult: async () => ({} as any),
|
|
126
|
+
reload: async () => {},
|
|
127
|
+
toJSON: () => ({}),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return user;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('[Firebase Capacitor] ❌ Get current user failed:', error);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { initializeApp, getApps, getApp, FirebaseApp } from 'firebase/app';
|
|
2
|
+
import { getAuth, Auth, GoogleAuthProvider } from 'firebase/auth';
|
|
3
|
+
import { Capacitor } from '@capacitor/core';
|
|
4
|
+
|
|
5
|
+
const firebaseConfig = {
|
|
6
|
+
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
|
7
|
+
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
8
|
+
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
|
9
|
+
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
|
10
|
+
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
|
11
|
+
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
|
12
|
+
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let app: FirebaseApp | undefined;
|
|
16
|
+
let auth: Auth | undefined;
|
|
17
|
+
let _googleProvider: GoogleAuthProvider | undefined;
|
|
18
|
+
|
|
19
|
+
// 檢查是否為原生平台
|
|
20
|
+
const isNative = Capacitor.isNativePlatform();
|
|
21
|
+
|
|
22
|
+
// 初始化 Firebase App 的函數,確保只在客戶端執行
|
|
23
|
+
function initializeFirebaseClient() {
|
|
24
|
+
if (typeof window !== 'undefined') {
|
|
25
|
+
// 檢查是否在瀏覽器環境
|
|
26
|
+
console.log('[Firebase] Initializing Firebase client...');
|
|
27
|
+
console.log('[Firebase] Platform:', isNative ? 'Native (Capacitor)' : 'Web');
|
|
28
|
+
console.log('[Firebase] Config check:', {
|
|
29
|
+
hasApiKey: !!firebaseConfig.apiKey,
|
|
30
|
+
hasAuthDomain: !!firebaseConfig.authDomain,
|
|
31
|
+
hasProjectId: !!firebaseConfig.projectId,
|
|
32
|
+
apiKeyPrefix: firebaseConfig.apiKey?.substring(0, 10),
|
|
33
|
+
authDomain: firebaseConfig.authDomain,
|
|
34
|
+
projectId: firebaseConfig.projectId,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 如果是原生平台,只初始化 Firebase App,不初始化 Web Auth
|
|
38
|
+
if (isNative) {
|
|
39
|
+
console.log('[Firebase] ⚠️ Native platform detected - skipping Firebase Web Auth initialization');
|
|
40
|
+
console.log('[Firebase] Native auth will be handled by @capacitor-firebase/authentication');
|
|
41
|
+
|
|
42
|
+
// 只初始化 Firebase App(用於其他 Firebase 服務,如 Firestore)
|
|
43
|
+
if (!getApps().length) {
|
|
44
|
+
try {
|
|
45
|
+
app = initializeApp(firebaseConfig);
|
|
46
|
+
console.log('[Firebase] ✅ Firebase app initialized (native mode)');
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('[Firebase] ❌ Failed to initialize Firebase app:', error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return; // 不初始化 Web Auth 和 GoogleProvider
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Web 平台:正常初始化
|
|
55
|
+
// 檢查必要的配置
|
|
56
|
+
if (!firebaseConfig.apiKey || !firebaseConfig.authDomain || !firebaseConfig.projectId) {
|
|
57
|
+
const errorMsg = `[Firebase] ❌ Missing config - apiKey: ${firebaseConfig.apiKey ? 'SET' : 'MISSING'}, authDomain: ${firebaseConfig.authDomain || 'MISSING'}, projectId: ${firebaseConfig.projectId || 'MISSING'}`;
|
|
58
|
+
console.error(errorMsg);
|
|
59
|
+
console.error('[Firebase] ❌ Firebase will not be initialized. Check environment variables.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 成功讀取配置
|
|
64
|
+
console.log('[Firebase] ✅ Config loaded successfully!', {
|
|
65
|
+
authDomain: firebaseConfig.authDomain,
|
|
66
|
+
projectId: firebaseConfig.projectId,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (!getApps().length) {
|
|
70
|
+
console.log('[Firebase] No existing app found, creating new Firebase app');
|
|
71
|
+
try {
|
|
72
|
+
app = initializeApp(firebaseConfig);
|
|
73
|
+
console.log('[Firebase] ✅ Firebase app initialized successfully');
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('[Firebase] ❌ Failed to initialize Firebase app:', error);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
app = getApp();
|
|
80
|
+
console.log('[Firebase] ✅ Using existing Firebase app');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 確保 app 已成功初始化才獲取 auth
|
|
84
|
+
if (app && !auth) {
|
|
85
|
+
try {
|
|
86
|
+
auth = getAuth(app);
|
|
87
|
+
console.log('[Firebase] ✅ Firebase Auth initialized successfully');
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('[Firebase] ❌ Failed to initialize Firebase Auth:', error);
|
|
90
|
+
auth = undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
console.log('[Firebase] Skipping initialization (not in browser environment)');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 在模組載入時呼叫一次初始化函數
|
|
99
|
+
initializeFirebaseClient();
|
|
100
|
+
|
|
101
|
+
// 提供一個獲取 auth 實例的函數
|
|
102
|
+
export function getClientAuth(): Auth | undefined {
|
|
103
|
+
if (!auth && typeof window !== 'undefined' && !isNative) {
|
|
104
|
+
console.warn('[Firebase] Auth is not initialized. This may be due to an earlier error.');
|
|
105
|
+
}
|
|
106
|
+
return auth;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 提供一個獲取 Google Provider 的函數(只在 Web 平台創建)
|
|
110
|
+
export function getGoogleProvider(): GoogleAuthProvider | undefined {
|
|
111
|
+
if (isNative) {
|
|
112
|
+
console.warn('[Firebase] GoogleProvider is not available on native platform. Use signInWithGoogleNative() instead.');
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Lazy initialization: 只在 Web 平台且第一次呼叫時創建
|
|
117
|
+
if (!_googleProvider && typeof window !== 'undefined') {
|
|
118
|
+
console.log('[Firebase] Creating GoogleAuthProvider for web platform');
|
|
119
|
+
_googleProvider = new GoogleAuthProvider();
|
|
120
|
+
_googleProvider.setCustomParameters({
|
|
121
|
+
prompt: 'select_account'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return _googleProvider;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 為了向後相容,export 一個 proxy
|
|
129
|
+
export const googleProvider = new Proxy({} as GoogleAuthProvider, {
|
|
130
|
+
get(target, prop) {
|
|
131
|
+
const provider = getGoogleProvider();
|
|
132
|
+
if (!provider) {
|
|
133
|
+
throw new Error('GoogleProvider is not available on native platform');
|
|
134
|
+
}
|
|
135
|
+
return (provider as any)[prop];
|
|
136
|
+
}
|
|
137
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firestore Authentication & Authorization Utilities
|
|
3
|
+
* 簡化版:只要 Gmail 登入即可使用
|
|
4
|
+
*
|
|
5
|
+
* 🔑 架構說明:
|
|
6
|
+
* - 任何 Google 帳號都可以登入使用
|
|
7
|
+
* - 不需要白名單驗證
|
|
8
|
+
* - 不需要使用者文件設定
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { User } from 'firebase/auth';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 檢查使用者是否有權存取當前服務
|
|
15
|
+
* 簡化版:任何 Gmail 登入即可使用
|
|
16
|
+
*/
|
|
17
|
+
export async function checkServiceAccess(email: string): Promise<{
|
|
18
|
+
allowed: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
}> {
|
|
21
|
+
try {
|
|
22
|
+
console.log('✅ [Service Access] Gmail 登入成功:', email);
|
|
23
|
+
console.log('✅ [Service Access] 任何 Google 帳號都可以使用此系統');
|
|
24
|
+
|
|
25
|
+
// 直接允許存取
|
|
26
|
+
return {
|
|
27
|
+
allowed: true,
|
|
28
|
+
};
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('❌ [Service Access] Error:', error);
|
|
31
|
+
return {
|
|
32
|
+
allowed: false,
|
|
33
|
+
error: '系統錯誤,請稍後再試。',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 檢查 Firebase Token 中的 Custom Claims
|
|
40
|
+
* 簡化版:不檢查 Custom Claims,直接允許
|
|
41
|
+
*/
|
|
42
|
+
export async function checkCustomClaims(user: User): Promise<{
|
|
43
|
+
valid: boolean;
|
|
44
|
+
error?: string;
|
|
45
|
+
}> {
|
|
46
|
+
try {
|
|
47
|
+
console.log('✅ [Auth] 使用者已登入:', user.email);
|
|
48
|
+
console.log('✅ [Auth] 任何 Google 帳號都可以使用此系統');
|
|
49
|
+
|
|
50
|
+
// 直接允許
|
|
51
|
+
return {
|
|
52
|
+
valid: true,
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('❌ [Auth] Error:', error);
|
|
56
|
+
return {
|
|
57
|
+
valid: false,
|
|
58
|
+
error: '無法驗證您的權限。請重新登入。',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firestore Authentication & Authorization Utilities
|
|
3
|
+
* 檢查使用者是否在白名單、是否有權存取當前服務
|
|
4
|
+
*
|
|
5
|
+
* 🔑 架構說明:
|
|
6
|
+
* - 統一使用 scoop-386004 專案處理 Auth 和 Firestore
|
|
7
|
+
* - 簡化為單一 Firebase 專案,避免跨專案複雜度
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { User } from 'firebase/auth';
|
|
11
|
+
import { getFirestore, doc, getDoc } from 'firebase/firestore';
|
|
12
|
+
import { getFirebaseApp } from './firebase';
|
|
13
|
+
|
|
14
|
+
export interface UserData {
|
|
15
|
+
email: string;
|
|
16
|
+
allowedService: string;
|
|
17
|
+
serviceUrl: string;
|
|
18
|
+
bucketName: string;
|
|
19
|
+
bucketHash: string;
|
|
20
|
+
role: string;
|
|
21
|
+
displayName?: string;
|
|
22
|
+
loginMethods: string[];
|
|
23
|
+
active: boolean;
|
|
24
|
+
createdAt: any;
|
|
25
|
+
updatedAt: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SystemAllowedUsers {
|
|
29
|
+
emails: string[];
|
|
30
|
+
updatedAt: any;
|
|
31
|
+
updatedBy: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 檢查使用者是否在系統白名單中
|
|
36
|
+
*/
|
|
37
|
+
export async function isUserInWhitelist(email: string): Promise<boolean> {
|
|
38
|
+
try {
|
|
39
|
+
console.log('🔄 [Firestore] Checking whitelist for:', email);
|
|
40
|
+
console.log('🔧 [Firestore] Using project:', process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID);
|
|
41
|
+
const db = getFirestore(getFirebaseApp());
|
|
42
|
+
console.log('✅ [Firestore] Firestore instance created');
|
|
43
|
+
const systemRef = doc(db, 'system', 'allowedUsers');
|
|
44
|
+
console.log('📋 [Firestore] Document path: system/allowedUsers');
|
|
45
|
+
|
|
46
|
+
console.log('📋 [Firestore] Fetching allowedUsers document...');
|
|
47
|
+
const systemDoc = await getDoc(systemRef);
|
|
48
|
+
|
|
49
|
+
if (!systemDoc.exists()) {
|
|
50
|
+
console.warn('⚠️ [Firestore] System allowedUsers document not found');
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const data = systemDoc.data() as SystemAllowedUsers;
|
|
55
|
+
const isAllowed = data.emails?.includes(email) || false;
|
|
56
|
+
|
|
57
|
+
console.log(`✅ [Firestore] Whitelist check for ${email}: ${isAllowed}`);
|
|
58
|
+
console.log('📊 [Firestore] Total allowed users:', data.emails?.length || 0);
|
|
59
|
+
return isAllowed;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('❌ [Firestore] Error checking whitelist:', error);
|
|
62
|
+
console.error('📍 [Firestore] Error details:', JSON.stringify(error, null, 2));
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 取得使用者資料
|
|
69
|
+
*/
|
|
70
|
+
export async function getUserData(email: string): Promise<UserData | null> {
|
|
71
|
+
try {
|
|
72
|
+
console.log('🔄 [Firestore] Fetching user data for:', email);
|
|
73
|
+
console.log('🔧 [Firestore] Using project:', process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID);
|
|
74
|
+
const db = getFirestore(getFirebaseApp());
|
|
75
|
+
console.log('✅ [Firestore] Firestore instance created');
|
|
76
|
+
const userRef = doc(db, 'users', email);
|
|
77
|
+
console.log('📋 [Firestore] Document path: users/' + email);
|
|
78
|
+
|
|
79
|
+
console.log('📋 [Firestore] Querying users collection...');
|
|
80
|
+
const userDoc = await getDoc(userRef);
|
|
81
|
+
|
|
82
|
+
if (!userDoc.exists()) {
|
|
83
|
+
console.warn(`⚠️ [Firestore] User document not found: ${email}`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const data = userDoc.data() as UserData;
|
|
88
|
+
console.log(`✅ [Firestore] User data loaded:`);
|
|
89
|
+
console.log(' Email:', data.email);
|
|
90
|
+
console.log(' Service:', data.allowedService);
|
|
91
|
+
console.log(' Active:', data.active);
|
|
92
|
+
return data;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('❌ [Firestore] Error fetching user data:', error);
|
|
95
|
+
console.error('📍 [Firestore] Error details:', JSON.stringify(error, null, 2));
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 檢查使用者是否有權存取當前服務
|
|
102
|
+
*/
|
|
103
|
+
export async function checkServiceAccess(email: string): Promise<{
|
|
104
|
+
allowed: boolean;
|
|
105
|
+
userData?: UserData;
|
|
106
|
+
error?: string;
|
|
107
|
+
redirectUrl?: string;
|
|
108
|
+
}> {
|
|
109
|
+
try {
|
|
110
|
+
console.log('🔄 [Service Access] Starting service access check for:', email);
|
|
111
|
+
|
|
112
|
+
// 1. 檢查白名單
|
|
113
|
+
console.log('🔄 [Service Access] Step 1/4: Checking whitelist...');
|
|
114
|
+
const inWhitelist = await isUserInWhitelist(email);
|
|
115
|
+
if (!inWhitelist) {
|
|
116
|
+
console.error('❌ [Service Access] User not in whitelist');
|
|
117
|
+
return {
|
|
118
|
+
allowed: false,
|
|
119
|
+
error: '您的帳號未被授權使用此系統。請聯絡管理員。',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
console.log('✅ [Service Access] User is in whitelist');
|
|
123
|
+
|
|
124
|
+
// 2. 取得使用者資料
|
|
125
|
+
console.log('🔄 [Service Access] Step 2/4: Fetching user data...');
|
|
126
|
+
const userData = await getUserData(email);
|
|
127
|
+
if (!userData) {
|
|
128
|
+
console.error('❌ [Service Access] User data not found');
|
|
129
|
+
return {
|
|
130
|
+
allowed: false,
|
|
131
|
+
error: '找不到您的使用者設定。請聯絡管理員。',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
console.log('✅ [Service Access] User data retrieved');
|
|
135
|
+
|
|
136
|
+
// 3. 檢查是否為 active
|
|
137
|
+
console.log('🔄 [Service Access] Step 3/4: Checking user active status...');
|
|
138
|
+
if (!userData.active) {
|
|
139
|
+
console.error('❌ [Service Access] User account is inactive');
|
|
140
|
+
return {
|
|
141
|
+
allowed: false,
|
|
142
|
+
error: '您的帳號已被停用。請聯絡管理員。',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
console.log('✅ [Service Access] User account is active');
|
|
146
|
+
|
|
147
|
+
// 4. 檢查當前 Service 與儲存使用者專屬 API URL
|
|
148
|
+
console.log('🔄 [Service Access] Step 4/4: Service validation...');
|
|
149
|
+
const currentHostname = window.location.hostname;
|
|
150
|
+
|
|
151
|
+
// 🎯 正確的域名格式判斷:
|
|
152
|
+
// 統一前端: j.cameo.tw (Load Balancer) 或 botrun-j-{revision}.asia-northeast1.run.app (東京)
|
|
153
|
+
// 個人後端: j.cameo.tw/u/{hash}/ (Load Balancer) 或 botrun-j-{hash}-{revision}.asia-east1.run.app (台灣)
|
|
154
|
+
|
|
155
|
+
const pathname = window.location.pathname;
|
|
156
|
+
const isUnifiedFrontend =
|
|
157
|
+
currentHostname === 'j.cameo.tw' && !pathname.startsWith('/u/') || // Load Balancer 統一前端
|
|
158
|
+
currentHostname.includes('.asia-northeast1.run.app') || // 舊的 Cloud Run 統一前端
|
|
159
|
+
currentHostname === 'localhost'; // 開發環境
|
|
160
|
+
|
|
161
|
+
// 提取 service hash (8位16進制) - 只在個人後端有效
|
|
162
|
+
let currentServiceHash: string | null = null;
|
|
163
|
+
|
|
164
|
+
if (currentHostname === 'j.cameo.tw') {
|
|
165
|
+
// Load Balancer URL: j.cameo.tw/u/{hash}/
|
|
166
|
+
const pathnameHashMatch = pathname.match(/^\/u\/([0-9a-f]{8})/);
|
|
167
|
+
currentServiceHash = pathnameHashMatch ? pathnameHashMatch[1] : null;
|
|
168
|
+
} else {
|
|
169
|
+
// 舊的 Cloud Run URL: botrun-j-{hash}-{revision}.asia-east1.run.app
|
|
170
|
+
const hostnameHashMatch = currentHostname.match(/botrun-j-([0-9a-f]{8})-\d+\.asia-east1\.run\.app/);
|
|
171
|
+
currentServiceHash = hostnameHashMatch ? hostnameHashMatch[1] : null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const allowedServiceHash = userData.bucketHash;
|
|
175
|
+
|
|
176
|
+
console.log('🔍 [Service Access] Service info:');
|
|
177
|
+
console.log(` Current hostname: ${currentHostname}`);
|
|
178
|
+
console.log(` Is unified frontend: ${isUnifiedFrontend}`);
|
|
179
|
+
console.log(` Current hash: ${currentServiceHash || '(統一前端)'}`);
|
|
180
|
+
console.log(` User's allowed service: ${userData.allowedService}`);
|
|
181
|
+
console.log(` User's service URL: ${userData.serviceUrl}`);
|
|
182
|
+
console.log(` User's bucket hash: ${allowedServiceHash}`);
|
|
183
|
+
|
|
184
|
+
// 📌 新架構:統一前端作為登入入口,登入後重定向到個人後端
|
|
185
|
+
// userData.serviceUrl 用於重定向目標
|
|
186
|
+
if (isUnifiedFrontend) {
|
|
187
|
+
console.log('✅ [Service Access] 統一前端 - 允許登入');
|
|
188
|
+
console.log('📍 [Service Access] 使用者將重定向到: ' + userData.serviceUrl);
|
|
189
|
+
// 允許登入,userData 包含 serviceUrl 供重定向使用
|
|
190
|
+
return {
|
|
191
|
+
allowed: true,
|
|
192
|
+
userData, // 包含 serviceUrl,AuthContext 會用來重定向
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 如果使用者直接訪問專屬服務 URL,檢查 hash 是否匹配
|
|
197
|
+
if (currentServiceHash !== allowedServiceHash) {
|
|
198
|
+
console.warn('⚠️ [Service Access] 訪問了其他使用者的專屬服務');
|
|
199
|
+
return {
|
|
200
|
+
allowed: false,
|
|
201
|
+
userData,
|
|
202
|
+
error: `您的帳號授權使用 ${userData.allowedService},請使用主服務登入。`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
console.log('✅ [Service Access] 訪問自己的專屬服務(允許)');
|
|
206
|
+
|
|
207
|
+
// 5. 所有檢查通過
|
|
208
|
+
console.log('✅ [Service Access] ALL CHECKS PASSED');
|
|
209
|
+
return {
|
|
210
|
+
allowed: true,
|
|
211
|
+
userData,
|
|
212
|
+
};
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error('❌ [Service Access] Error checking service access:', error);
|
|
215
|
+
console.error('📍 [Service Access] Error details:', JSON.stringify(error, null, 2));
|
|
216
|
+
return {
|
|
217
|
+
allowed: false,
|
|
218
|
+
error: '系統錯誤,請稍後再試。',
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 檢查 Firebase Token 中的 Custom Claims
|
|
225
|
+
*/
|
|
226
|
+
export async function checkCustomClaims(user: User): Promise<{
|
|
227
|
+
valid: boolean;
|
|
228
|
+
allowedService?: string;
|
|
229
|
+
error?: string;
|
|
230
|
+
}> {
|
|
231
|
+
try {
|
|
232
|
+
console.log('🔄 [Custom Claims] Starting custom claims check for:', user.email);
|
|
233
|
+
console.log('⏱️ [Custom Claims] Fetching ID token result...');
|
|
234
|
+
|
|
235
|
+
const tokenResult = await user.getIdTokenResult();
|
|
236
|
+
const claims = tokenResult.claims;
|
|
237
|
+
|
|
238
|
+
console.log(`✅ [Custom Claims] Token retrieved`);
|
|
239
|
+
console.log('📋 [Custom Claims] Claims:', claims);
|
|
240
|
+
|
|
241
|
+
// 檢查是否有 allowedService claim
|
|
242
|
+
if (!claims.allowedService) {
|
|
243
|
+
console.warn('⚠️ [Custom Claims] No allowedService claim (might be a new user)');
|
|
244
|
+
return {
|
|
245
|
+
valid: false,
|
|
246
|
+
error: '您的帳號尚未完成設定。請登出後重新登入,或聯絡管理員。',
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 檢查當前服務是否符合
|
|
251
|
+
const currentHostname = window.location.hostname;
|
|
252
|
+
|
|
253
|
+
// 🎯 正確的域名格式判斷:
|
|
254
|
+
// 統一前端: j.cameo.tw (Load Balancer) 或 botrun-j-{revision}.asia-northeast1.run.app (東京)
|
|
255
|
+
// 個人後端: j.cameo.tw/u/{hash}/ (Load Balancer) 或 botrun-j-{hash}-{revision}.asia-east1.run.app (台灣)
|
|
256
|
+
|
|
257
|
+
// 判斷是否為統一前端
|
|
258
|
+
const pathname = window.location.pathname;
|
|
259
|
+
const isUnifiedFrontend =
|
|
260
|
+
currentHostname === 'j.cameo.tw' && !pathname.startsWith('/u/') || // Load Balancer 統一前端
|
|
261
|
+
currentHostname.includes('.asia-northeast1.run.app') || // 舊的 Cloud Run 統一前端
|
|
262
|
+
currentHostname === 'localhost'; // 開發環境
|
|
263
|
+
|
|
264
|
+
// 提取 service hash (8位16進制) - 只在個人後端有效
|
|
265
|
+
let currentServiceHash: string | null = null;
|
|
266
|
+
|
|
267
|
+
if (currentHostname === 'j.cameo.tw') {
|
|
268
|
+
// Load Balancer URL: j.cameo.tw/u/{hash}/
|
|
269
|
+
const pathnameHashMatch = pathname.match(/^\/u\/([0-9a-f]{8})/);
|
|
270
|
+
currentServiceHash = pathnameHashMatch ? pathnameHashMatch[1] : null;
|
|
271
|
+
} else {
|
|
272
|
+
// 舊的 Cloud Run URL: botrun-j-{hash}-{revision}.asia-east1.run.app
|
|
273
|
+
const hostnameHashMatch = currentHostname.match(/botrun-j-([0-9a-f]{8})-\d+\.asia-east1\.run\.app/);
|
|
274
|
+
currentServiceHash = hostnameHashMatch ? hostnameHashMatch[1] : null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const currentService = currentServiceHash ? `botrun-j-${currentServiceHash}` : null;
|
|
278
|
+
|
|
279
|
+
console.log('🔍 [Custom Claims] Service check:');
|
|
280
|
+
console.log(' Current hostname:', currentHostname);
|
|
281
|
+
console.log(' Is unified frontend:', isUnifiedFrontend);
|
|
282
|
+
console.log(' Extracted hash:', currentServiceHash || '(none)');
|
|
283
|
+
console.log(' Current service:', currentService || '(統一前端)');
|
|
284
|
+
console.log(' Allowed service:', claims.allowedService);
|
|
285
|
+
|
|
286
|
+
// 📌 新架構:統一前端作為登入入口,允許所有使用者登入
|
|
287
|
+
if (isUnifiedFrontend) {
|
|
288
|
+
console.log('✅ [Custom Claims] 統一前端 - 允許登入,準備重定向');
|
|
289
|
+
console.log('📍 [Custom Claims] 使用者應前往: ' + claims.allowedService);
|
|
290
|
+
return {
|
|
291
|
+
valid: true,
|
|
292
|
+
allowedService: claims.allowedService as string,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 如果使用者直接訪問專屬服務,檢查是否匹配
|
|
297
|
+
if (claims.allowedService !== currentService) {
|
|
298
|
+
console.error('❌ [Custom Claims] 訪問了其他使用者的專屬服務');
|
|
299
|
+
return {
|
|
300
|
+
valid: false,
|
|
301
|
+
allowedService: claims.allowedService as string,
|
|
302
|
+
error: `您的帳號授權使用 ${claims.allowedService},請使用主服務登入。`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
console.log('✅ [Custom Claims] All checks passed');
|
|
307
|
+
return {
|
|
308
|
+
valid: true,
|
|
309
|
+
allowedService: claims.allowedService as string,
|
|
310
|
+
};
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error('❌ [Custom Claims] Error checking custom claims:', error);
|
|
313
|
+
console.error('📍 [Custom Claims] Error details:', JSON.stringify(error, null, 2));
|
|
314
|
+
return {
|
|
315
|
+
valid: false,
|
|
316
|
+
error: '無法驗證您的權限。請重新登入。',
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|