@cravery/core 0.0.21 → 0.0.22
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/lib/ai/embedding.d.ts +1 -1
- package/dist/lib/ai/embedding.d.ts.map +1 -1
- package/dist/lib/ai/embedding.js +12 -9
- package/dist/lib/ai/embedding.js.map +1 -1
- package/dist/lib/ai/genkit.d.ts +3 -3
- package/dist/lib/ai/genkit.d.ts.map +1 -1
- package/dist/lib/ai/genkit.js +12 -8
- package/dist/lib/ai/genkit.js.map +1 -1
- package/dist/types/core/settings.d.ts.map +1 -1
- package/dist/types/core/settings.js.map +1 -1
- package/dist/types/iam/user.d.ts.map +1 -1
- package/dist/types/iam/user.js.map +1 -1
- package/package.json +56 -56
- package/src/lib/ai/embedding.ts +15 -9
- package/src/lib/ai/flow.ts +89 -89
- package/src/lib/ai/genkit.ts +18 -12
- package/src/lib/api.ts +103 -103
- package/src/lib/utils/sanitize.ts +38 -38
- package/src/types/ai/recipe.ts +61 -61
- package/src/types/ai/translation.ts +27 -27
- package/src/types/core/asset.ts +17 -17
- package/src/types/core/enums/image_type.ts +5 -5
- package/src/types/core/enums/locale.ts +5 -5
- package/src/types/core/enums/measurement_system.ts +5 -5
- package/src/types/core/enums/theme.ts +5 -5
- package/src/types/core/enums/url_type.ts +13 -13
- package/src/types/core/settings.ts +68 -61
- package/src/types/iam/enums/profile_status.ts +10 -10
- package/src/types/iam/enums/subscription_role.ts +5 -5
- package/src/types/iam/enums/subscription_status.ts +10 -10
- package/src/types/iam/enums/subscription_tier.ts +4 -4
- package/src/types/iam/enums/user_role.ts +11 -11
- package/src/types/iam/enums/user_status.ts +10 -10
- package/src/types/iam/profile.ts +45 -45
- package/src/types/iam/subscription.ts +45 -45
- package/src/types/iam/user.ts +36 -31
- package/src/types/moderation/enums/moderation_status.ts +9 -9
- package/src/types/moderation/enums/priority.ts +5 -5
- package/src/types/moderation/enums/severity.ts +5 -5
- package/src/types/moderation/enums/suggestion_category.ts +11 -11
- package/src/types/moderation/moderation.ts +87 -87
- package/src/types/recipe/enums/allergen.ts +19 -19
- package/src/types/recipe/enums/cuisine.ts +39 -39
- package/src/types/recipe/enums/dietary_tag.ts +21 -21
- package/src/types/recipe/enums/difficulty.ts +10 -10
- package/src/types/recipe/enums/meal_type.ts +14 -14
- package/src/types/recipe/enums/recipe_source.ts +5 -5
- package/src/types/recipe/enums/recipe_status.ts +12 -12
- package/src/types/recipe/enums/spiciness.ts +5 -5
- package/src/types/recipe/enums/temperature_unit.ts +5 -5
- package/src/types/recipe/enums/unit.ts +51 -51
- package/src/types/recipe/equipment.ts +31 -31
- package/src/types/recipe/filters.ts +35 -35
- package/src/types/recipe/ingredient.ts +70 -70
- package/src/types/recipe/instruction.ts +31 -31
- package/src/types/recipe/nutrition.ts +29 -29
- package/src/types/recipe/recipe.ts +198 -198
- package/src/types/recipe/temperature.ts +12 -12
- package/src/types/report/enums/report_priority.ts +10 -10
- package/src/types/report/enums/report_status.ts +10 -10
- package/src/types/report/enums/report_target_type.ts +10 -10
- package/src/types/report/enums/report_type.ts +12 -12
- package/src/types/report/report.ts +68 -68
package/src/lib/api.ts
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
onCall,
|
|
3
|
-
HttpsError,
|
|
4
|
-
CallableRequest,
|
|
5
|
-
CallableOptions,
|
|
6
|
-
} from "firebase-functions/v2/https";
|
|
7
|
-
import { z } from "genkit";
|
|
8
|
-
import { isAdmin, isModeratorOrAbove, isTranslatorOrAbove } from "./iam";
|
|
9
|
-
|
|
10
|
-
const DEFAULT_OPTIONS: CallableOptions = { cors: true, enforceAppCheck: true };
|
|
11
|
-
|
|
12
|
-
const handleError = (error: unknown): never => {
|
|
13
|
-
if (error instanceof z.ZodError) {
|
|
14
|
-
throw new HttpsError(
|
|
15
|
-
"invalid-argument",
|
|
16
|
-
`Validation failed: ${error.message}`,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
if (error instanceof HttpsError) {
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
|
-
throw new HttpsError(
|
|
23
|
-
"internal",
|
|
24
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
class CallableBuilder<T> {
|
|
29
|
-
private requiresAuth = false;
|
|
30
|
-
private requiresAdmin = false;
|
|
31
|
-
private requiresModerator = false;
|
|
32
|
-
private requiresTranslator = false;
|
|
33
|
-
private options: CallableOptions = DEFAULT_OPTIONS;
|
|
34
|
-
|
|
35
|
-
constructor(private schema: z.ZodSchema<T>) {}
|
|
36
|
-
|
|
37
|
-
requireAdmin() {
|
|
38
|
-
this.requiresAuth = true;
|
|
39
|
-
this.requiresAdmin = true;
|
|
40
|
-
return this;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
requireUser() {
|
|
44
|
-
this.requiresAuth = true;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
requireModerator() {
|
|
49
|
-
this.requiresAuth = true;
|
|
50
|
-
this.requiresModerator = true;
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
requireTranslator() {
|
|
55
|
-
this.requiresAuth = true;
|
|
56
|
-
this.requiresTranslator = true;
|
|
57
|
-
return this;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
withOptions(options: CallableOptions) {
|
|
61
|
-
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
62
|
-
return this;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
handle<R>(handler: (data: T, request: CallableRequest) => Promise<R>) {
|
|
66
|
-
return onCall(this.options, async (request) => {
|
|
67
|
-
if (this.requiresAuth && !request.auth) {
|
|
68
|
-
throw new HttpsError("unauthenticated", "Authentication required");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (request.auth) {
|
|
72
|
-
const uid = request.auth.uid;
|
|
73
|
-
|
|
74
|
-
if (this.requiresAdmin && !(await isAdmin(uid))) {
|
|
75
|
-
throw new HttpsError("permission-denied", "Admin access required");
|
|
76
|
-
} else if (this.requiresModerator && !(await isModeratorOrAbove(uid))) {
|
|
77
|
-
throw new HttpsError(
|
|
78
|
-
"permission-denied",
|
|
79
|
-
"Moderator access required",
|
|
80
|
-
);
|
|
81
|
-
} else if (
|
|
82
|
-
this.requiresTranslator &&
|
|
83
|
-
!(await isTranslatorOrAbove(uid))
|
|
84
|
-
) {
|
|
85
|
-
throw new HttpsError(
|
|
86
|
-
"permission-denied",
|
|
87
|
-
"Translator access required",
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
const data = this.schema.parse(request.data);
|
|
94
|
-
return await handler(data, request);
|
|
95
|
-
} catch (error) {
|
|
96
|
-
throw handleError(error);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const callable = <T>(schema: z.ZodSchema<T>) =>
|
|
103
|
-
new CallableBuilder(schema);
|
|
1
|
+
import {
|
|
2
|
+
onCall,
|
|
3
|
+
HttpsError,
|
|
4
|
+
CallableRequest,
|
|
5
|
+
CallableOptions,
|
|
6
|
+
} from "firebase-functions/v2/https";
|
|
7
|
+
import { z } from "genkit";
|
|
8
|
+
import { isAdmin, isModeratorOrAbove, isTranslatorOrAbove } from "./iam";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_OPTIONS: CallableOptions = { cors: true, enforceAppCheck: true };
|
|
11
|
+
|
|
12
|
+
const handleError = (error: unknown): never => {
|
|
13
|
+
if (error instanceof z.ZodError) {
|
|
14
|
+
throw new HttpsError(
|
|
15
|
+
"invalid-argument",
|
|
16
|
+
`Validation failed: ${error.message}`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
if (error instanceof HttpsError) {
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
throw new HttpsError(
|
|
23
|
+
"internal",
|
|
24
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
class CallableBuilder<T> {
|
|
29
|
+
private requiresAuth = false;
|
|
30
|
+
private requiresAdmin = false;
|
|
31
|
+
private requiresModerator = false;
|
|
32
|
+
private requiresTranslator = false;
|
|
33
|
+
private options: CallableOptions = DEFAULT_OPTIONS;
|
|
34
|
+
|
|
35
|
+
constructor(private schema: z.ZodSchema<T>) {}
|
|
36
|
+
|
|
37
|
+
requireAdmin() {
|
|
38
|
+
this.requiresAuth = true;
|
|
39
|
+
this.requiresAdmin = true;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
requireUser() {
|
|
44
|
+
this.requiresAuth = true;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
requireModerator() {
|
|
49
|
+
this.requiresAuth = true;
|
|
50
|
+
this.requiresModerator = true;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
requireTranslator() {
|
|
55
|
+
this.requiresAuth = true;
|
|
56
|
+
this.requiresTranslator = true;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
withOptions(options: CallableOptions) {
|
|
61
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
handle<R>(handler: (data: T, request: CallableRequest) => Promise<R>) {
|
|
66
|
+
return onCall(this.options, async (request) => {
|
|
67
|
+
if (this.requiresAuth && !request.auth) {
|
|
68
|
+
throw new HttpsError("unauthenticated", "Authentication required");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (request.auth) {
|
|
72
|
+
const uid = request.auth.uid;
|
|
73
|
+
|
|
74
|
+
if (this.requiresAdmin && !(await isAdmin(uid))) {
|
|
75
|
+
throw new HttpsError("permission-denied", "Admin access required");
|
|
76
|
+
} else if (this.requiresModerator && !(await isModeratorOrAbove(uid))) {
|
|
77
|
+
throw new HttpsError(
|
|
78
|
+
"permission-denied",
|
|
79
|
+
"Moderator access required",
|
|
80
|
+
);
|
|
81
|
+
} else if (
|
|
82
|
+
this.requiresTranslator &&
|
|
83
|
+
!(await isTranslatorOrAbove(uid))
|
|
84
|
+
) {
|
|
85
|
+
throw new HttpsError(
|
|
86
|
+
"permission-denied",
|
|
87
|
+
"Translator access required",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const data = this.schema.parse(request.data);
|
|
94
|
+
return await handler(data, request);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw handleError(error);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const callable = <T>(schema: z.ZodSchema<T>) =>
|
|
103
|
+
new CallableBuilder(schema);
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Removes HTML tags and script content from a string.
|
|
5
|
-
* Use for text fields that should not contain HTML (descriptions, bios, etc.)
|
|
6
|
-
*/
|
|
7
|
-
export function sanitizeText(text: string): string {
|
|
8
|
-
return text
|
|
9
|
-
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
|
|
10
|
-
.replace(/<[^>]*>/g, "")
|
|
11
|
-
.trim();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Creates a Zod string schema that sanitizes HTML on transformation.
|
|
16
|
-
* Use in schemas where text input needs to be cleaned.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* const BioSchema = sanitizedString(z.string().max(280));
|
|
20
|
-
*/
|
|
21
|
-
export function sanitizedString<T extends z.ZodString>(schema: T) {
|
|
22
|
-
return schema.transform(sanitizeText);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Escapes HTML special characters to prevent XSS.
|
|
27
|
-
* Use when HTML needs to be displayed as text.
|
|
28
|
-
*/
|
|
29
|
-
export function escapeHtml(text: string): string {
|
|
30
|
-
const htmlEscapes: Record<string, string> = {
|
|
31
|
-
"&": "&",
|
|
32
|
-
"<": "<",
|
|
33
|
-
">": ">",
|
|
34
|
-
'"': """,
|
|
35
|
-
"'": "'",
|
|
36
|
-
};
|
|
37
|
-
return text.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
38
|
-
}
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Removes HTML tags and script content from a string.
|
|
5
|
+
* Use for text fields that should not contain HTML (descriptions, bios, etc.)
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeText(text: string): string {
|
|
8
|
+
return text
|
|
9
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
|
|
10
|
+
.replace(/<[^>]*>/g, "")
|
|
11
|
+
.trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates a Zod string schema that sanitizes HTML on transformation.
|
|
16
|
+
* Use in schemas where text input needs to be cleaned.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const BioSchema = sanitizedString(z.string().max(280));
|
|
20
|
+
*/
|
|
21
|
+
export function sanitizedString<T extends z.ZodString>(schema: T) {
|
|
22
|
+
return schema.transform(sanitizeText);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Escapes HTML special characters to prevent XSS.
|
|
27
|
+
* Use when HTML needs to be displayed as text.
|
|
28
|
+
*/
|
|
29
|
+
export function escapeHtml(text: string): string {
|
|
30
|
+
const htmlEscapes: Record<string, string> = {
|
|
31
|
+
"&": "&",
|
|
32
|
+
"<": "<",
|
|
33
|
+
">": ">",
|
|
34
|
+
'"': """,
|
|
35
|
+
"'": "'",
|
|
36
|
+
};
|
|
37
|
+
return text.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
38
|
+
}
|
package/src/types/ai/recipe.ts
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
import {
|
|
3
|
-
AllergenSchema,
|
|
4
|
-
CuisineSchema,
|
|
5
|
-
DietaryTagSchema,
|
|
6
|
-
DifficultySchema,
|
|
7
|
-
EquipmentSchema,
|
|
8
|
-
IngredientSectionSchema,
|
|
9
|
-
InstructionSchema,
|
|
10
|
-
MealTypeSchema,
|
|
11
|
-
NutritionSchema,
|
|
12
|
-
SpicinessSchema,
|
|
13
|
-
type Allergen,
|
|
14
|
-
type Cuisine,
|
|
15
|
-
type DietaryTag,
|
|
16
|
-
type Difficulty,
|
|
17
|
-
type Equipment,
|
|
18
|
-
type IngredientSection,
|
|
19
|
-
type Instruction,
|
|
20
|
-
type MealType,
|
|
21
|
-
type Nutrition,
|
|
22
|
-
type Spiciness,
|
|
23
|
-
} from "../recipe";
|
|
24
|
-
|
|
25
|
-
export interface AIRecipe {
|
|
26
|
-
allergens: Allergen[];
|
|
27
|
-
confidence: number;
|
|
28
|
-
cuisine: Cuisine;
|
|
29
|
-
description: string;
|
|
30
|
-
dietaryTags: DietaryTag[];
|
|
31
|
-
difficulty: Difficulty;
|
|
32
|
-
equipment?: Equipment[];
|
|
33
|
-
ingredientSections: IngredientSection[];
|
|
34
|
-
instructions: Instruction[];
|
|
35
|
-
mealTypes: MealType[];
|
|
36
|
-
nutrition?: Nutrition;
|
|
37
|
-
servings: number;
|
|
38
|
-
spiciness: Spiciness;
|
|
39
|
-
time: number;
|
|
40
|
-
tips?: string[];
|
|
41
|
-
title: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const AIRecipeSchema = z.object({
|
|
45
|
-
allergens: z.array(AllergenSchema),
|
|
46
|
-
confidence: z.number().min(0).max(1),
|
|
47
|
-
cuisine: CuisineSchema,
|
|
48
|
-
description: z.string().min(10).max(2000),
|
|
49
|
-
dietaryTags: z.array(DietaryTagSchema),
|
|
50
|
-
difficulty: DifficultySchema,
|
|
51
|
-
equipment: z.array(EquipmentSchema).max(20).optional(),
|
|
52
|
-
ingredientSections: z.array(IngredientSectionSchema).min(1).max(10),
|
|
53
|
-
instructions: z.array(InstructionSchema).min(1).max(50),
|
|
54
|
-
mealTypes: z.array(MealTypeSchema).min(1),
|
|
55
|
-
nutrition: NutritionSchema.optional(),
|
|
56
|
-
servings: z.number().int().min(1).max(100),
|
|
57
|
-
spiciness: SpicinessSchema,
|
|
58
|
-
time: z.number().int().min(1).max(1440),
|
|
59
|
-
tips: z.array(z.string().max(500)).max(10).optional(),
|
|
60
|
-
title: z.string().min(3).max(200),
|
|
61
|
-
}) satisfies z.ZodType<AIRecipe>;
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
import {
|
|
3
|
+
AllergenSchema,
|
|
4
|
+
CuisineSchema,
|
|
5
|
+
DietaryTagSchema,
|
|
6
|
+
DifficultySchema,
|
|
7
|
+
EquipmentSchema,
|
|
8
|
+
IngredientSectionSchema,
|
|
9
|
+
InstructionSchema,
|
|
10
|
+
MealTypeSchema,
|
|
11
|
+
NutritionSchema,
|
|
12
|
+
SpicinessSchema,
|
|
13
|
+
type Allergen,
|
|
14
|
+
type Cuisine,
|
|
15
|
+
type DietaryTag,
|
|
16
|
+
type Difficulty,
|
|
17
|
+
type Equipment,
|
|
18
|
+
type IngredientSection,
|
|
19
|
+
type Instruction,
|
|
20
|
+
type MealType,
|
|
21
|
+
type Nutrition,
|
|
22
|
+
type Spiciness,
|
|
23
|
+
} from "../recipe";
|
|
24
|
+
|
|
25
|
+
export interface AIRecipe {
|
|
26
|
+
allergens: Allergen[];
|
|
27
|
+
confidence: number;
|
|
28
|
+
cuisine: Cuisine;
|
|
29
|
+
description: string;
|
|
30
|
+
dietaryTags: DietaryTag[];
|
|
31
|
+
difficulty: Difficulty;
|
|
32
|
+
equipment?: Equipment[];
|
|
33
|
+
ingredientSections: IngredientSection[];
|
|
34
|
+
instructions: Instruction[];
|
|
35
|
+
mealTypes: MealType[];
|
|
36
|
+
nutrition?: Nutrition;
|
|
37
|
+
servings: number;
|
|
38
|
+
spiciness: Spiciness;
|
|
39
|
+
time: number;
|
|
40
|
+
tips?: string[];
|
|
41
|
+
title: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const AIRecipeSchema = z.object({
|
|
45
|
+
allergens: z.array(AllergenSchema),
|
|
46
|
+
confidence: z.number().min(0).max(1),
|
|
47
|
+
cuisine: CuisineSchema,
|
|
48
|
+
description: z.string().min(10).max(2000),
|
|
49
|
+
dietaryTags: z.array(DietaryTagSchema),
|
|
50
|
+
difficulty: DifficultySchema,
|
|
51
|
+
equipment: z.array(EquipmentSchema).max(20).optional(),
|
|
52
|
+
ingredientSections: z.array(IngredientSectionSchema).min(1).max(10),
|
|
53
|
+
instructions: z.array(InstructionSchema).min(1).max(50),
|
|
54
|
+
mealTypes: z.array(MealTypeSchema).min(1),
|
|
55
|
+
nutrition: NutritionSchema.optional(),
|
|
56
|
+
servings: z.number().int().min(1).max(100),
|
|
57
|
+
spiciness: SpicinessSchema,
|
|
58
|
+
time: z.number().int().min(1).max(1440),
|
|
59
|
+
tips: z.array(z.string().max(500)).max(10).optional(),
|
|
60
|
+
title: z.string().min(3).max(200),
|
|
61
|
+
}) satisfies z.ZodType<AIRecipe>;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
import {
|
|
3
|
-
EquipmentContentSchema,
|
|
4
|
-
IngredientSectionContentSchema,
|
|
5
|
-
InstructionContentSchema,
|
|
6
|
-
type EquipmentContent,
|
|
7
|
-
type IngredientSectionContent,
|
|
8
|
-
type InstructionContent,
|
|
9
|
-
} from "../recipe";
|
|
10
|
-
|
|
11
|
-
export interface AIRecipeTranslation {
|
|
12
|
-
description: string;
|
|
13
|
-
equipment?: EquipmentContent[];
|
|
14
|
-
ingredientSections: IngredientSectionContent[];
|
|
15
|
-
instructions: InstructionContent[];
|
|
16
|
-
tips?: string[];
|
|
17
|
-
title: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const AIRecipeTranslationSchema = z.object({
|
|
21
|
-
description: z.string().min(10).max(2000),
|
|
22
|
-
equipment: z.array(EquipmentContentSchema).optional(),
|
|
23
|
-
ingredientSections: z.array(IngredientSectionContentSchema).min(1),
|
|
24
|
-
instructions: z.array(InstructionContentSchema).min(1),
|
|
25
|
-
tips: z.array(z.string().max(500)).optional(),
|
|
26
|
-
title: z.string().min(3).max(200),
|
|
27
|
-
}) satisfies z.ZodType<AIRecipeTranslation>;
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
import {
|
|
3
|
+
EquipmentContentSchema,
|
|
4
|
+
IngredientSectionContentSchema,
|
|
5
|
+
InstructionContentSchema,
|
|
6
|
+
type EquipmentContent,
|
|
7
|
+
type IngredientSectionContent,
|
|
8
|
+
type InstructionContent,
|
|
9
|
+
} from "../recipe";
|
|
10
|
+
|
|
11
|
+
export interface AIRecipeTranslation {
|
|
12
|
+
description: string;
|
|
13
|
+
equipment?: EquipmentContent[];
|
|
14
|
+
ingredientSections: IngredientSectionContent[];
|
|
15
|
+
instructions: InstructionContent[];
|
|
16
|
+
tips?: string[];
|
|
17
|
+
title: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const AIRecipeTranslationSchema = z.object({
|
|
21
|
+
description: z.string().min(10).max(2000),
|
|
22
|
+
equipment: z.array(EquipmentContentSchema).optional(),
|
|
23
|
+
ingredientSections: z.array(IngredientSectionContentSchema).min(1),
|
|
24
|
+
instructions: z.array(InstructionContentSchema).min(1),
|
|
25
|
+
tips: z.array(z.string().max(500)).optional(),
|
|
26
|
+
title: z.string().min(3).max(200),
|
|
27
|
+
}) satisfies z.ZodType<AIRecipeTranslation>;
|
package/src/types/core/asset.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
import type { Timestamp } from "firebase-admin/firestore";
|
|
3
|
-
import { SLUG_REGEX } from "../../config";
|
|
4
|
-
|
|
5
|
-
export interface Asset {
|
|
6
|
-
createdAt: Timestamp;
|
|
7
|
-
id: string;
|
|
8
|
-
imageUrl?: string;
|
|
9
|
-
updatedAt: Timestamp;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const AssetSchema = z.object({
|
|
13
|
-
createdAt: z.custom<Timestamp>(),
|
|
14
|
-
id: z.string().regex(SLUG_REGEX),
|
|
15
|
-
imageUrl: z.string().optional(),
|
|
16
|
-
updatedAt: z.custom<Timestamp>(),
|
|
17
|
-
});
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
import type { Timestamp } from "firebase-admin/firestore";
|
|
3
|
+
import { SLUG_REGEX } from "../../config";
|
|
4
|
+
|
|
5
|
+
export interface Asset {
|
|
6
|
+
createdAt: Timestamp;
|
|
7
|
+
id: string;
|
|
8
|
+
imageUrl?: string;
|
|
9
|
+
updatedAt: Timestamp;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const AssetSchema = z.object({
|
|
13
|
+
createdAt: z.custom<Timestamp>(),
|
|
14
|
+
id: z.string().regex(SLUG_REGEX),
|
|
15
|
+
imageUrl: z.string().optional(),
|
|
16
|
+
updatedAt: z.custom<Timestamp>(),
|
|
17
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
export const IMAGE_TYPE_VALUES = ["recipe", "ingredients"] as const;
|
|
4
|
-
export const ImageTypeSchema = z.enum(IMAGE_TYPE_VALUES);
|
|
5
|
-
export type ImageType = z.infer<typeof ImageTypeSchema>;
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
export const IMAGE_TYPE_VALUES = ["recipe", "ingredients"] as const;
|
|
4
|
+
export const ImageTypeSchema = z.enum(IMAGE_TYPE_VALUES);
|
|
5
|
+
export type ImageType = z.infer<typeof ImageTypeSchema>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
export const LOCALE_VALUES = ["en", "ar", "es", "fr", "ru"] as const;
|
|
4
|
-
export const LocaleSchema = z.enum(LOCALE_VALUES);
|
|
5
|
-
export type Locale = (typeof LOCALE_VALUES)[number];
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
export const LOCALE_VALUES = ["en", "ar", "es", "fr", "ru"] as const;
|
|
4
|
+
export const LocaleSchema = z.enum(LOCALE_VALUES);
|
|
5
|
+
export type Locale = (typeof LOCALE_VALUES)[number];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
export const MEASUREMENT_SYSTEM_VALUES = ["metric", "imperial"] as const;
|
|
4
|
-
export const MeasurementSystemSchema = z.enum(MEASUREMENT_SYSTEM_VALUES);
|
|
5
|
-
export type MeasurementSystem = (typeof MEASUREMENT_SYSTEM_VALUES)[number];
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
export const MEASUREMENT_SYSTEM_VALUES = ["metric", "imperial"] as const;
|
|
4
|
+
export const MeasurementSystemSchema = z.enum(MEASUREMENT_SYSTEM_VALUES);
|
|
5
|
+
export type MeasurementSystem = (typeof MEASUREMENT_SYSTEM_VALUES)[number];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
export const THEME_VALUES = ["light", "dark", "system"] as const;
|
|
4
|
-
export const ThemeSchema = z.enum(THEME_VALUES);
|
|
5
|
-
export type Theme = (typeof THEME_VALUES)[number];
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
export const THEME_VALUES = ["light", "dark", "system"] as const;
|
|
4
|
+
export const ThemeSchema = z.enum(THEME_VALUES);
|
|
5
|
+
export type Theme = (typeof THEME_VALUES)[number];
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { z } from "genkit";
|
|
2
|
-
|
|
3
|
-
export const URL_TYPE_VALUES = [
|
|
4
|
-
"facebook",
|
|
5
|
-
"instagram",
|
|
6
|
-
"pdf",
|
|
7
|
-
"pinterest",
|
|
8
|
-
"tiktok",
|
|
9
|
-
"website",
|
|
10
|
-
"youtube",
|
|
11
|
-
] as const;
|
|
12
|
-
export const UrlTypeSchema = z.enum(URL_TYPE_VALUES);
|
|
13
|
-
export type UrlType = z.infer<typeof UrlTypeSchema>;
|
|
1
|
+
import { z } from "genkit";
|
|
2
|
+
|
|
3
|
+
export const URL_TYPE_VALUES = [
|
|
4
|
+
"facebook",
|
|
5
|
+
"instagram",
|
|
6
|
+
"pdf",
|
|
7
|
+
"pinterest",
|
|
8
|
+
"tiktok",
|
|
9
|
+
"website",
|
|
10
|
+
"youtube",
|
|
11
|
+
] as const;
|
|
12
|
+
export const UrlTypeSchema = z.enum(URL_TYPE_VALUES);
|
|
13
|
+
export type UrlType = z.infer<typeof UrlTypeSchema>;
|