vibefast-cli 0.7.12 → 0.7.14
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/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +28 -2
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +5 -3
- package/dist/commands/init.js.map +1 -1
- package/package.json +1 -1
- package/recipes/audio-recorder/recipe.json +1 -1
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/{charts → (root)/(protected)/charts}/index.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/index.ts +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +0 -3
- package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +0 -3
- package/recipes/charts/apps/native/src/features/charts/types/index.ts +0 -3
- package/recipes/charts/recipe.json +1 -1
- package/recipes/charts@latest.zip +0 -0
- package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +83 -0
- package/recipes/chatbot/apps/native/src/app/{chatbot → (root)/(protected)/chatbot}/index.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/app/index.tsx +56 -60
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +3 -26
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +10 -14
- package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +0 -1
- package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +5 -3
- package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +0 -1
- package/recipes/chatbot/packages/backend/convex/agents.ts +3 -4
- package/recipes/chatbot/packages/backend/convex/chatbot/content.ts +35 -0
- package/recipes/chatbot/packages/backend/convex/chatbot/sessions.ts +52 -0
- package/recipes/chatbot/packages/backend/convex/chatbot/streaming.ts +422 -0
- package/recipes/chatbot/packages/backend/convex/chatbot/telemetry.ts +56 -0
- package/recipes/chatbot/packages/backend/convex/chatbot/tools.ts +128 -0
- package/recipes/chatbot/packages/backend/convex/chatbotAgent.ts +6 -651
- package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -714
- package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +12 -7
- package/recipes/chatbot/recipe.json +6 -1
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +34 -0
- package/recipes/image-generator/packages/backend/convex/{imageGeneratorFunctions.ts → imageGenerator.ts} +1 -1
- package/recipes/image-generator/recipe.json +5 -1
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/payments/apps/native/src/api-client/payments.ts +44 -0
- package/recipes/payments/packages/backend/convex/payments/index.ts +13 -0
- package/recipes/payments/packages/backend/convex/payments.ts +119 -0
- package/recipes/payments/recipe.json +15 -2
- package/recipes/payments@latest.zip +0 -0
- package/recipes/quiz/recipe.json +1 -1
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/tracker-app/recipe.json +1 -1
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/voice-bot/recipe.json +1 -1
- package/recipes/voice-bot@latest.zip +0 -0
- package/src/commands/add.ts +108 -70
- package/src/commands/init.ts +5 -3
- package/tmp-npm-cache/_update-notifier-last-checked +0 -0
- /package/recipes/audio-recorder/apps/native/src/app/{audio-recorder → (root)/(protected)/audio-recorder}/index.tsx +0 -0
- /package/recipes/image-generator/apps/native/src/app/{image-generator → (root)/(protected)/image-generator}/gallery.tsx +0 -0
- /package/recipes/image-generator/apps/native/src/app/{image-generator → (root)/(protected)/image-generator}/index.tsx +0 -0
- /package/recipes/quiz/apps/native/src/app/{quiz → (root)/(protected)/quiz}/index.tsx +0 -0
- /package/recipes/tracker-app/apps/native/src/app/{tracker-app → (root)/(protected)/tracker-app}/index.tsx +0 -0
- /package/recipes/voice-bot/apps/native/src/app/{voice-bot → (root)/(protected)/voice-bot}/index.tsx +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import { createTool } from '@convex-dev/agent';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
|
|
@@ -65,13 +66,16 @@ export const knowledgeRetrievalTool = createTool({
|
|
|
65
66
|
after: args.chunkContext?.after ?? 1,
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
const result = (await ctx.runAction(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
const result = (await (ctx as any).runAction(
|
|
70
|
+
(api as any).ragKnowledge.askKnowledge,
|
|
71
|
+
{
|
|
72
|
+
prompt,
|
|
73
|
+
globalNamespace: args.scope === 'global',
|
|
74
|
+
limit: args.limit,
|
|
75
|
+
chunkContext,
|
|
76
|
+
filter,
|
|
77
|
+
} as any,
|
|
78
|
+
)) as {
|
|
75
79
|
answer: string;
|
|
76
80
|
files?: { filename: string; url: string | null }[];
|
|
77
81
|
};
|
|
@@ -90,3 +94,4 @@ export const knowledgeRetrievalTool = createTool({
|
|
|
90
94
|
return `${result.answer}\n\n**References**\n${references}`;
|
|
91
95
|
},
|
|
92
96
|
});
|
|
97
|
+
// @ts-nocheck
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatbot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "AI-powered chat assistant",
|
|
5
5
|
"copy": [
|
|
6
6
|
{
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"from": "apps/native/src/features/chatbot",
|
|
12
12
|
"to": "apps/native/src/features/chatbot"
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
"from": "apps/native/src/api-client/chatbot.ts",
|
|
16
|
+
"to": "apps/native/src/api-client/chatbot.ts"
|
|
17
|
+
},
|
|
14
18
|
{
|
|
15
19
|
"from": "packages/backend/convex/chatbot",
|
|
16
20
|
"to": "packages/backend/convex/chatbot"
|
|
@@ -69,6 +73,7 @@
|
|
|
69
73
|
"expo-clipboard",
|
|
70
74
|
"markdown-it",
|
|
71
75
|
"react-native-markdown-display",
|
|
76
|
+
"react-native-syntax-highlighter",
|
|
72
77
|
"react-syntax-highlighter",
|
|
73
78
|
"react-native-reanimated",
|
|
74
79
|
"react-native-safe-area-context"
|
|
Binary file
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { api } from '@vibefast/backend/_generated/api';
|
|
2
|
+
import { useAction } from 'convex/react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Image Generator API Gateway
|
|
6
|
+
*
|
|
7
|
+
* This gateway provides typed wrappers around Convex image generation functions.
|
|
8
|
+
* It handles AI-powered image generation backed by the AI SDK providers.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* - Import this gateway in feature code: `import { imageGeneratorApi } from '@/platform/api/image-generator'`
|
|
12
|
+
* - Never import from `@vibefast/backend/_generated/api` directly in feature code
|
|
13
|
+
*/
|
|
14
|
+
export const imageGeneratorApi = {
|
|
15
|
+
/**
|
|
16
|
+
* Generate an image based on user prompt and provider selection
|
|
17
|
+
*
|
|
18
|
+
* @returns Promise with image data URI, mime type, and metadata
|
|
19
|
+
*/
|
|
20
|
+
useGenerateImage() {
|
|
21
|
+
const action = useAction(api['imageGeneration/index'].generateImageAction);
|
|
22
|
+
|
|
23
|
+
return (args: GenerateImageArgs) =>
|
|
24
|
+
action(args as Parameters<typeof action>[0]);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type ImageGeneratorApi = typeof imageGeneratorApi;
|
|
29
|
+
|
|
30
|
+
export type GenerateImageArgs = {
|
|
31
|
+
prompt: string;
|
|
32
|
+
provider: string;
|
|
33
|
+
model: string;
|
|
34
|
+
};
|
|
@@ -63,7 +63,7 @@ const generateWithOpenAI = async (prompt: string, model: string) => {
|
|
|
63
63
|
throw new Error('OpenAI image generation did not return any image data.');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const mimeType = imageResult.mimeType ?? 'image/png';
|
|
66
|
+
const mimeType = (imageResult as any).mimeType ?? 'image/png';
|
|
67
67
|
const base64Data =
|
|
68
68
|
imageResult.base64 ??
|
|
69
69
|
(imageResult.uint8Array
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-generator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "AI-powered image generation",
|
|
5
5
|
"copy": [
|
|
6
6
|
{
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"from": "apps/native/src/features/image-generator",
|
|
12
12
|
"to": "apps/native/src/features/image-generator"
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
"from": "apps/native/src/api-client/image-generator.ts",
|
|
16
|
+
"to": "apps/native/src/api-client/image-generator.ts"
|
|
17
|
+
},
|
|
14
18
|
{
|
|
15
19
|
"from": "packages/backend/convex/imageGeneration/index.ts",
|
|
16
20
|
"to": "packages/backend/convex/imageGeneration/index.ts"
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { api } from '@vibefast/backend/_generated/api';
|
|
2
|
+
import { useMutation, useQuery } from 'convex/react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Payments API Gateway
|
|
6
|
+
*
|
|
7
|
+
* This gateway provides typed wrappers around Convex payment functions.
|
|
8
|
+
* It handles RevenueCat purchases, credit management, and purchase history.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* - Import this gateway in feature code: `import { paymentsApi } from '@/platform/api/payments'`
|
|
12
|
+
* - Never import from `@vibefast/backend/_generated/api` directly in feature code
|
|
13
|
+
*/
|
|
14
|
+
export const paymentsApi = {
|
|
15
|
+
/**
|
|
16
|
+
* Record a consumable purchase (like credits) in the database
|
|
17
|
+
*/
|
|
18
|
+
useRecordConsumablePurchase() {
|
|
19
|
+
return useMutation(api['payments/index'].recordConsumablePurchase);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get user's current credit balance
|
|
24
|
+
*/
|
|
25
|
+
useGetUserCredits() {
|
|
26
|
+
return useQuery(api['payments/index'].getUserCredits);
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get user's purchase history with pagination
|
|
31
|
+
*/
|
|
32
|
+
useGetPurchaseHistory(
|
|
33
|
+
paginationOpts: { numItems: number; cursor: string | null } = {
|
|
34
|
+
numItems: 50,
|
|
35
|
+
cursor: null,
|
|
36
|
+
},
|
|
37
|
+
) {
|
|
38
|
+
return useQuery(api['payments/index'].getPurchaseHistory, {
|
|
39
|
+
paginationOpts,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type PaymentsApi = typeof paymentsApi;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payments Domain Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Single entry point for all payment-related Convex functions.
|
|
5
|
+
* Re-exports functions from payments.ts to decouple
|
|
6
|
+
* frontend from internal file structure.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
getPurchaseHistory,
|
|
11
|
+
getUserCredits,
|
|
12
|
+
recordConsumablePurchase,
|
|
13
|
+
} from '../payments';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { getAuthUserId } from '@convex-dev/auth/server';
|
|
2
|
+
import { v } from 'convex/values';
|
|
3
|
+
|
|
4
|
+
import { mutation, query } from './_generated/server';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Record a consumable purchase (like credits) in the database
|
|
8
|
+
*/
|
|
9
|
+
export const recordConsumablePurchase = mutation({
|
|
10
|
+
args: {
|
|
11
|
+
productId: v.string(),
|
|
12
|
+
quantity: v.number(),
|
|
13
|
+
},
|
|
14
|
+
returns: v.object({
|
|
15
|
+
success: v.boolean(),
|
|
16
|
+
newCredits: v.number(),
|
|
17
|
+
totalCredits: v.number(),
|
|
18
|
+
}),
|
|
19
|
+
handler: async (ctx, args) => {
|
|
20
|
+
const userId = await getAuthUserId(ctx);
|
|
21
|
+
if (!userId) {
|
|
22
|
+
throw new Error('Not authenticated');
|
|
23
|
+
}
|
|
24
|
+
// Get current user to check existing credits
|
|
25
|
+
const user = await ctx.db.get(userId);
|
|
26
|
+
if (!user) {
|
|
27
|
+
throw new Error('User not found');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Calculate new credits based on product
|
|
31
|
+
let creditsToAdd = args.quantity;
|
|
32
|
+
|
|
33
|
+
// You can customize credit amounts based on productId
|
|
34
|
+
if (args.productId.includes('premium')) {
|
|
35
|
+
creditsToAdd = args.quantity * 2; // Premium products give 2x credits
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Update user credits - safely access credits field
|
|
39
|
+
const currentCredits = (user as any).credits || 0;
|
|
40
|
+
const newTotalCredits = currentCredits + creditsToAdd;
|
|
41
|
+
|
|
42
|
+
await ctx.db.patch(userId, {
|
|
43
|
+
credits: newTotalCredits,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Log the purchase
|
|
47
|
+
await ctx.db.insert('purchases', {
|
|
48
|
+
userId,
|
|
49
|
+
productId: args.productId,
|
|
50
|
+
quantity: args.quantity,
|
|
51
|
+
creditsAdded: creditsToAdd,
|
|
52
|
+
purchaseDate: Date.now(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
newCredits: creditsToAdd,
|
|
58
|
+
totalCredits: newTotalCredits,
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get user's current credit balance
|
|
65
|
+
*/
|
|
66
|
+
export const getUserCredits = query({
|
|
67
|
+
args: {},
|
|
68
|
+
returns: v.union(v.number(), v.null()),
|
|
69
|
+
handler: async (ctx) => {
|
|
70
|
+
const userId = await getAuthUserId(ctx);
|
|
71
|
+
if (!userId) {
|
|
72
|
+
throw new Error('Not authenticated');
|
|
73
|
+
}
|
|
74
|
+
const user = await ctx.db.get(userId);
|
|
75
|
+
|
|
76
|
+
return (user as any)?.credits || 0;
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get user's purchase history with pagination
|
|
82
|
+
*/
|
|
83
|
+
export const getPurchaseHistory = query({
|
|
84
|
+
args: {
|
|
85
|
+
paginationOpts: v.optional(
|
|
86
|
+
v.object({
|
|
87
|
+
numItems: v.number(),
|
|
88
|
+
cursor: v.union(v.string(), v.null()),
|
|
89
|
+
}),
|
|
90
|
+
),
|
|
91
|
+
},
|
|
92
|
+
returns: v.object({
|
|
93
|
+
page: v.array(
|
|
94
|
+
v.object({
|
|
95
|
+
_id: v.id('purchases'),
|
|
96
|
+
_creationTime: v.number(),
|
|
97
|
+
productId: v.string(),
|
|
98
|
+
quantity: v.number(),
|
|
99
|
+
creditsAdded: v.number(),
|
|
100
|
+
purchaseDate: v.number(),
|
|
101
|
+
}),
|
|
102
|
+
),
|
|
103
|
+
isDone: v.boolean(),
|
|
104
|
+
continueCursor: v.string(),
|
|
105
|
+
pageStatus: v.optional(v.union(v.string(), v.null())),
|
|
106
|
+
splitCursor: v.optional(v.union(v.string(), v.null())),
|
|
107
|
+
}),
|
|
108
|
+
handler: async (ctx, args) => {
|
|
109
|
+
const userId = await getAuthUserId(ctx);
|
|
110
|
+
if (!userId) {
|
|
111
|
+
throw new Error('Not authenticated');
|
|
112
|
+
}
|
|
113
|
+
return await ctx.db
|
|
114
|
+
.query('purchases')
|
|
115
|
+
.withIndex('by_userId', (q) => q.eq('userId', userId))
|
|
116
|
+
.order('desc')
|
|
117
|
+
.paginate(args.paginationOpts ?? { numItems: 50, cursor: null });
|
|
118
|
+
},
|
|
119
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payments",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "In-app purchases and subscriptions with RevenueCat",
|
|
5
5
|
"copy": [
|
|
6
6
|
{
|
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
{
|
|
11
11
|
"from": "apps/native/src/features/payments",
|
|
12
12
|
"to": "apps/native/src/features/payments"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"from": "apps/native/src/api-client/payments.ts",
|
|
16
|
+
"to": "apps/native/src/api-client/payments.ts"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"from": "packages/backend/convex/payments",
|
|
20
|
+
"to": "packages/backend/convex/payments"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"from": "packages/backend/convex/payments.ts",
|
|
24
|
+
"to": "packages/backend/convex/payments.ts"
|
|
13
25
|
}
|
|
14
26
|
],
|
|
15
27
|
"nav": {
|
|
@@ -21,7 +33,8 @@
|
|
|
21
33
|
"target": "native",
|
|
22
34
|
"dependencies": {
|
|
23
35
|
"expo": [
|
|
24
|
-
"react-native-purchases"
|
|
36
|
+
"react-native-purchases",
|
|
37
|
+
"react-native-purchases-ui"
|
|
25
38
|
]
|
|
26
39
|
},
|
|
27
40
|
"env": [
|
|
Binary file
|
package/recipes/quiz/recipe.json
CHANGED
package/recipes/quiz@latest.zip
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/commands/add.ts
CHANGED
|
@@ -22,7 +22,8 @@ import {
|
|
|
22
22
|
ENV_CONSTANTS_END,
|
|
23
23
|
ENV_CONSTANTS_START,
|
|
24
24
|
} from '../core/codemod.js';
|
|
25
|
-
import { join, resolve } from 'path';
|
|
25
|
+
import { join, resolve, dirname } from 'path';
|
|
26
|
+
import { copyFile, mkdir } from 'fs/promises';
|
|
26
27
|
import { ensureWithinBase } from '../core/pathGuard.js';
|
|
27
28
|
import { extractZipSafe } from '../core/archive.js';
|
|
28
29
|
import { hashFiles } from '../core/hash.js';
|
|
@@ -259,6 +260,41 @@ function groupEnvVars(env: RecipeManifest['env'] | undefined, cwd: string): EnvG
|
|
|
259
260
|
return [...groups.values()];
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
async function ensureEnvFileFromExample(
|
|
264
|
+
group: EnvGroup,
|
|
265
|
+
options: any,
|
|
266
|
+
): Promise<boolean> {
|
|
267
|
+
if (await exists(group.path)) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const exampleCandidates = [
|
|
272
|
+
`${group.path}.example`,
|
|
273
|
+
join(dirname(group.path), '.env.example'),
|
|
274
|
+
];
|
|
275
|
+
const examplePath = (await Promise.all(
|
|
276
|
+
exampleCandidates.map(async (candidate) => ((await exists(candidate)) ? candidate : null)),
|
|
277
|
+
)).find(Boolean);
|
|
278
|
+
|
|
279
|
+
if (!examplePath) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const exampleLabel = examplePath.startsWith(dirname(group.path))
|
|
284
|
+
? examplePath.slice(dirname(group.path).length + 1)
|
|
285
|
+
: examplePath;
|
|
286
|
+
|
|
287
|
+
if (options?.dryRun) {
|
|
288
|
+
log.info(`[DRY RUN] Would create ${group.relativePath} from ${exampleLabel}`);
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
await mkdir(dirname(group.path), { recursive: true });
|
|
293
|
+
await copyFile(examplePath, group.path);
|
|
294
|
+
log.info(`Created ${group.relativePath} from ${exampleLabel}`);
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
|
|
262
298
|
async function ensureEnvVarsForGroups(
|
|
263
299
|
envGroups: EnvGroup[],
|
|
264
300
|
options: any,
|
|
@@ -266,6 +302,8 @@ async function ensureEnvVarsForGroups(
|
|
|
266
302
|
const summary: Array<{ relativePath: string; added: string[] }> = [];
|
|
267
303
|
|
|
268
304
|
for (const group of envGroups) {
|
|
305
|
+
await ensureEnvFileFromExample(group, options);
|
|
306
|
+
|
|
269
307
|
const vars: CoreEnvVar[] = group.vars.map(envVar => ({
|
|
270
308
|
key: envVar.key,
|
|
271
309
|
value: envVar.value ?? envVar.example ?? '',
|
|
@@ -457,84 +495,84 @@ async function applyEnvConfiguration(paths: ReturnType<typeof getPaths>, envConf
|
|
|
457
495
|
let zipPath: string | null = null;
|
|
458
496
|
let extractDir: string | null = null;
|
|
459
497
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
498
|
+
if (!response.ok || (!response.signedUrl && !response.zipData)) {
|
|
499
|
+
// Remote fetch failed; try bundled fallback
|
|
500
|
+
const error = response.error || 'Unknown error';
|
|
501
|
+
const message = response.message || '';
|
|
502
|
+
const localZip = await getBundledRecipeZipPath(feature);
|
|
465
503
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
log.plain('');
|
|
471
|
-
|
|
472
|
-
// User-friendly error messages
|
|
473
|
-
if (error.includes('Invalid') || error.includes('token') || error.includes('license')) {
|
|
474
|
-
log.plain('❌ Invalid or expired license key');
|
|
475
|
-
log.plain('');
|
|
476
|
-
log.info('Your license key may be:');
|
|
477
|
-
log.plain(' • Incorrect or mistyped');
|
|
478
|
-
log.plain(' • Expired');
|
|
479
|
-
log.plain(' • Revoked');
|
|
480
|
-
log.plain('');
|
|
481
|
-
log.info('To fix this:');
|
|
482
|
-
log.plain(' 1. Check your license key from your purchase receipt');
|
|
483
|
-
log.plain(' 2. Run: vf logout');
|
|
484
|
-
log.plain(' 3. Run: vf login --token YOUR_CORRECT_TOKEN');
|
|
485
|
-
log.plain('');
|
|
486
|
-
log.info('Need help? Contact support@vibefast.pro');
|
|
487
|
-
} else if (error.includes('Device limit') || error.includes('device') || message.includes('device')) {
|
|
488
|
-
log.plain('❌ Device limit reached');
|
|
489
|
-
log.plain('');
|
|
490
|
-
log.info('You have reached the maximum number of devices for your license');
|
|
491
|
-
log.plain('');
|
|
492
|
-
log.info('To fix this:');
|
|
493
|
-
log.plain(' 1. Run: vf devices');
|
|
494
|
-
log.plain(' 2. Deactivate an unused device: vf devices --deactivate <device-id>');
|
|
495
|
-
log.plain(' 3. Try again: vf add ' + feature);
|
|
504
|
+
if (localZip) {
|
|
505
|
+
log.info(`Remote recipe unavailable (${error}). Using bundled recipe.`);
|
|
506
|
+
zipPath = localZip;
|
|
507
|
+
} else {
|
|
496
508
|
log.plain('');
|
|
497
|
-
|
|
498
|
-
|
|
509
|
+
|
|
510
|
+
// User-friendly error messages
|
|
511
|
+
if (error.includes('Invalid') || error.includes('token') || error.includes('license')) {
|
|
512
|
+
log.plain('❌ Invalid or expired license key');
|
|
499
513
|
log.plain('');
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
log.info('Could not connect to VibeFast servers');
|
|
505
|
-
log.plain('');
|
|
506
|
-
log.info('Please check:');
|
|
507
|
-
log.plain(' • Your internet connection');
|
|
508
|
-
log.plain(' • Firewall settings');
|
|
509
|
-
log.plain(' • VPN configuration');
|
|
510
|
-
log.plain('');
|
|
511
|
-
if (message) {
|
|
512
|
-
log.plain(`Details: ${message}`);
|
|
514
|
+
log.info('Your license key may be:');
|
|
515
|
+
log.plain(' • Incorrect or mistyped');
|
|
516
|
+
log.plain(' • Expired');
|
|
517
|
+
log.plain(' • Revoked');
|
|
513
518
|
log.plain('');
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
519
|
+
log.info('To fix this:');
|
|
520
|
+
log.plain(' 1. Check your license key from your purchase receipt');
|
|
521
|
+
log.plain(' 2. Run: vf logout');
|
|
522
|
+
log.plain(' 3. Run: vf login --token YOUR_CORRECT_TOKEN');
|
|
523
|
+
log.plain('');
|
|
524
|
+
log.info('Need help? Contact support@vibefast.pro');
|
|
525
|
+
} else if (error.includes('Device limit') || error.includes('device') || message.includes('device')) {
|
|
526
|
+
log.plain('❌ Device limit reached');
|
|
527
|
+
log.plain('');
|
|
528
|
+
log.info('You have reached the maximum number of devices for your license');
|
|
529
|
+
log.plain('');
|
|
530
|
+
log.info('To fix this:');
|
|
531
|
+
log.plain(' 1. Run: vf devices');
|
|
532
|
+
log.plain(' 2. Deactivate an unused device: vf devices --deactivate <device-id>');
|
|
533
|
+
log.plain(' 3. Try again: vf add ' + feature);
|
|
534
|
+
log.plain('');
|
|
535
|
+
if (message) {
|
|
536
|
+
log.plain(`Details: ${message}`);
|
|
537
|
+
log.plain('');
|
|
538
|
+
}
|
|
539
|
+
} else if (error.includes('Network') || error.includes('connect')) {
|
|
540
|
+
log.plain('❌ Network error');
|
|
541
|
+
log.plain('');
|
|
542
|
+
log.info('Could not connect to VibeFast servers');
|
|
543
|
+
log.plain('');
|
|
544
|
+
log.info('Please check:');
|
|
545
|
+
log.plain(' • Your internet connection');
|
|
546
|
+
log.plain(' • Firewall settings');
|
|
547
|
+
log.plain(' • VPN configuration');
|
|
527
548
|
log.plain('');
|
|
528
|
-
|
|
549
|
+
if (message) {
|
|
550
|
+
log.plain(`Details: ${message}`);
|
|
551
|
+
log.plain('');
|
|
552
|
+
}
|
|
553
|
+
} else if (error.includes('not found') || error.includes('404')) {
|
|
554
|
+
log.plain('❌ Feature not found');
|
|
555
|
+
log.plain('');
|
|
556
|
+
log.info(`The feature "${feature}" does not exist or is not available for ${target}`);
|
|
557
|
+
log.plain('');
|
|
558
|
+
log.info('To see available features:');
|
|
559
|
+
log.plain(' vf list');
|
|
560
|
+
log.plain('');
|
|
561
|
+
} else {
|
|
562
|
+
// Generic error
|
|
563
|
+
log.plain(`❌ ${error}`);
|
|
564
|
+
if (message) {
|
|
565
|
+
log.plain('');
|
|
566
|
+
log.plain(`Details: ${message}`);
|
|
567
|
+
}
|
|
568
|
+
log.plain('');
|
|
569
|
+
log.info('If this problem persists, contact support@vibefast.pro');
|
|
529
570
|
}
|
|
571
|
+
|
|
530
572
|
log.plain('');
|
|
531
|
-
|
|
573
|
+
process.exit(1);
|
|
532
574
|
}
|
|
533
|
-
|
|
534
|
-
log.plain('');
|
|
535
|
-
process.exit(1);
|
|
536
575
|
}
|
|
537
|
-
}
|
|
538
576
|
|
|
539
577
|
const fallbackZip = await getBundledRecipeZipPath(feature);
|
|
540
578
|
let attemptedFallback = false;
|
package/src/commands/init.ts
CHANGED
|
@@ -448,7 +448,9 @@ export const initCommand = new Command('init')
|
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
// Step 6: Run starter setup script (optional)
|
|
451
|
-
const
|
|
451
|
+
const nativeSetupPath = join(projectPath, 'apps/native/scripts/starter-setup.mjs');
|
|
452
|
+
const rootSetupPath = join(projectPath, 'scripts/starter-setup.mjs');
|
|
453
|
+
const setupScriptPath = existsSync(rootSetupPath) ? rootSetupPath : nativeSetupPath;
|
|
452
454
|
|
|
453
455
|
if (platforms.includes('native') && existsSync(setupScriptPath)) {
|
|
454
456
|
log.info('📋 Starter Setup Available');
|
|
@@ -473,8 +475,8 @@ export const initCommand = new Command('init')
|
|
|
473
475
|
// Use spawn instead of execAsync for interactive scripts
|
|
474
476
|
const { spawn } = await import('child_process');
|
|
475
477
|
await new Promise<void>((resolve, reject) => {
|
|
476
|
-
const child = spawn('node', [
|
|
477
|
-
cwd:
|
|
478
|
+
const child = spawn('node', [setupScriptPath], {
|
|
479
|
+
cwd: projectPath,
|
|
478
480
|
stdio: 'inherit',
|
|
479
481
|
});
|
|
480
482
|
child.on('close', (code) => {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/recipes/voice-bot/apps/native/src/app/{voice-bot → (root)/(protected)/voice-bot}/index.tsx
RENAMED
|
File without changes
|