vibefast-cli 0.1.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/FINAL-STATUS.md +144 -0
- package/HOW-IT-WORKS.md +559 -0
- package/PLAN.md +453 -0
- package/README.md +129 -0
- package/RECIPES-READY.md +172 -0
- package/STATUS.md +199 -0
- package/SUCCESS.md +259 -0
- package/TESTING-CHECKLIST.md +450 -0
- package/cloudflare-worker/.wrangler/state/v3/kv/64907821e2634080acce34618d2f3d4c/blobs/11f2769953c717e188062bc644da97c1fd1e4d6d0813a226ce7567dba759afab0000019a736fb8d4 +1 -0
- package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite +0 -0
- package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-shm +0 -0
- package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-wal +0 -0
- package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite +0 -0
- package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-shm +0 -0
- package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-wal +0 -0
- package/cloudflare-worker/.wrangler/state/v3/r2/vibefast-recipes/blobs/620e8cf7c35d9806da25dee237e1d7e8b2432bd98f755b60e2c7f08a48d2c7b90000019a73736484 +0 -0
- package/cloudflare-worker/MIGRATION.md +160 -0
- package/cloudflare-worker/QUICKSTART.md +200 -0
- package/cloudflare-worker/README.md +242 -0
- package/cloudflare-worker/generate-token.js +32 -0
- package/cloudflare-worker/mini-native@latest.zip +0 -0
- package/cloudflare-worker/setup.sh +143 -0
- package/cloudflare-worker/test-recipe/apps/native/src/app/mini/index.tsx +15 -0
- package/cloudflare-worker/test-recipe/recipe.json +16 -0
- package/cloudflare-worker/worker.js +308 -0
- package/cloudflare-worker/wrangler.toml +13 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +149 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/devices.d.ts +3 -0
- package/dist/commands/devices.d.ts.map +1 -0
- package/dist/commands/devices.js +35 -0
- package/dist/commands/devices.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +67 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +40 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +23 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +67 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/core/__tests__/journal.test.d.ts +2 -0
- package/dist/core/__tests__/journal.test.d.ts.map +1 -0
- package/dist/core/__tests__/journal.test.js +101 -0
- package/dist/core/__tests__/journal.test.js.map +1 -0
- package/dist/core/__tests__/validate.test.d.ts +2 -0
- package/dist/core/__tests__/validate.test.d.ts.map +1 -0
- package/dist/core/__tests__/validate.test.js +53 -0
- package/dist/core/__tests__/validate.test.js.map +1 -0
- package/dist/core/archive.d.ts +2 -0
- package/dist/core/archive.d.ts.map +1 -0
- package/dist/core/archive.js +59 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/auth.d.ts +15 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +76 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/codemod.d.ts +20 -0
- package/dist/core/codemod.d.ts.map +1 -0
- package/dist/core/codemod.js +150 -0
- package/dist/core/codemod.js.map +1 -0
- package/dist/core/fsx.d.ts +12 -0
- package/dist/core/fsx.d.ts.map +1 -0
- package/dist/core/fsx.js +70 -0
- package/dist/core/fsx.js.map +1 -0
- package/dist/core/http.d.ts +30 -0
- package/dist/core/http.d.ts.map +1 -0
- package/dist/core/http.js +95 -0
- package/dist/core/http.js.map +1 -0
- package/dist/core/journal.d.ts +18 -0
- package/dist/core/journal.d.ts.map +1 -0
- package/dist/core/journal.js +34 -0
- package/dist/core/journal.js.map +1 -0
- package/dist/core/log.d.ts +8 -0
- package/dist/core/log.d.ts.map +1 -0
- package/dist/core/log.js +9 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/pathGuard.d.ts +3 -0
- package/dist/core/pathGuard.d.ts.map +1 -0
- package/dist/core/pathGuard.js +18 -0
- package/dist/core/pathGuard.js.map +1 -0
- package/dist/core/paths.d.ts +11 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +22 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/validate.d.ts +8 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +27 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/docs/decisions.md +55 -0
- package/package.json +39 -0
- package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/index.ts +4 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
- package/recipes/audio-recorder/recipe.json +22 -0
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
- package/recipes/charts/apps/native/src/features/charts/README.md +185 -0
- package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +223 -0
- package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +40 -0
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +143 -0
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +196 -0
- package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +65 -0
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +143 -0
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +246 -0
- package/recipes/charts/apps/native/src/features/charts/components/index.ts +10 -0
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +308 -0
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +180 -0
- package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +188 -0
- package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +265 -0
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +322 -0
- package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +183 -0
- package/recipes/charts/apps/native/src/features/charts/types/index.ts +66 -0
- package/recipes/charts/recipe.json +22 -0
- 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/app/index.tsx +302 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +469 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +246 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +115 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +173 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +20 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +143 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +664 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +359 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +79 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +207 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +86 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +162 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +62 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +40 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +238 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +180 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +60 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
- package/recipes/chatbot/recipe.json +22 -0
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
- package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/_layout.tsx +25 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +237 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/components/gallery-image.tsx +26 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +210 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +93 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/models/models.ts +66 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/services/image-gallery-service.ts +98 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/services/image-save-service.ts +121 -0
- package/recipes/image-generator/recipe.json +22 -0
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
- package/recipes/quiz/apps/native/src/features/quiz/components/question.tsx +67 -0
- package/recipes/quiz/apps/native/src/features/quiz/config.ts +11 -0
- package/recipes/quiz/apps/native/src/features/quiz/index.tsx +133 -0
- package/recipes/quiz/recipe.json +22 -0
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +108 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/animated-number.tsx +102 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/calorie-card.tsx +66 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/circular-progress.tsx +97 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/floating-add-button.tsx +27 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/macro-card.tsx +80 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/promo-banner.tsx +98 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/recently-logged.tsx +64 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/components/week-calendar.tsx +68 -0
- package/recipes/tracker-app/recipe.json +22 -0
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/upload-all.sh +32 -0
- package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +27 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/README.md +185 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/components/conversation-status.tsx +76 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/components/index.ts +4 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/components/message-input.tsx +98 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-bot-screen.tsx +173 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-controls.tsx +73 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/index.ts +3 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/services/index.ts +1 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/services/use-voice-bot.ts +161 -0
- package/recipes/voice-bot/apps/native/src/features/voice-bot/types.ts +29 -0
- package/recipes/voice-bot/recipe.json +22 -0
- package/recipes/voice-bot@latest.zip +0 -0
- package/scripts/create-recipes.mjs +189 -0
- package/src/commands/add.ts +183 -0
- package/src/commands/devices.ts +38 -0
- package/src/commands/doctor.ts +67 -0
- package/src/commands/list.ts +45 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/logout.ts +15 -0
- package/src/commands/remove.ts +78 -0
- package/src/core/__tests__/journal.test.ts +119 -0
- package/src/core/__tests__/validate.test.ts +64 -0
- package/src/core/archive.ts +69 -0
- package/src/core/auth.ts +103 -0
- package/src/core/codemod.ts +211 -0
- package/src/core/fsx.ts +80 -0
- package/src/core/http.ts +136 -0
- package/src/core/journal.ts +64 -0
- package/src/core/log.ts +9 -0
- package/src/core/pathGuard.ts +22 -0
- package/src/core/paths.ts +33 -0
- package/src/core/validate.ts +44 -0
- package/src/index.ts +27 -0
- package/test-critical-cases.mjs +258 -0
- package/tsconfig.json +21 -0
- package/vitest.config.mts +12 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Cloudflare Worker Quick Start
|
|
2
|
+
|
|
3
|
+
## What You Have Now
|
|
4
|
+
|
|
5
|
+
Your current worker at `https://vibefast.mzafar611.workers.dev` is close but missing:
|
|
6
|
+
- Proper routing (`/api/recipe/fetch` instead of `/`)
|
|
7
|
+
- Signed URLs (yours uses public URLs)
|
|
8
|
+
- Additional endpoints for `list`, `devices`, etc.
|
|
9
|
+
|
|
10
|
+
## Deploy the New Worker (2 Options)
|
|
11
|
+
|
|
12
|
+
### Option 1: Automated Setup (Recommended)
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd vibefast-cli/cloudflare-worker
|
|
16
|
+
./setup.sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This script will:
|
|
20
|
+
1. ✅ Create KV namespace for licenses
|
|
21
|
+
2. ✅ Create R2 bucket for recipes
|
|
22
|
+
3. ✅ Add a test license token
|
|
23
|
+
4. ✅ Create and upload a test recipe
|
|
24
|
+
5. ✅ Deploy the worker
|
|
25
|
+
|
|
26
|
+
**Time:** ~2 minutes
|
|
27
|
+
|
|
28
|
+
### Option 2: Manual Setup
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 1. Create KV namespace
|
|
32
|
+
wrangler kv:namespace create "LICENSES"
|
|
33
|
+
# Copy the ID and update wrangler.toml
|
|
34
|
+
|
|
35
|
+
# 2. Create R2 bucket
|
|
36
|
+
wrangler r2 bucket create vibefast-recipes
|
|
37
|
+
|
|
38
|
+
# 3. Generate and add a token
|
|
39
|
+
node generate-token.js
|
|
40
|
+
# Copy the wrangler command and run it
|
|
41
|
+
|
|
42
|
+
# 4. Deploy
|
|
43
|
+
wrangler deploy
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## After Deployment
|
|
47
|
+
|
|
48
|
+
### 1. Get Your Worker URL
|
|
49
|
+
|
|
50
|
+
After running `wrangler deploy`, you'll see:
|
|
51
|
+
```
|
|
52
|
+
Published vibefast-cli-worker
|
|
53
|
+
https://vibefast-cli-worker.YOUR_SUBDOMAIN.workers.dev
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Update CLI Configuration
|
|
57
|
+
|
|
58
|
+
**Option A:** Environment variable (temporary)
|
|
59
|
+
```bash
|
|
60
|
+
export VIBEFAST_WORKER_URL=https://vibefast-cli-worker.YOUR_SUBDOMAIN.workers.dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Option B:** Update CLI code (permanent)
|
|
64
|
+
Edit `vibefast-cli/src/core/http.ts`:
|
|
65
|
+
```typescript
|
|
66
|
+
const WORKER_URL = process.env.VIBEFAST_WORKER_URL || 'https://vibefast-cli-worker.YOUR_SUBDOMAIN.workers.dev';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then rebuild:
|
|
70
|
+
```bash
|
|
71
|
+
cd vibefast-cli
|
|
72
|
+
npm run build
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Test the Full Flow
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cd vibefast-monorepo
|
|
79
|
+
|
|
80
|
+
# Login with test token
|
|
81
|
+
vf login --token TEST_TOKEN_12345
|
|
82
|
+
|
|
83
|
+
# Verify setup
|
|
84
|
+
vf doctor
|
|
85
|
+
|
|
86
|
+
# List available recipes
|
|
87
|
+
vf list
|
|
88
|
+
|
|
89
|
+
# Install a feature
|
|
90
|
+
vf add mini-native
|
|
91
|
+
|
|
92
|
+
# Check what was installed
|
|
93
|
+
cat .vibefast/journal.json
|
|
94
|
+
|
|
95
|
+
# Remove it
|
|
96
|
+
vf remove mini-native
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Troubleshooting
|
|
100
|
+
|
|
101
|
+
### "Failed to fetch recipe: Not found"
|
|
102
|
+
- Check that recipes are uploaded to R2: `wrangler r2 object list vibefast-recipes`
|
|
103
|
+
- Recipe filename must match: `<feature>@latest.zip`
|
|
104
|
+
|
|
105
|
+
### "Invalid or inactive token"
|
|
106
|
+
- Verify token is in KV: `wrangler kv:key get --binding=LICENSES "lic:<hash>"`
|
|
107
|
+
- Check token hash: `node generate-token.js YOUR_TOKEN`
|
|
108
|
+
|
|
109
|
+
### "Device limit reached"
|
|
110
|
+
- List devices: `vf devices`
|
|
111
|
+
- Deactivate one: `vf devices --deactivate <id>`
|
|
112
|
+
|
|
113
|
+
### Worker not responding
|
|
114
|
+
- Check logs: `wrangler tail`
|
|
115
|
+
- Verify bindings in `wrangler.toml`
|
|
116
|
+
|
|
117
|
+
## Adding More Recipes
|
|
118
|
+
|
|
119
|
+
### 1. Create Recipe Structure
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
mkdir -p my-recipe/apps/native/src/app/my-feature
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 2. Add Files
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Create the feature component
|
|
129
|
+
cat > my-recipe/apps/native/src/app/my-feature/index.tsx << 'EOF'
|
|
130
|
+
import { View, Text } from 'react-native';
|
|
131
|
+
|
|
132
|
+
export default function MyFeature() {
|
|
133
|
+
return (
|
|
134
|
+
<View className="flex-1 items-center justify-center">
|
|
135
|
+
<Text className="text-2xl">My Feature</Text>
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
EOF
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 3. Create Manifest
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cat > my-recipe/recipe.json << 'EOF'
|
|
146
|
+
{
|
|
147
|
+
"name": "my-feature",
|
|
148
|
+
"version": "0.1.0",
|
|
149
|
+
"description": "My awesome feature",
|
|
150
|
+
"copy": [
|
|
151
|
+
{
|
|
152
|
+
"from": "apps/native/src/app/my-feature",
|
|
153
|
+
"to": "apps/native/src/app/(root)/(protected)/my-feature"
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"nav": {
|
|
157
|
+
"href": "/(root)/(protected)/my-feature",
|
|
158
|
+
"label": "My Feature"
|
|
159
|
+
},
|
|
160
|
+
"target": "native"
|
|
161
|
+
}
|
|
162
|
+
EOF
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 4. Package and Upload
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cd my-recipe
|
|
169
|
+
zip -r ../my-feature@latest.zip .
|
|
170
|
+
cd ..
|
|
171
|
+
wrangler r2 object put vibefast-recipes/my-feature@latest.zip --file=my-feature@latest.zip
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 5. Install via CLI
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
cd vibefast-monorepo
|
|
178
|
+
vf add my-feature
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Production Checklist
|
|
182
|
+
|
|
183
|
+
Before going live:
|
|
184
|
+
|
|
185
|
+
- [ ] Replace test tokens with real customer tokens
|
|
186
|
+
- [ ] Set up proper token generation system
|
|
187
|
+
- [ ] Add monitoring (Cloudflare Analytics)
|
|
188
|
+
- [ ] Set up alerts for errors
|
|
189
|
+
- [ ] Implement proper rate limiting (KV-based)
|
|
190
|
+
- [ ] Add token revocation system
|
|
191
|
+
- [ ] Set up automated backups of KV data
|
|
192
|
+
- [ ] Document customer onboarding flow
|
|
193
|
+
- [ ] Create admin dashboard for license management
|
|
194
|
+
|
|
195
|
+
## Next Steps
|
|
196
|
+
|
|
197
|
+
1. Run `./setup.sh` to deploy
|
|
198
|
+
2. Test with `vf doctor` and `vf list`
|
|
199
|
+
3. Create your first real recipe (Phase 4)
|
|
200
|
+
4. Start building features!
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# VibeFast CLI Cloudflare Worker
|
|
2
|
+
|
|
3
|
+
Backend API for VibeFast CLI authentication and recipe delivery.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### 1. Install Wrangler CLI
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g wrangler
|
|
11
|
+
wrangler login
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 2. Create KV Namespace
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
wrangler kv:namespace create "LICENSES"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Copy the `id` from the output and update `wrangler.toml`:
|
|
21
|
+
```toml
|
|
22
|
+
[[kv_namespaces]]
|
|
23
|
+
binding = "LICENSES"
|
|
24
|
+
id = "YOUR_KV_NAMESPACE_ID_HERE"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. Create R2 Bucket
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
wrangler r2 bucket create vibefast-recipes
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 4. Add a Test License
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Generate token hash
|
|
37
|
+
echo -n "TEST_TOKEN_12345" | openssl dgst -sha256 -hex
|
|
38
|
+
# Output: (stdin)= abc123...
|
|
39
|
+
|
|
40
|
+
# Add to KV
|
|
41
|
+
wrangler kv:key put --binding=LICENSES "lic:abc123..." '{
|
|
42
|
+
"status": "active",
|
|
43
|
+
"max_devices": 2,
|
|
44
|
+
"devices": [],
|
|
45
|
+
"lastSeen": null
|
|
46
|
+
}' --preview false
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or use this Node.js script:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const crypto = require('crypto');
|
|
53
|
+
const token = 'TEST_TOKEN_12345';
|
|
54
|
+
const hash = crypto.createHash('sha256').update(token).digest('hex');
|
|
55
|
+
console.log('Token:', token);
|
|
56
|
+
console.log('Hash:', hash);
|
|
57
|
+
console.log('KV Key:', `lic:${hash}`);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 5. Upload a Test Recipe
|
|
61
|
+
|
|
62
|
+
Create a test recipe zip:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
mkdir -p test-recipe
|
|
66
|
+
echo '{"name":"mini-native","version":"0.1.0","target":"native","copy":[],"nav":{"href":"/mini","label":"Mini"}}' > test-recipe/recipe.json
|
|
67
|
+
zip -r mini-native@latest.zip test-recipe/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Upload to R2:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
wrangler r2 object put vibefast-recipes/mini-native@latest.zip --file=mini-native@latest.zip
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 6. Deploy Worker
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
wrangler deploy
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 7. Update CLI Environment Variable
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
export VIBEFAST_WORKER_URL=https://vibefast.YOUR_SUBDOMAIN.workers.dev
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Or update the CLI's `src/core/http.ts`:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const WORKER_URL = process.env.VIBEFAST_WORKER_URL || 'https://vibefast.YOUR_SUBDOMAIN.workers.dev';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Testing
|
|
95
|
+
|
|
96
|
+
### Test Recipe Fetch
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
curl -X POST "https://vibefast.YOUR_SUBDOMAIN.workers.dev/api/recipe/fetch" \
|
|
100
|
+
-H "Content-Type: application/json" \
|
|
101
|
+
-d '{
|
|
102
|
+
"token": "TEST_TOKEN_12345",
|
|
103
|
+
"device": {
|
|
104
|
+
"id": "test-device-1",
|
|
105
|
+
"os": "darwin",
|
|
106
|
+
"arch": "arm64",
|
|
107
|
+
"version": "0.1.0"
|
|
108
|
+
},
|
|
109
|
+
"feature": "mini-native",
|
|
110
|
+
"target": "native",
|
|
111
|
+
"starter": {
|
|
112
|
+
"name": "vibefast",
|
|
113
|
+
"version": "1.0.0"
|
|
114
|
+
}
|
|
115
|
+
}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Expected response:
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"ok": true,
|
|
122
|
+
"signedUrl": "https://...",
|
|
123
|
+
"expiresIn": 180,
|
|
124
|
+
"watermark": "abc12345-test1234"
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Test List Recipes
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
curl -X GET "https://vibefast.YOUR_SUBDOMAIN.workers.dev/api/recipes/list" \
|
|
132
|
+
-H "Authorization: Bearer TEST_TOKEN_12345"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Test List Devices
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
curl -X GET "https://vibefast.YOUR_SUBDOMAIN.workers.dev/api/devices/list" \
|
|
139
|
+
-H "Authorization: Bearer TEST_TOKEN_12345"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Test Deactivate Device
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
curl -X POST "https://vibefast.YOUR_SUBDOMAIN.workers.dev/api/devices/deactivate" \
|
|
146
|
+
-H "Authorization: Bearer TEST_TOKEN_12345" \
|
|
147
|
+
-H "Content-Type: application/json" \
|
|
148
|
+
-d '{"deviceId": "test-device-1"}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## API Endpoints
|
|
152
|
+
|
|
153
|
+
### POST `/api/recipe/fetch`
|
|
154
|
+
Validates token, checks device slots, returns signed URL to recipe zip.
|
|
155
|
+
|
|
156
|
+
**Request:**
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"token": "string",
|
|
160
|
+
"device": { "id": "string", "os": "string", "arch": "string", "version": "string" },
|
|
161
|
+
"feature": "string",
|
|
162
|
+
"target": "native|web",
|
|
163
|
+
"starter": { "name": "string", "version": "string" }
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Response:**
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"ok": true,
|
|
171
|
+
"signedUrl": "string",
|
|
172
|
+
"expiresIn": 180,
|
|
173
|
+
"watermark": "string"
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### GET `/api/recipes/list`
|
|
178
|
+
Lists available recipes.
|
|
179
|
+
|
|
180
|
+
**Headers:** `Authorization: Bearer <token>`
|
|
181
|
+
|
|
182
|
+
**Response:**
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"recipes": [
|
|
186
|
+
{ "name": "string", "target": "native|web", "description": "string", "version": "string" }
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### GET `/api/devices/list`
|
|
192
|
+
Lists active devices for the token.
|
|
193
|
+
|
|
194
|
+
**Headers:** `Authorization: Bearer <token>`
|
|
195
|
+
|
|
196
|
+
**Response:**
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"devices": [
|
|
200
|
+
{ "id": "string", "os": "string", "arch": "string", "lastSeen": "string" }
|
|
201
|
+
],
|
|
202
|
+
"maxDevices": 2
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### POST `/api/devices/deactivate`
|
|
207
|
+
Deactivates a device.
|
|
208
|
+
|
|
209
|
+
**Headers:** `Authorization: Bearer <token>`
|
|
210
|
+
|
|
211
|
+
**Request:**
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"deviceId": "string"
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## License Data Structure
|
|
219
|
+
|
|
220
|
+
KV Key: `lic:<sha256(token)>`
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"status": "active",
|
|
225
|
+
"max_devices": 2,
|
|
226
|
+
"devices": ["device-id-1", "device-id-2"],
|
|
227
|
+
"lastSeen": "2024-01-01T00:00:00Z"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Rate Limiting
|
|
232
|
+
|
|
233
|
+
- 30 requests per minute per token
|
|
234
|
+
- Enforced in-memory (resets on worker restart)
|
|
235
|
+
- For production, use KV-based rate limiting
|
|
236
|
+
|
|
237
|
+
## Security Notes
|
|
238
|
+
|
|
239
|
+
- Tokens are hashed with SHA-256 before storage
|
|
240
|
+
- Signed URLs expire after 3 minutes
|
|
241
|
+
- Device IDs are stable per machine
|
|
242
|
+
- CORS enabled for CLI access
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
|
|
5
|
+
// Get token from command line or generate random
|
|
6
|
+
const token = process.argv[2] || `VF_${crypto.randomBytes(16).toString('hex')}`;
|
|
7
|
+
|
|
8
|
+
// Generate SHA-256 hash
|
|
9
|
+
const hash = crypto.createHash('sha256').update(token).digest('hex');
|
|
10
|
+
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log('🔑 VibeFast Token Generated');
|
|
13
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
14
|
+
console.log('');
|
|
15
|
+
console.log('Token: ', token);
|
|
16
|
+
console.log('Hash: ', hash);
|
|
17
|
+
console.log('KV Key: ', `lic:${hash}`);
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log('📋 Add to KV with:');
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(`wrangler kv:key put --binding=LICENSES "lic:${hash}" '{
|
|
22
|
+
"status": "active",
|
|
23
|
+
"max_devices": 2,
|
|
24
|
+
"devices": [],
|
|
25
|
+
"lastSeen": null
|
|
26
|
+
}' --preview false`);
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log('🧪 Test with CLI:');
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(`vf login --token ${token}`);
|
|
31
|
+
console.log('vf doctor');
|
|
32
|
+
console.log('');
|
|
Binary file
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
echo "🚀 VibeFast CLI Worker Setup"
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
# Check if wrangler is installed
|
|
8
|
+
if ! command -v wrangler &> /dev/null; then
|
|
9
|
+
echo "❌ Wrangler CLI not found. Installing..."
|
|
10
|
+
npm install -g wrangler
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
echo "✅ Wrangler CLI found"
|
|
14
|
+
echo ""
|
|
15
|
+
|
|
16
|
+
# Login check
|
|
17
|
+
echo "🔐 Checking Cloudflare authentication..."
|
|
18
|
+
if ! wrangler whoami &> /dev/null; then
|
|
19
|
+
echo "Please login to Cloudflare:"
|
|
20
|
+
wrangler login
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "✅ Authenticated"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
# Create KV namespace
|
|
27
|
+
echo "📦 Creating KV namespace for licenses..."
|
|
28
|
+
KV_OUTPUT=$(wrangler kv:namespace create "LICENSES" 2>&1)
|
|
29
|
+
KV_ID=$(echo "$KV_OUTPUT" | grep -o 'id = "[^"]*"' | cut -d'"' -f2)
|
|
30
|
+
|
|
31
|
+
if [ -z "$KV_ID" ]; then
|
|
32
|
+
echo "⚠️ KV namespace might already exist. Check wrangler.toml"
|
|
33
|
+
else
|
|
34
|
+
echo "✅ KV Namespace created: $KV_ID"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "📝 Update wrangler.toml with this ID:"
|
|
37
|
+
echo " id = \"$KV_ID\""
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
# Create R2 bucket
|
|
43
|
+
echo "🪣 Creating R2 bucket for recipes..."
|
|
44
|
+
if wrangler r2 bucket create vibefast-recipes 2>&1 | grep -q "already exists"; then
|
|
45
|
+
echo "✅ R2 bucket already exists"
|
|
46
|
+
else
|
|
47
|
+
echo "✅ R2 bucket created: vibefast-recipes"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo ""
|
|
51
|
+
|
|
52
|
+
# Generate test token
|
|
53
|
+
echo "🔑 Generating test token..."
|
|
54
|
+
TEST_TOKEN="TEST_TOKEN_12345"
|
|
55
|
+
TOKEN_HASH=$(echo -n "$TEST_TOKEN" | openssl dgst -sha256 -hex | awk '{print $2}')
|
|
56
|
+
|
|
57
|
+
echo "Token: $TEST_TOKEN"
|
|
58
|
+
echo "Hash: $TOKEN_HASH"
|
|
59
|
+
echo "KV Key: lic:$TOKEN_HASH"
|
|
60
|
+
echo ""
|
|
61
|
+
|
|
62
|
+
# Add test license to KV
|
|
63
|
+
echo "💾 Adding test license to KV..."
|
|
64
|
+
LICENSE_DATA='{
|
|
65
|
+
"status": "active",
|
|
66
|
+
"max_devices": 2,
|
|
67
|
+
"devices": [],
|
|
68
|
+
"lastSeen": null
|
|
69
|
+
}'
|
|
70
|
+
|
|
71
|
+
wrangler kv:key put --binding=LICENSES "lic:$TOKEN_HASH" "$LICENSE_DATA" --preview false
|
|
72
|
+
|
|
73
|
+
echo "✅ Test license added"
|
|
74
|
+
echo ""
|
|
75
|
+
|
|
76
|
+
# Create test recipe
|
|
77
|
+
echo "📦 Creating test recipe..."
|
|
78
|
+
mkdir -p test-recipe/apps/native/src/app/mini
|
|
79
|
+
cat > test-recipe/recipe.json << 'EOF'
|
|
80
|
+
{
|
|
81
|
+
"name": "mini-native",
|
|
82
|
+
"version": "0.1.0",
|
|
83
|
+
"description": "Demo feature (Expo)",
|
|
84
|
+
"copy": [
|
|
85
|
+
{
|
|
86
|
+
"from": "apps/native/src/app/mini",
|
|
87
|
+
"to": "apps/native/src/app/(root)/(protected)/mini"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"nav": {
|
|
91
|
+
"href": "/(root)/(protected)/mini",
|
|
92
|
+
"label": "Mini"
|
|
93
|
+
},
|
|
94
|
+
"target": "native"
|
|
95
|
+
}
|
|
96
|
+
EOF
|
|
97
|
+
|
|
98
|
+
cat > test-recipe/apps/native/src/app/mini/index.tsx << 'EOF'
|
|
99
|
+
import { View, Text } from 'react-native';
|
|
100
|
+
|
|
101
|
+
export default function MiniFeature() {
|
|
102
|
+
return (
|
|
103
|
+
<View className="flex-1 items-center justify-center">
|
|
104
|
+
<Text className="text-2xl font-bold">Mini Feature</Text>
|
|
105
|
+
<Text className="text-gray-600">Installed via VibeFast CLI</Text>
|
|
106
|
+
</View>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
EOF
|
|
110
|
+
|
|
111
|
+
cd test-recipe
|
|
112
|
+
zip -r ../mini-native@latest.zip . > /dev/null
|
|
113
|
+
cd ..
|
|
114
|
+
rm -rf test-recipe
|
|
115
|
+
|
|
116
|
+
echo "✅ Test recipe created: mini-native@latest.zip"
|
|
117
|
+
echo ""
|
|
118
|
+
|
|
119
|
+
# Upload to R2
|
|
120
|
+
echo "☁️ Uploading test recipe to R2..."
|
|
121
|
+
wrangler r2 object put vibefast-recipes/mini-native@latest.zip --file=mini-native@latest.zip
|
|
122
|
+
|
|
123
|
+
echo "✅ Recipe uploaded"
|
|
124
|
+
echo ""
|
|
125
|
+
|
|
126
|
+
# Deploy worker
|
|
127
|
+
echo "🚀 Deploying worker..."
|
|
128
|
+
wrangler deploy
|
|
129
|
+
|
|
130
|
+
echo ""
|
|
131
|
+
echo "✅ Setup complete!"
|
|
132
|
+
echo ""
|
|
133
|
+
echo "📋 Next steps:"
|
|
134
|
+
echo "1. Note your worker URL from the output above"
|
|
135
|
+
echo "2. Update CLI environment variable:"
|
|
136
|
+
echo " export VIBEFAST_WORKER_URL=https://YOUR_WORKER.workers.dev"
|
|
137
|
+
echo ""
|
|
138
|
+
echo "3. Test the CLI:"
|
|
139
|
+
echo " cd ../vibefast-monorepo"
|
|
140
|
+
echo " vf login --token $TEST_TOKEN"
|
|
141
|
+
echo " vf list"
|
|
142
|
+
echo " vf add mini-native"
|
|
143
|
+
echo ""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { View, Text } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export default function MiniFeature() {
|
|
4
|
+
return (
|
|
5
|
+
<View className="flex-1 items-center justify-center bg-background">
|
|
6
|
+
<Text className="text-3xl font-bold text-foreground">🎉 Mini Feature</Text>
|
|
7
|
+
<Text className="mt-4 text-lg text-muted-foreground">
|
|
8
|
+
Installed via VibeFast CLI
|
|
9
|
+
</Text>
|
|
10
|
+
<Text className="mt-2 text-sm text-muted-foreground">
|
|
11
|
+
This is a demo feature to test the CLI workflow
|
|
12
|
+
</Text>
|
|
13
|
+
</View>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mini-native",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Demo feature (Expo)",
|
|
5
|
+
"copy": [
|
|
6
|
+
{
|
|
7
|
+
"from": "apps/native/src/app/mini",
|
|
8
|
+
"to": "apps/native/src/app/(root)/(protected)/mini"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"nav": {
|
|
12
|
+
"href": "/(root)/(protected)/mini",
|
|
13
|
+
"label": "Mini"
|
|
14
|
+
},
|
|
15
|
+
"target": "native"
|
|
16
|
+
}
|