vibefast-cli 1.1.5 → 1.2.1
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/CHANGELOG.md +32 -0
- package/README.md +63 -169
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +547 -589
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/checklist.d.ts +1 -1
- package/dist/commands/checklist.d.ts.map +1 -1
- package/dist/commands/checklist.js +40 -39
- package/dist/commands/checklist.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +22 -22
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +58 -53
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/health.d.ts +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +101 -93
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +416 -296
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/remove.d.ts +1 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +77 -64
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/core/__tests__/detect.test.js +68 -34
- package/dist/core/__tests__/detect.test.js.map +1 -1
- package/dist/core/ast.d.ts +14 -0
- package/dist/core/ast.d.ts.map +1 -0
- package/dist/core/ast.js +239 -0
- package/dist/core/ast.js.map +1 -0
- package/dist/core/codemod.d.ts.map +1 -1
- package/dist/core/codemod.js +62 -44
- package/dist/core/codemod.js.map +1 -1
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +51 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/detect.d.ts +8 -2
- package/dist/core/detect.d.ts.map +1 -1
- package/dist/core/detect.js +52 -21
- package/dist/core/detect.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +9 -8
- package/dist/core/errors.js.map +1 -1
- package/dist/core/exec.d.ts +16 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +48 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/manualSteps.d.ts +7 -0
- package/dist/core/manualSteps.d.ts.map +1 -0
- package/dist/core/manualSteps.js +59 -0
- package/dist/core/manualSteps.js.map +1 -0
- package/dist/core/paths.d.ts +3 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +14 -10
- package/dist/core/paths.js.map +1 -1
- package/dist/core/spinner.d.ts +1 -1
- package/dist/core/spinner.d.ts.map +1 -1
- package/dist/core/spinner.js +38 -8
- package/dist/core/spinner.js.map +1 -1
- package/dist/core/vosk.d.ts.map +1 -1
- package/dist/core/vosk.js +50 -39
- package/dist/core/vosk.js.map +1 -1
- package/docs/manual-testing.md +91 -0
- package/package.json +6 -3
- package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
- package/recipes/audio-recorder/recipe.json +3 -3
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
- package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
- package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
- package/recipes/audio-recorder-supabase/recipe.json +35 -0
- package/recipes/audio-recorder-supabase@latest.zip +0 -0
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
- package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
- package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
- package/recipes/charts/recipe.json +4 -13
- package/recipes/charts@latest.zip +0 -0
- package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
- package/recipes/chatbot/recipe.json +26 -92
- package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
- package/recipes/chatbot-supabase/recipe.json +79 -0
- package/recipes/chatbot-supabase@latest.zip +0 -0
- package/recipes/chatbot.zip +0 -0
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis.ts +0 -1
- package/recipes/image-analysis/recipe.json +15 -55
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
- package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
- package/recipes/image-analysis-supabase/recipe.json +57 -0
- package/recipes/image-analysis-supabase@latest.zip +0 -0
- package/recipes/image-analysis@latest.zip +0 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
- package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
- package/recipes/image-generator/recipe.json +16 -39
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
- package/recipes/image-generator-supabase/recipe.json +59 -0
- package/recipes/image-generator-supabase@latest.zip +0 -0
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/ios-widget/recipe.json +15 -24
- package/recipes/ios-widget@latest.zip +0 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
- package/recipes/onboarding/recipe.json +15 -0
- package/recipes/onboarding@latest.zip +0 -0
- package/recipes/payments/recipe.json +28 -61
- package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
- package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
- package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
- package/recipes/payments-supabase/recipe.json +51 -0
- package/recipes/payments-supabase@latest.zip +0 -0
- package/recipes/payments@latest.zip +0 -0
- package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
- package/recipes/quiz/recipe.json +6 -9
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
- package/recipes/tracker-app/recipe.json +7 -10
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/voice-bot/recipe.json +8 -68
- package/recipes/voice-bot.zip +0 -0
- package/recipes/voice-bot@latest.zip +0 -0
- package/recipes/wake-word/recipe.json +10 -9
- package/recipes/wake-word.zip +0 -0
- package/recipes/wake-word@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
- package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
- package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
- package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
- package/recipes/image-analysis/packages/backend/convex/imageAnalysisFunctions.ts +0 -325
- package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
- package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
- package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
- package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
- package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
- /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/index.tsx +0 -0
package/dist/core/vosk.js
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
|
-
import { appendFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, unlinkSync, } from
|
|
2
|
-
import https from
|
|
3
|
-
import { join, resolve } from
|
|
4
|
-
import { log } from
|
|
5
|
-
import { extractZipSafe } from
|
|
6
|
-
import {
|
|
7
|
-
const MODEL_URL =
|
|
8
|
-
const MODEL_NAME =
|
|
1
|
+
import { appendFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, unlinkSync, } from "fs";
|
|
2
|
+
import https from "https";
|
|
3
|
+
import { join, resolve } from "path";
|
|
4
|
+
import { log } from "./log.js";
|
|
5
|
+
import { extractZipSafe } from "./archive.js";
|
|
6
|
+
import { spawnSync } from "child_process";
|
|
7
|
+
const MODEL_URL = "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip";
|
|
8
|
+
const MODEL_NAME = "model-en-us";
|
|
9
9
|
/**
|
|
10
10
|
* Download and setup Vosk model for wake-word detection
|
|
11
11
|
*/
|
|
12
12
|
export async function setupVoskModel(projectRoot, options) {
|
|
13
|
-
const ASSETS_DIR = resolve(projectRoot,
|
|
14
|
-
const LEGACY_DIR = resolve(projectRoot,
|
|
13
|
+
const ASSETS_DIR = resolve(projectRoot, "apps/native/assets/vosk-model");
|
|
14
|
+
const LEGACY_DIR = resolve(projectRoot, "assets/vosk-model");
|
|
15
15
|
const MODEL_PATH = join(ASSETS_DIR, MODEL_NAME);
|
|
16
16
|
const LEGACY_MODEL_PATH = join(LEGACY_DIR, MODEL_NAME);
|
|
17
|
-
const ZIP_PATH = join(ASSETS_DIR,
|
|
18
|
-
const GITIGNORE_PATH = resolve(projectRoot,
|
|
17
|
+
const ZIP_PATH = join(ASSETS_DIR, "model.zip");
|
|
18
|
+
const GITIGNORE_PATH = resolve(projectRoot, ".gitignore");
|
|
19
19
|
const ensureGitignoreEntry = () => {
|
|
20
|
-
const entry =
|
|
21
|
-
let content =
|
|
20
|
+
const entry = "apps/native/assets/vosk-model/model-en-us";
|
|
21
|
+
let content = "";
|
|
22
22
|
if (existsSync(GITIGNORE_PATH)) {
|
|
23
|
-
content = readFileSync(GITIGNORE_PATH,
|
|
24
|
-
const hasEntry = content
|
|
23
|
+
content = readFileSync(GITIGNORE_PATH, "utf8");
|
|
24
|
+
const hasEntry = content
|
|
25
|
+
.split(/\r?\n/)
|
|
26
|
+
.some((line) => line.trim() === entry);
|
|
25
27
|
if (hasEntry)
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
28
|
-
const prefix = content.endsWith(
|
|
30
|
+
const prefix = content.endsWith("\n") || content.length === 0 ? "" : "\n";
|
|
29
31
|
appendFileSync(GITIGNORE_PATH, `${prefix}${entry}\n`);
|
|
30
32
|
};
|
|
31
33
|
const finalizeSuccess = (message) => {
|
|
@@ -36,11 +38,11 @@ export async function setupVoskModel(projectRoot, options) {
|
|
|
36
38
|
return true;
|
|
37
39
|
};
|
|
38
40
|
const manualFallback = () => {
|
|
39
|
-
log.plain(
|
|
40
|
-
log.info(
|
|
41
|
-
log.plain(
|
|
42
|
-
log.plain(
|
|
43
|
-
log.plain(
|
|
41
|
+
log.plain("");
|
|
42
|
+
log.info("Manual setup:");
|
|
43
|
+
log.plain(" 1. Download: https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip");
|
|
44
|
+
log.plain(" 2. Extract to: apps/native/assets/vosk-model/");
|
|
45
|
+
log.plain(" 3. Rename folder to: model-en-us");
|
|
44
46
|
return false;
|
|
45
47
|
};
|
|
46
48
|
try {
|
|
@@ -48,16 +50,16 @@ export async function setupVoskModel(projectRoot, options) {
|
|
|
48
50
|
if (existsSync(LEGACY_MODEL_PATH) && !existsSync(MODEL_PATH)) {
|
|
49
51
|
mkdirSync(ASSETS_DIR, { recursive: true });
|
|
50
52
|
renameSync(LEGACY_MODEL_PATH, MODEL_PATH);
|
|
51
|
-
log.info(
|
|
53
|
+
log.info("✓ Moved existing Vosk model from legacy path to apps/native/assets/vosk-model");
|
|
52
54
|
return finalizeSuccess();
|
|
53
55
|
}
|
|
54
56
|
// Check if model already exists
|
|
55
57
|
if (existsSync(MODEL_PATH)) {
|
|
56
|
-
log.info(
|
|
58
|
+
log.info("✓ Vosk model already exists");
|
|
57
59
|
return finalizeSuccess();
|
|
58
60
|
}
|
|
59
61
|
if (options?.dryRun) {
|
|
60
|
-
log.info(
|
|
62
|
+
log.info("[DRY RUN] Would download Vosk model (~40MB)");
|
|
61
63
|
return true;
|
|
62
64
|
}
|
|
63
65
|
// Create assets directory if it doesn't exist
|
|
@@ -67,13 +69,13 @@ export async function setupVoskModel(projectRoot, options) {
|
|
|
67
69
|
let installed = false;
|
|
68
70
|
// Attempt direct download first
|
|
69
71
|
try {
|
|
70
|
-
log.info(
|
|
72
|
+
log.info("📥 Downloading Vosk model (~40MB)...");
|
|
71
73
|
await downloadFile(MODEL_URL, ZIP_PATH);
|
|
72
|
-
log.info(
|
|
74
|
+
log.info("📦 Extracting model...");
|
|
73
75
|
await extractZipSafe(ZIP_PATH, ASSETS_DIR);
|
|
74
|
-
const extractedFolder = readdirSync(ASSETS_DIR).find((f) => f.startsWith(
|
|
76
|
+
const extractedFolder = readdirSync(ASSETS_DIR).find((f) => f.startsWith("vosk-model-small-en-us"));
|
|
75
77
|
if (!extractedFolder) {
|
|
76
|
-
throw new Error(
|
|
78
|
+
throw new Error("Extracted folder not found. The zip structure may have changed.");
|
|
77
79
|
}
|
|
78
80
|
const extractedPath = join(ASSETS_DIR, extractedFolder);
|
|
79
81
|
renameSync(extractedPath, MODEL_PATH);
|
|
@@ -81,13 +83,20 @@ export async function setupVoskModel(projectRoot, options) {
|
|
|
81
83
|
installed = true;
|
|
82
84
|
}
|
|
83
85
|
catch (error) {
|
|
84
|
-
log.info(
|
|
86
|
+
log.info("Direct download failed, retrying with bundled script...");
|
|
85
87
|
}
|
|
86
88
|
// Fallback: try bundled script if direct download failed
|
|
87
|
-
const scriptPath = resolve(projectRoot,
|
|
89
|
+
const scriptPath = resolve(projectRoot, "apps/native/scripts/download-vosk-model.mjs");
|
|
88
90
|
if (!installed && existsSync(scriptPath)) {
|
|
89
91
|
try {
|
|
90
|
-
|
|
92
|
+
// Use spawnSync with args array for safety (no shell interpolation)
|
|
93
|
+
const result = spawnSync("node", [scriptPath], {
|
|
94
|
+
stdio: "inherit",
|
|
95
|
+
cwd: projectRoot,
|
|
96
|
+
});
|
|
97
|
+
if (result.error) {
|
|
98
|
+
throw result.error;
|
|
99
|
+
}
|
|
91
100
|
installed = existsSync(MODEL_PATH);
|
|
92
101
|
}
|
|
93
102
|
catch (e) {
|
|
@@ -95,7 +104,7 @@ export async function setupVoskModel(projectRoot, options) {
|
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
if (installed) {
|
|
98
|
-
return finalizeSuccess(
|
|
107
|
+
return finalizeSuccess("✓ Vosk model ready");
|
|
99
108
|
}
|
|
100
109
|
return manualFallback();
|
|
101
110
|
}
|
|
@@ -118,22 +127,24 @@ function downloadFile(url, dest) {
|
|
|
118
127
|
.then(resolve)
|
|
119
128
|
.catch(reject);
|
|
120
129
|
}
|
|
121
|
-
const totalSize = parseInt(response.headers[
|
|
130
|
+
const totalSize = parseInt(response.headers["content-length"] || "0", 10);
|
|
122
131
|
let downloaded = 0;
|
|
123
|
-
response.on(
|
|
132
|
+
response.on("data", (chunk) => {
|
|
124
133
|
downloaded += chunk.length;
|
|
125
134
|
const percent = ((downloaded / totalSize) * 100).toFixed(1);
|
|
126
|
-
process.stdout.write(`\r ${percent}% (${(downloaded / 1024 / 1024).toFixed(1)}MB / ${(totalSize /
|
|
135
|
+
process.stdout.write(`\r ${percent}% (${(downloaded / 1024 / 1024).toFixed(1)}MB / ${(totalSize /
|
|
136
|
+
1024 /
|
|
137
|
+
1024).toFixed(1)}MB)`);
|
|
127
138
|
});
|
|
128
139
|
response.pipe(file);
|
|
129
|
-
file.on(
|
|
140
|
+
file.on("finish", () => {
|
|
130
141
|
file.close(() => {
|
|
131
|
-
process.stdout.write(
|
|
142
|
+
process.stdout.write("\r");
|
|
132
143
|
resolve();
|
|
133
144
|
});
|
|
134
145
|
});
|
|
135
146
|
})
|
|
136
|
-
.on(
|
|
147
|
+
.on("error", (err) => {
|
|
137
148
|
unlinkSync(dest);
|
|
138
149
|
reject(err);
|
|
139
150
|
});
|
package/dist/core/vosk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vosk.js","sourceRoot":"","sources":["../../src/core/vosk.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,IAAI,CAAC;AACZ,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"vosk.js","sourceRoot":"","sources":["../../src/core/vosk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Manual Testing Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to manually test the `vibefast-cli` during development without affecting your globally installed version (if any).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- You are in the `vibefast-cli` directory.
|
|
8
|
+
- You have run `npm install`.
|
|
9
|
+
|
|
10
|
+
## Method 1: The "Alias" Method (Recommended)
|
|
11
|
+
|
|
12
|
+
This method allows you to run your local build as `vf-dev` without overwriting your global `vf` command.
|
|
13
|
+
|
|
14
|
+
1. **Build the CLI**:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm run build
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **Create an Alias** (run this in your terminal):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Run this inside the vibefast-cli directory
|
|
24
|
+
alias vf-dev="node $(pwd)/dist/index.js"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. **Test in a Sandbox**:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Go to a temporary directory
|
|
31
|
+
mkdir ~/Desktop/vf-playground
|
|
32
|
+
cd ~/Desktop/vf-playground
|
|
33
|
+
|
|
34
|
+
# Run your local CLI
|
|
35
|
+
vf-dev init
|
|
36
|
+
vf-dev add chatbot
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Method 2: The "Link" Method
|
|
40
|
+
|
|
41
|
+
Use this if you want to replace your global `vf` command with your local version.
|
|
42
|
+
|
|
43
|
+
1. **Build**:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
2. **Link**:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm link
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
3. **Test**:
|
|
56
|
+
Now `vf` runs your local code anywhere.
|
|
57
|
+
|
|
58
|
+
4. **Unlink (Revert)**:
|
|
59
|
+
```bash
|
|
60
|
+
npm unlink -g vibefast-cli
|
|
61
|
+
# Then reinstall the production version if needed
|
|
62
|
+
npm i -g vibefast-cli
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## What to Test?
|
|
66
|
+
|
|
67
|
+
### 1. Initialization
|
|
68
|
+
|
|
69
|
+
- Run `vf init`.
|
|
70
|
+
- Check if `.vibefast/starter.json` is created.
|
|
71
|
+
- Check if it asks for a license key (if not already saved).
|
|
72
|
+
|
|
73
|
+
### 2. Adding Features
|
|
74
|
+
|
|
75
|
+
- Run `vf add <feature>`.
|
|
76
|
+
- **Verify**:
|
|
77
|
+
- Files are copied to `apps/native` or `apps/web`.
|
|
78
|
+
- `app.config.ts` (Native) has the plugin added (if applicable).
|
|
79
|
+
- `package.json` dependencies are updated (or prompted).
|
|
80
|
+
|
|
81
|
+
### 3. Removing Features
|
|
82
|
+
|
|
83
|
+
- Run `vf remove <feature>`.
|
|
84
|
+
- **Verify**:
|
|
85
|
+
- Files are deleted.
|
|
86
|
+
- `app.config.ts` plugin is removed (if implemented) or you are warned.
|
|
87
|
+
|
|
88
|
+
### 4. Edge Cases
|
|
89
|
+
|
|
90
|
+
- Run in a folder that is _not_ a VibeFast project (should fail gracefully).
|
|
91
|
+
- Run with invalid arguments.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibefast-cli",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "CLI for installing VibeFast features into your monorepo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"dev": "tsx src/index.ts",
|
|
12
12
|
"test": "vitest",
|
|
13
|
-
"prepublishOnly": "npm run build"
|
|
13
|
+
"prepublishOnly": "npm run build",
|
|
14
|
+
"prepare": "husky"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"vibefast",
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"picocolors": "^1.0.0",
|
|
48
49
|
"readline-sync": "^1.4.10",
|
|
49
50
|
"simple-git": "^3.30.0",
|
|
51
|
+
"ts-morph": "^27.0.2",
|
|
50
52
|
"yauzl": "^2.10.0"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
@@ -54,11 +56,12 @@
|
|
|
54
56
|
"@types/node": "^20.11.0",
|
|
55
57
|
"@types/readline-sync": "^1.4.8",
|
|
56
58
|
"@types/yauzl": "^2.10.3",
|
|
59
|
+
"husky": "^9.1.7",
|
|
57
60
|
"tsx": "^4.7.0",
|
|
58
61
|
"typescript": "^5.3.3",
|
|
59
62
|
"vitest": "^1.2.0"
|
|
60
63
|
},
|
|
61
64
|
"engines": {
|
|
62
|
-
"node": ">=
|
|
65
|
+
"node": ">=20.10.0"
|
|
63
66
|
}
|
|
64
67
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "audio-recorder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Record and manage voice notes",
|
|
5
5
|
"copy": [
|
|
6
6
|
{
|
|
7
|
-
"from": "apps/native/src/app/
|
|
7
|
+
"from": "apps/native/src/app/audio-recorder",
|
|
8
8
|
"to": "apps/native/src/app/(root)/(protected)/audio-recorder"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
@@ -19,4 +19,4 @@
|
|
|
19
19
|
"color": "#EF4444"
|
|
20
20
|
},
|
|
21
21
|
"target": "native"
|
|
22
|
-
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AudioSource,
|
|
3
|
+
useAudioPlayer,
|
|
4
|
+
useAudioPlayerStatus,
|
|
5
|
+
} from 'expo-audio';
|
|
6
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
7
|
+
import { View, type ViewStyle } from 'react-native';
|
|
8
|
+
import { tv } from 'tailwind-variants';
|
|
9
|
+
|
|
10
|
+
import { Button, Icon, Text } from '@/components/ui';
|
|
11
|
+
import { useThemeConfig } from '@/lib/use-theme-config';
|
|
12
|
+
|
|
13
|
+
// import { Progress } from '@/components/ui/progress';
|
|
14
|
+
import { AudioWaveform } from './audio-waveform';
|
|
15
|
+
|
|
16
|
+
const audioPlayerStyles = tv({
|
|
17
|
+
slots: {
|
|
18
|
+
container: 'm-2 rounded-2xl p-4',
|
|
19
|
+
waveformContainer: 'mb-3 items-center',
|
|
20
|
+
progressBarContainer: 'mb-3 px-1',
|
|
21
|
+
timerContainer: 'mb-3 flex-row items-center justify-between',
|
|
22
|
+
timerText: 'font-mono text-sm text-muted',
|
|
23
|
+
controlsContainer: 'mt-2 flex-row items-center justify-center gap-4',
|
|
24
|
+
controlButton: 'size-14',
|
|
25
|
+
playPauseButton: 'size-16 rounded-full',
|
|
26
|
+
loadingContainer: 'items-center p-2',
|
|
27
|
+
loadingText: 'text-muted',
|
|
28
|
+
},
|
|
29
|
+
variants: {
|
|
30
|
+
shrinked: {
|
|
31
|
+
true: {
|
|
32
|
+
container: 'm-0 rounded-2xl p-2',
|
|
33
|
+
waveformContainer: 'mb-0 items-center',
|
|
34
|
+
progressBarContainer: 'mb-0 px-1',
|
|
35
|
+
timerContainer: 'mb-0 flex-row items-center justify-between',
|
|
36
|
+
controlsContainer: 'mt-0 flex-row items-center justify-center gap-2',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export interface AudioPlayerProps {
|
|
43
|
+
source: AudioSource;
|
|
44
|
+
shrinked?: boolean;
|
|
45
|
+
style?: ViewStyle & { className?: string };
|
|
46
|
+
showControls?: boolean;
|
|
47
|
+
showWaveform?: boolean;
|
|
48
|
+
showTimer?: boolean;
|
|
49
|
+
showProgressBar?: boolean;
|
|
50
|
+
autoPlay?: boolean;
|
|
51
|
+
onPlaybackStatusUpdate?: (status: any) => void;
|
|
52
|
+
// Custom sizing props for compact mode
|
|
53
|
+
waveformHeight?: number;
|
|
54
|
+
waveformBarCount?: number;
|
|
55
|
+
waveformBarWidth?: number;
|
|
56
|
+
waveformBarGap?: number;
|
|
57
|
+
controlButtonSize?: number;
|
|
58
|
+
playButtonSize?: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function AudioPlayer({
|
|
62
|
+
source,
|
|
63
|
+
style,
|
|
64
|
+
shrinked = false,
|
|
65
|
+
showControls = true,
|
|
66
|
+
showWaveform = true,
|
|
67
|
+
showTimer = true,
|
|
68
|
+
// showProgressBar = true,
|
|
69
|
+
autoPlay = false,
|
|
70
|
+
onPlaybackStatusUpdate,
|
|
71
|
+
// Custom sizing with defaults
|
|
72
|
+
waveformHeight = 80,
|
|
73
|
+
waveformBarCount = 60,
|
|
74
|
+
waveformBarWidth = 4,
|
|
75
|
+
waveformBarGap = 1.5,
|
|
76
|
+
controlButtonSize = 24,
|
|
77
|
+
playButtonSize = 28,
|
|
78
|
+
}: AudioPlayerProps) {
|
|
79
|
+
const {
|
|
80
|
+
container,
|
|
81
|
+
waveformContainer,
|
|
82
|
+
// progressBarContainer,
|
|
83
|
+
timerContainer,
|
|
84
|
+
timerText,
|
|
85
|
+
controlsContainer,
|
|
86
|
+
controlButton,
|
|
87
|
+
playPauseButton,
|
|
88
|
+
loadingContainer,
|
|
89
|
+
loadingText,
|
|
90
|
+
} = audioPlayerStyles({ shrinked });
|
|
91
|
+
const theme = useThemeConfig();
|
|
92
|
+
const player = useAudioPlayer(source);
|
|
93
|
+
const status = useAudioPlayerStatus(player);
|
|
94
|
+
const [duration, setDuration] = useState(0);
|
|
95
|
+
const [position, setPosition] = useState(0);
|
|
96
|
+
const [isSeeking, setIsSeeking] = useState(false);
|
|
97
|
+
|
|
98
|
+
// Enhanced waveform data - more bars for smoother visualization
|
|
99
|
+
const [waveformData] = useState<number[]>(
|
|
100
|
+
Array.from({ length: 60 }, (_, i) => {
|
|
101
|
+
// Create more varied and realistic waveform pattern
|
|
102
|
+
const base1 = Math.sin((i / 60) * Math.PI * 6) * 0.4 + 0.5;
|
|
103
|
+
const base2 = Math.sin((i / 60) * Math.PI * 2.5) * 0.3 + 0.4;
|
|
104
|
+
const noise = (Math.random() - 0.5) * 0.25;
|
|
105
|
+
const peak = Math.random() < 0.15 ? Math.random() * 0.4 : 0; // Occasional peaks
|
|
106
|
+
return Math.max(0.15, Math.min(0.95, (base1 + base2) / 2 + noise + peak));
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (autoPlay && player.isLoaded && !player.playing) {
|
|
112
|
+
player.play();
|
|
113
|
+
}
|
|
114
|
+
}, [autoPlay, player]);
|
|
115
|
+
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!isSeeking && status?.isLoaded) {
|
|
118
|
+
setDuration(status.duration || 0);
|
|
119
|
+
setPosition(status.currentTime || 0);
|
|
120
|
+
|
|
121
|
+
if (status.didJustFinish && status.duration > 0) {
|
|
122
|
+
player.seekTo(0);
|
|
123
|
+
player.pause();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
onPlaybackStatusUpdate?.(status);
|
|
127
|
+
}
|
|
128
|
+
}, [status, isSeeking, player, onPlaybackStatusUpdate]);
|
|
129
|
+
|
|
130
|
+
const handlePlayPause = () => {
|
|
131
|
+
if (player.playing) {
|
|
132
|
+
player.pause();
|
|
133
|
+
} else {
|
|
134
|
+
player.play();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const handleBackFiveSeconds = () => {
|
|
139
|
+
const newPosition = Math.max(0, position - 5);
|
|
140
|
+
seekToPosition(newPosition);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const handleRestart = () => {
|
|
144
|
+
seekToPosition(0);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Unified seeking function
|
|
148
|
+
const seekToPosition = useCallback(
|
|
149
|
+
(newPosition: number) => {
|
|
150
|
+
if (player.isLoaded && duration > 0) {
|
|
151
|
+
const clampedPosition = Math.max(0, Math.min(duration, newPosition));
|
|
152
|
+
player.seekTo(clampedPosition);
|
|
153
|
+
setPosition(clampedPosition);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
[player, duration],
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Handle waveform seeking
|
|
160
|
+
const handleWaveformSeek = useCallback(
|
|
161
|
+
(seekPercentage: number) => {
|
|
162
|
+
if (duration > 0) {
|
|
163
|
+
const newPosition = (seekPercentage / 100) * duration;
|
|
164
|
+
seekToPosition(newPosition);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
[duration, seekToPosition],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Handle progress bar seeking
|
|
171
|
+
// const handleProgressSeek = useCallback(
|
|
172
|
+
// (progressValue: number) => {
|
|
173
|
+
// if (duration > 0) {
|
|
174
|
+
// const newPosition = (progressValue / 100) * duration;
|
|
175
|
+
// seekToPosition(newPosition);
|
|
176
|
+
// }
|
|
177
|
+
// },
|
|
178
|
+
// [duration, seekToPosition]
|
|
179
|
+
// );
|
|
180
|
+
|
|
181
|
+
// Handle seeking start/end for smooth updates
|
|
182
|
+
const handleSeekStart = useCallback(() => {
|
|
183
|
+
setIsSeeking(true);
|
|
184
|
+
}, []);
|
|
185
|
+
|
|
186
|
+
const handleSeekEnd = useCallback(() => {
|
|
187
|
+
setIsSeeking(false);
|
|
188
|
+
}, []);
|
|
189
|
+
|
|
190
|
+
const formatTime = (seconds: number) => {
|
|
191
|
+
const mins = Math.floor(seconds / 60);
|
|
192
|
+
const secs = Math.floor(seconds % 60);
|
|
193
|
+
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const progressPercentage = duration > 0 ? (position / duration) * 100 : 0;
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<View className={container({ class: style?.className })}>
|
|
200
|
+
{/* Waveform Visualization with seeking capability */}
|
|
201
|
+
{showWaveform && (
|
|
202
|
+
<View className={waveformContainer()}>
|
|
203
|
+
<AudioWaveform
|
|
204
|
+
data={waveformData}
|
|
205
|
+
isPlaying={player.playing}
|
|
206
|
+
progress={progressPercentage}
|
|
207
|
+
onSeek={handleWaveformSeek}
|
|
208
|
+
onSeekStart={handleSeekStart}
|
|
209
|
+
onSeekEnd={handleSeekEnd}
|
|
210
|
+
height={waveformHeight}
|
|
211
|
+
barCount={waveformBarCount}
|
|
212
|
+
barWidth={waveformBarWidth}
|
|
213
|
+
barGap={waveformBarGap}
|
|
214
|
+
animated={true}
|
|
215
|
+
showProgress={true}
|
|
216
|
+
interactive={true} // Enable seeking
|
|
217
|
+
/>
|
|
218
|
+
</View>
|
|
219
|
+
)}
|
|
220
|
+
|
|
221
|
+
{/* Interactive Progress Bar */}
|
|
222
|
+
{/* {showProgressBar && (
|
|
223
|
+
<View className={progressBarContainer()}>
|
|
224
|
+
<Progress
|
|
225
|
+
value={progressPercentage}
|
|
226
|
+
onValueChange={handleProgressSeek}
|
|
227
|
+
onSeekStart={handleSeekStart}
|
|
228
|
+
onSeekEnd={handleSeekEnd}
|
|
229
|
+
style={{ height: 8 }}
|
|
230
|
+
indicatorClassName="bg-destructive"
|
|
231
|
+
/>
|
|
232
|
+
</View>
|
|
233
|
+
)} */}
|
|
234
|
+
|
|
235
|
+
{/* Timer Display */}
|
|
236
|
+
{showTimer && (
|
|
237
|
+
<View className={timerContainer()}>
|
|
238
|
+
<Text className={timerText()}>{formatTime(position)}</Text>
|
|
239
|
+
<Text className={timerText()}>{formatTime(duration)}</Text>
|
|
240
|
+
</View>
|
|
241
|
+
)}
|
|
242
|
+
|
|
243
|
+
{/* Playback Controls */}
|
|
244
|
+
{showControls && (
|
|
245
|
+
<View className={controlsContainer()}>
|
|
246
|
+
{/* Back 5s Button */}
|
|
247
|
+
<Button
|
|
248
|
+
variant="ghost"
|
|
249
|
+
size="icon"
|
|
250
|
+
className={controlButton()}
|
|
251
|
+
onPress={handleBackFiveSeconds}
|
|
252
|
+
disabled={!player.isLoaded}
|
|
253
|
+
>
|
|
254
|
+
<Icon name="refresh" size={controlButtonSize} />
|
|
255
|
+
</Button>
|
|
256
|
+
|
|
257
|
+
{/* Play/Pause Button */}
|
|
258
|
+
<Button
|
|
259
|
+
variant="default"
|
|
260
|
+
size="icon"
|
|
261
|
+
className={playPauseButton()}
|
|
262
|
+
onPress={handlePlayPause}
|
|
263
|
+
disabled={!player.isLoaded}
|
|
264
|
+
>
|
|
265
|
+
{player.playing ? (
|
|
266
|
+
<Icon
|
|
267
|
+
name="pause"
|
|
268
|
+
size={playButtonSize}
|
|
269
|
+
color={theme.colors.background}
|
|
270
|
+
/>
|
|
271
|
+
) : (
|
|
272
|
+
<Icon
|
|
273
|
+
name="play"
|
|
274
|
+
size={playButtonSize}
|
|
275
|
+
color={theme.colors.background}
|
|
276
|
+
/>
|
|
277
|
+
)}
|
|
278
|
+
</Button>
|
|
279
|
+
|
|
280
|
+
{/* Stop Button */}
|
|
281
|
+
<Button
|
|
282
|
+
variant="ghost"
|
|
283
|
+
size="icon"
|
|
284
|
+
className={controlButton()}
|
|
285
|
+
onPress={handleRestart}
|
|
286
|
+
disabled={!player.isLoaded}
|
|
287
|
+
>
|
|
288
|
+
<Icon name="stop" size={controlButtonSize} />
|
|
289
|
+
</Button>
|
|
290
|
+
</View>
|
|
291
|
+
)}
|
|
292
|
+
|
|
293
|
+
{/* Loading State */}
|
|
294
|
+
{!player.isLoaded && (
|
|
295
|
+
<View className={loadingContainer()}>
|
|
296
|
+
<Text className={loadingText()}>Loading audio...</Text>
|
|
297
|
+
</View>
|
|
298
|
+
)}
|
|
299
|
+
</View>
|
|
300
|
+
);
|
|
301
|
+
}
|