soustack 0.4.0 → 0.4.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/README.md +4 -4
- package/dist/cli/index.js +4412 -1275
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +106 -80
- package/dist/index.d.ts +106 -80
- package/dist/index.js +4527 -1360
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4527 -1360
- package/dist/index.mjs.map +1 -1
- package/dist/scrape/index.d.mts +86 -74
- package/dist/scrape/index.d.ts +86 -74
- package/dist/scrape/index.js +91 -64
- package/dist/scrape/index.js.map +1 -1
- package/dist/scrape/index.mjs +91 -64
- package/dist/scrape/index.mjs.map +1 -1
- package/package.json +15 -6
- package/spec/.sync-meta.json +149 -0
- package/spec/SOUSTACK_SPEC_VERSION +1 -0
- package/spec/defs/common.schema.json +46 -0
- package/spec/defs/duration.schema.json +33 -0
- package/spec/defs/entities.schema.json +111 -0
- package/spec/defs/ingredientQuantified.schema.json +9 -0
- package/spec/defs/quantity.schema.json +16 -0
- package/spec/defs/scalingRule.schema.json +127 -0
- package/spec/defs/temperature.schema.json +63 -0
- package/spec/fixtures/content/illustrated-step.valid.json +24 -0
- package/spec/fixtures/invalid/equipment-unknown-reference.invalid.json +38 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-equipment.invalid.json +37 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-input.invalid.json +41 -0
- package/spec/fixtures/invalid/storage-leftovers-missing-method.invalid.json +31 -0
- package/spec/fixtures/invalid/storage-leftovers-wrong-type.invalid.json +23 -0
- package/spec/fixtures/level/base-full.valid.json +162 -0
- package/spec/fixtures/level/base-missing-yield.invalid.json +12 -0
- package/spec/fixtures/level/lite-min.valid.json +14 -0
- package/spec/fixtures/profile/profile-base.valid.json +20 -0
- package/spec/fixtures/profile/profile-equipped.valid.json +28 -0
- package/spec/fixtures/profile/profile-illustrated.valid.json +28 -0
- package/spec/fixtures/profile/profile-lite.valid.json +13 -0
- package/spec/fixtures/profile/profile-prepped.valid.json +31 -0
- package/spec/fixtures/profile/profile-scalable-missing-scaling.invalid.json +29 -0
- package/spec/fixtures/profile/profile-scalable.valid.json +49 -0
- package/spec/fixtures/profile/profile-timed-missing-structured.invalid.json +30 -0
- package/spec/fixtures/scaling/bakers-percent-missing-ref.invalid.json +41 -0
- package/spec/fixtures/scaling/bakers-percent.valid.json +51 -0
- package/spec/fixtures/scaling/discrete-range.invalid.json +36 -0
- package/spec/fixtures/scaling/missing-quantified.invalid.json +40 -0
- package/spec/fixtures/scaling/reject-bakersPercentage.invalid.json +50 -0
- package/spec/fixtures/stacks/compute-missing-timed.invalid.json +32 -0
- package/spec/fixtures/stacks/dietary-no-signal.invalid.json +16 -0
- package/spec/fixtures/stacks/illustrated-empty.invalid.json +13 -0
- package/spec/fixtures/stacks/quantified-string.invalid.json +22 -0
- package/spec/fixtures/stacks/referenced-missing-input.invalid.json +32 -0
- package/spec/fixtures/stacks/storage-min.valid.json +20 -0
- package/spec/fixtures/stacks/storage-no-duration.invalid.json +16 -0
- package/spec/fixtures/stacks/timed-implies-structured.valid.json +50 -0
- package/spec/fixtures/stacks/timed-range.invalid.json +33 -0
- package/spec/fixtures/valid/equipment-scaling-rules.valid.json +76 -0
- package/spec/fixtures/valid/equipment-strings.valid.json +31 -0
- package/spec/fixtures/valid/equipment-structured-uses.valid.json +47 -0
- package/spec/fixtures/valid/mise-en-place-basic.valid.json +31 -0
- package/spec/fixtures/valid/mise-en-place-referenced-equipment.valid.json +51 -0
- package/spec/fixtures/valid/prep-ingredient-strings.valid.json +48 -0
- package/spec/fixtures/valid/prep-ingredient-structured.valid.json +45 -0
- package/spec/fixtures/valid/profile-equipped.valid.json +29 -0
- package/spec/fixtures/valid/profile-prepped.valid.json +32 -0
- package/spec/fixtures/valid/quantified-nested-ingredient-sections.valid.json +61 -0
- package/spec/fixtures/valid/referenced-scaling.valid.json +67 -0
- package/spec/fixtures/valid/storage-leftovers-simple.valid.json +27 -0
- package/spec/fixtures/valid/storage-leftovers-structured.valid.json +43 -0
- package/spec/fixtures/valid/structured-nested-step-sections.valid.json +84 -0
- package/spec/schemas/stacks-registry.schema.json +108 -0
- package/spec/soustack.schema.json +2379 -0
- package/spec/stacks/compute.schema.json +7 -0
- package/spec/stacks/compute@1.md +22 -0
- package/spec/stacks/dietary.schema.json +45 -0
- package/spec/stacks/dietary@1.md +24 -0
- package/spec/stacks/equipment.schema.json +98 -0
- package/spec/stacks/equipment@1.md +244 -0
- package/spec/stacks/illustrated.schema.json +54 -0
- package/spec/stacks/illustrated@1.md +24 -0
- package/spec/stacks/prep.schema.json +76 -0
- package/spec/stacks/prep@1.md +276 -0
- package/spec/stacks/quantified.schema.json +74 -0
- package/spec/stacks/quantified@1.md +24 -0
- package/spec/stacks/referenced.schema.json +96 -0
- package/spec/stacks/referenced@1.md +23 -0
- package/spec/stacks/registry.json +112 -0
- package/spec/stacks/scaling.schema.json +99 -0
- package/spec/stacks/scaling@1.md +238 -0
- package/spec/stacks/storage.schema.json +132 -0
- package/spec/stacks/storage@1.md +256 -0
- package/spec/stacks/structured.schema.json +48 -0
- package/spec/stacks/structured@1.md +24 -0
- package/spec/stacks/substitutions.schema.json +43 -0
- package/spec/stacks/substitutions@1.md +24 -0
- package/spec/stacks/techniques.schema.json +28 -0
- package/spec/stacks/techniques@1.md +23 -0
- package/spec/stacks/timed.schema.json +60 -0
- package/spec/stacks/timed@1.md +23 -0
- package/src/defs/common.schema.json +46 -0
- package/src/defs/duration.schema.json +33 -0
- package/src/defs/entities.schema.json +111 -0
- package/src/defs/ingredientQuantified.schema.json +9 -0
- package/src/defs/quantity.schema.json +16 -0
- package/src/defs/scalingRule.schema.json +127 -0
- package/src/defs/temperature.schema.json +63 -0
- package/src/profiles/base.schema.json +2 -2
- package/src/profiles/equipped.schema.json +10 -0
- package/src/profiles/illustrated.schema.json +4 -4
- package/src/profiles/lite.schema.json +10 -0
- package/src/profiles/prepped.schema.json +10 -0
- package/src/profiles/scalable.schema.json +6 -6
- package/src/profiles/timed.schema.json +10 -0
- package/src/schema.json +2271 -248
- package/src/schemas/stacks-registry.schema.json +108 -0
- package/src/soustack.schema.json +2271 -248
- package/src/stacks/compute.schema.json +7 -0
- package/src/stacks/compute@1.md +22 -0
- package/src/stacks/dietary.schema.json +45 -0
- package/src/stacks/dietary@1.md +24 -0
- package/src/stacks/equipment.schema.json +98 -0
- package/src/stacks/equipment@1.md +244 -0
- package/src/stacks/illustrated.schema.json +54 -0
- package/src/stacks/illustrated@1.md +24 -0
- package/src/stacks/prep.schema.json +76 -0
- package/src/stacks/prep@1.md +276 -0
- package/src/stacks/quantified.schema.json +74 -0
- package/src/stacks/quantified@1.md +24 -0
- package/src/stacks/referenced.schema.json +96 -0
- package/src/stacks/referenced@1.md +23 -0
- package/src/stacks/registry.json +112 -0
- package/src/stacks/scaling.schema.json +99 -0
- package/src/stacks/scaling@1.md +238 -0
- package/src/stacks/storage.schema.json +132 -0
- package/src/stacks/storage@1.md +256 -0
- package/src/stacks/structured.schema.json +48 -0
- package/src/stacks/structured@1.md +24 -0
- package/src/stacks/substitutions.schema.json +43 -0
- package/src/stacks/substitutions@1.md +24 -0
- package/src/stacks/techniques.schema.json +28 -0
- package/src/stacks/techniques@1.md +23 -0
- package/src/stacks/timed.schema.json +60 -0
- package/src/stacks/timed@1.md +23 -0
- package/src/profiles/cookable.schema.json +0 -18
- package/src/profiles/quantified.schema.json +0 -43
- package/src/profiles/schedulable.schema.json +0 -43
package/dist/scrape/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Soustack Recipe Schema v0.
|
|
2
|
+
* Soustack Recipe Schema v0.0.2
|
|
3
3
|
* A portable, scalable, interoperable recipe format.
|
|
4
4
|
*/
|
|
5
5
|
interface SoustackRecipe {
|
|
@@ -7,20 +7,10 @@ interface SoustackRecipe {
|
|
|
7
7
|
'@type'?: 'Recipe';
|
|
8
8
|
/** Optional $schema pointer for profile-aware validation */
|
|
9
9
|
$schema?: string;
|
|
10
|
-
/** Optional declared validation profile */
|
|
11
|
-
profile?:
|
|
12
|
-
/** Recipe level: "lite" or "base" */
|
|
13
|
-
level?: "lite" | "base";
|
|
10
|
+
/** Optional declared validation profile (vNext only) */
|
|
11
|
+
profile?: "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed";
|
|
14
12
|
/** Stack declarations as a map: Record<stackName, versionNumber> */
|
|
15
13
|
stacks?: Record<string, number>;
|
|
16
|
-
/** Attribution stack payload */
|
|
17
|
-
attribution?: AttributionModule;
|
|
18
|
-
/** Taxonomy stack payload */
|
|
19
|
-
taxonomy?: TaxonomyModule;
|
|
20
|
-
/** Media stack payload */
|
|
21
|
-
media?: MediaModule;
|
|
22
|
-
/** Times stack payload */
|
|
23
|
-
times?: TimesModule;
|
|
24
14
|
/** Unique identifier (slug or UUID) */
|
|
25
15
|
id?: string;
|
|
26
16
|
/** Optional display title */
|
|
@@ -37,6 +27,10 @@ interface SoustackRecipe {
|
|
|
37
27
|
/** Additional tags for filtering */
|
|
38
28
|
tags?: string[];
|
|
39
29
|
/** URL(s) to recipe image(s) */
|
|
30
|
+
images?: string[];
|
|
31
|
+
/** URL(s) to recipe video(s) */
|
|
32
|
+
videos?: string[];
|
|
33
|
+
/** Legacy image field preserved for compatibility */
|
|
40
34
|
image?: string | string[];
|
|
41
35
|
/** ISO 8601 date string */
|
|
42
36
|
dateAdded?: string;
|
|
@@ -68,19 +62,18 @@ interface Yield {
|
|
|
68
62
|
description?: string;
|
|
69
63
|
}
|
|
70
64
|
/**
|
|
71
|
-
* Time
|
|
72
|
-
*
|
|
65
|
+
* Time uses DurationMinutes format (vNext).
|
|
66
|
+
* Required total field with minutes.
|
|
73
67
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
cookTime?: string;
|
|
68
|
+
interface Time {
|
|
69
|
+
total: DurationMinutes;
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
[k: `x-${string}`]: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface DurationMinutes {
|
|
74
|
+
minutes: number;
|
|
75
|
+
metadata?: Record<string, unknown>;
|
|
76
|
+
[k: `x-${string}`]: unknown;
|
|
84
77
|
}
|
|
85
78
|
interface Equipment {
|
|
86
79
|
id?: string;
|
|
@@ -90,87 +83,119 @@ interface Equipment {
|
|
|
90
83
|
capacity?: Quantity;
|
|
91
84
|
scalingLimit?: number;
|
|
92
85
|
alternatives?: string[];
|
|
86
|
+
count?: number;
|
|
87
|
+
countScaling?: EquipmentCountScaling;
|
|
88
|
+
upgrades?: EquipmentUpgradeRule[];
|
|
93
89
|
}
|
|
94
90
|
interface Quantity {
|
|
95
91
|
amount: number;
|
|
96
92
|
/** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
|
|
97
93
|
unit: string | null;
|
|
98
94
|
}
|
|
95
|
+
type EquipmentCountScaling = 'fixed' | 'linear' | EquipmentThresholdScaling;
|
|
96
|
+
interface EquipmentThresholdScaling {
|
|
97
|
+
mode: 'threshold';
|
|
98
|
+
steps: EquipmentThresholdStep[];
|
|
99
|
+
}
|
|
100
|
+
interface EquipmentThresholdStep {
|
|
101
|
+
maxFactor: number;
|
|
102
|
+
count: number;
|
|
103
|
+
}
|
|
104
|
+
interface EquipmentUpgradeRule {
|
|
105
|
+
minFactor: number;
|
|
106
|
+
use: string;
|
|
107
|
+
}
|
|
99
108
|
type IngredientItem = string | Ingredient | IngredientSubsection;
|
|
100
109
|
interface IngredientSubsection {
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
section: string;
|
|
111
|
+
ingredients: IngredientItem[];
|
|
103
112
|
}
|
|
104
113
|
interface Ingredient {
|
|
105
114
|
id?: string;
|
|
106
|
-
/**
|
|
107
|
-
|
|
115
|
+
/** Ingredient name (required in vNext) */
|
|
116
|
+
name: string;
|
|
108
117
|
quantity?: Quantity;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/** Required prep state (e.g. "diced") */
|
|
112
|
-
prep?: string;
|
|
113
|
-
prepAction?: string;
|
|
114
|
-
prepTime?: number;
|
|
118
|
+
/** Required prep state (e.g. "diced") or array of prep items */
|
|
119
|
+
prep?: string | string[];
|
|
115
120
|
/** ID of equipment where this ingredient goes */
|
|
116
121
|
destination?: string;
|
|
117
122
|
scaling?: Scaling;
|
|
118
|
-
critical?: boolean;
|
|
119
123
|
optional?: boolean;
|
|
120
124
|
notes?: string;
|
|
125
|
+
temperature?: Temperature;
|
|
126
|
+
metadata?: Record<string, unknown>;
|
|
127
|
+
[k: `x-${string}`]: unknown;
|
|
121
128
|
}
|
|
122
129
|
/**
|
|
123
|
-
* Intelligent Scaling Logic
|
|
130
|
+
* Intelligent Scaling Logic (vNext format)
|
|
124
131
|
* Defines how an ingredient behaves when the recipe yield changes.
|
|
125
132
|
*/
|
|
126
|
-
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingBakersPercentage;
|
|
133
|
+
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingToTaste | ScalingBakersPercentage;
|
|
127
134
|
interface ScalingBase {
|
|
128
135
|
min?: number;
|
|
129
136
|
max?: number;
|
|
130
137
|
}
|
|
131
138
|
interface ScalingLinear extends ScalingBase {
|
|
132
|
-
|
|
139
|
+
mode: "linear";
|
|
133
140
|
}
|
|
134
141
|
interface ScalingDiscrete extends ScalingBase {
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
mode: "discrete";
|
|
143
|
+
step?: number;
|
|
144
|
+
rounding?: "nearest" | "ceil" | "floor";
|
|
137
145
|
}
|
|
138
146
|
interface ScalingProportional extends ScalingBase {
|
|
139
|
-
|
|
147
|
+
mode: "proportional";
|
|
140
148
|
factor?: number;
|
|
141
149
|
}
|
|
142
150
|
interface ScalingFixed extends ScalingBase {
|
|
143
|
-
|
|
151
|
+
mode: "fixed";
|
|
152
|
+
}
|
|
153
|
+
interface ScalingToTaste {
|
|
154
|
+
mode: "toTaste";
|
|
144
155
|
}
|
|
145
|
-
interface ScalingBakersPercentage
|
|
146
|
-
|
|
156
|
+
interface ScalingBakersPercentage {
|
|
157
|
+
mode: "bakersPercent";
|
|
158
|
+
/** The percentage relative to the reference (e.g. 2 for 2%) */
|
|
159
|
+
percent: number;
|
|
147
160
|
/** The ID of the flour/base ingredient this is relative to */
|
|
148
|
-
|
|
149
|
-
/** The percentage relative to the reference (e.g. 0.02 for 2%) */
|
|
150
|
-
factor?: number;
|
|
161
|
+
of: string;
|
|
151
162
|
}
|
|
152
163
|
type InstructionItem = string | Instruction | InstructionSubsection;
|
|
153
164
|
interface InstructionSubsection {
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
section: string;
|
|
166
|
+
steps: InstructionItem[];
|
|
156
167
|
}
|
|
157
168
|
interface SoustackInstruction {
|
|
158
169
|
id?: string;
|
|
159
170
|
text: string;
|
|
160
|
-
destination?: string;
|
|
161
171
|
/** IDs of steps that must complete before this one starts */
|
|
162
172
|
dependsOn?: string[];
|
|
163
173
|
/** IDs of ingredients used in this step */
|
|
164
174
|
inputs?: string[];
|
|
175
|
+
/** IDs of techniques used in this step */
|
|
176
|
+
techniqueIds?: string[];
|
|
177
|
+
/** IDs of equipment used in this step */
|
|
178
|
+
usesEquipment?: string[];
|
|
165
179
|
timing?: StepTiming;
|
|
166
|
-
|
|
167
|
-
|
|
180
|
+
temperature?: Temperature;
|
|
181
|
+
images?: string[];
|
|
182
|
+
videos?: string[];
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
[k: `x-${string}`]: unknown;
|
|
168
185
|
}
|
|
169
186
|
type Instruction = SoustackInstruction;
|
|
170
187
|
interface StepTiming {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
188
|
+
activity: "active" | "passive";
|
|
189
|
+
duration?: DurationMinutes | DurationRange;
|
|
190
|
+
completionCue?: string;
|
|
191
|
+
metadata?: Record<string, unknown>;
|
|
192
|
+
[k: `x-${string}`]: unknown;
|
|
193
|
+
}
|
|
194
|
+
interface DurationRange {
|
|
195
|
+
minMinutes: number;
|
|
196
|
+
maxMinutes: number;
|
|
197
|
+
metadata?: Record<string, unknown>;
|
|
198
|
+
[k: `x-${string}`]: unknown;
|
|
174
199
|
}
|
|
175
200
|
interface Storage {
|
|
176
201
|
roomTemp?: StorageMethod;
|
|
@@ -209,24 +234,11 @@ interface NutritionFacts {
|
|
|
209
234
|
calories?: number;
|
|
210
235
|
protein_g?: number;
|
|
211
236
|
}
|
|
212
|
-
interface
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
interface TaxonomyModule {
|
|
218
|
-
keywords?: string[];
|
|
219
|
-
category?: string;
|
|
220
|
-
cuisine?: string;
|
|
221
|
-
}
|
|
222
|
-
interface MediaModule {
|
|
223
|
-
images?: string[];
|
|
224
|
-
videos?: string[];
|
|
225
|
-
}
|
|
226
|
-
interface TimesModule {
|
|
227
|
-
prepMinutes?: number;
|
|
228
|
-
cookMinutes?: number;
|
|
229
|
-
totalMinutes?: number;
|
|
237
|
+
interface Temperature {
|
|
238
|
+
value: number;
|
|
239
|
+
unit: "celsius" | "fahrenheit";
|
|
240
|
+
metadata?: Record<string, unknown>;
|
|
241
|
+
[k: `x-${string}`]: unknown;
|
|
230
242
|
}
|
|
231
243
|
|
|
232
244
|
interface HowToStep {
|
package/dist/scrape/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Soustack Recipe Schema v0.
|
|
2
|
+
* Soustack Recipe Schema v0.0.2
|
|
3
3
|
* A portable, scalable, interoperable recipe format.
|
|
4
4
|
*/
|
|
5
5
|
interface SoustackRecipe {
|
|
@@ -7,20 +7,10 @@ interface SoustackRecipe {
|
|
|
7
7
|
'@type'?: 'Recipe';
|
|
8
8
|
/** Optional $schema pointer for profile-aware validation */
|
|
9
9
|
$schema?: string;
|
|
10
|
-
/** Optional declared validation profile */
|
|
11
|
-
profile?:
|
|
12
|
-
/** Recipe level: "lite" or "base" */
|
|
13
|
-
level?: "lite" | "base";
|
|
10
|
+
/** Optional declared validation profile (vNext only) */
|
|
11
|
+
profile?: "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed";
|
|
14
12
|
/** Stack declarations as a map: Record<stackName, versionNumber> */
|
|
15
13
|
stacks?: Record<string, number>;
|
|
16
|
-
/** Attribution stack payload */
|
|
17
|
-
attribution?: AttributionModule;
|
|
18
|
-
/** Taxonomy stack payload */
|
|
19
|
-
taxonomy?: TaxonomyModule;
|
|
20
|
-
/** Media stack payload */
|
|
21
|
-
media?: MediaModule;
|
|
22
|
-
/** Times stack payload */
|
|
23
|
-
times?: TimesModule;
|
|
24
14
|
/** Unique identifier (slug or UUID) */
|
|
25
15
|
id?: string;
|
|
26
16
|
/** Optional display title */
|
|
@@ -37,6 +27,10 @@ interface SoustackRecipe {
|
|
|
37
27
|
/** Additional tags for filtering */
|
|
38
28
|
tags?: string[];
|
|
39
29
|
/** URL(s) to recipe image(s) */
|
|
30
|
+
images?: string[];
|
|
31
|
+
/** URL(s) to recipe video(s) */
|
|
32
|
+
videos?: string[];
|
|
33
|
+
/** Legacy image field preserved for compatibility */
|
|
40
34
|
image?: string | string[];
|
|
41
35
|
/** ISO 8601 date string */
|
|
42
36
|
dateAdded?: string;
|
|
@@ -68,19 +62,18 @@ interface Yield {
|
|
|
68
62
|
description?: string;
|
|
69
63
|
}
|
|
70
64
|
/**
|
|
71
|
-
* Time
|
|
72
|
-
*
|
|
65
|
+
* Time uses DurationMinutes format (vNext).
|
|
66
|
+
* Required total field with minutes.
|
|
73
67
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
cookTime?: string;
|
|
68
|
+
interface Time {
|
|
69
|
+
total: DurationMinutes;
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
[k: `x-${string}`]: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface DurationMinutes {
|
|
74
|
+
minutes: number;
|
|
75
|
+
metadata?: Record<string, unknown>;
|
|
76
|
+
[k: `x-${string}`]: unknown;
|
|
84
77
|
}
|
|
85
78
|
interface Equipment {
|
|
86
79
|
id?: string;
|
|
@@ -90,87 +83,119 @@ interface Equipment {
|
|
|
90
83
|
capacity?: Quantity;
|
|
91
84
|
scalingLimit?: number;
|
|
92
85
|
alternatives?: string[];
|
|
86
|
+
count?: number;
|
|
87
|
+
countScaling?: EquipmentCountScaling;
|
|
88
|
+
upgrades?: EquipmentUpgradeRule[];
|
|
93
89
|
}
|
|
94
90
|
interface Quantity {
|
|
95
91
|
amount: number;
|
|
96
92
|
/** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
|
|
97
93
|
unit: string | null;
|
|
98
94
|
}
|
|
95
|
+
type EquipmentCountScaling = 'fixed' | 'linear' | EquipmentThresholdScaling;
|
|
96
|
+
interface EquipmentThresholdScaling {
|
|
97
|
+
mode: 'threshold';
|
|
98
|
+
steps: EquipmentThresholdStep[];
|
|
99
|
+
}
|
|
100
|
+
interface EquipmentThresholdStep {
|
|
101
|
+
maxFactor: number;
|
|
102
|
+
count: number;
|
|
103
|
+
}
|
|
104
|
+
interface EquipmentUpgradeRule {
|
|
105
|
+
minFactor: number;
|
|
106
|
+
use: string;
|
|
107
|
+
}
|
|
99
108
|
type IngredientItem = string | Ingredient | IngredientSubsection;
|
|
100
109
|
interface IngredientSubsection {
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
section: string;
|
|
111
|
+
ingredients: IngredientItem[];
|
|
103
112
|
}
|
|
104
113
|
interface Ingredient {
|
|
105
114
|
id?: string;
|
|
106
|
-
/**
|
|
107
|
-
|
|
115
|
+
/** Ingredient name (required in vNext) */
|
|
116
|
+
name: string;
|
|
108
117
|
quantity?: Quantity;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/** Required prep state (e.g. "diced") */
|
|
112
|
-
prep?: string;
|
|
113
|
-
prepAction?: string;
|
|
114
|
-
prepTime?: number;
|
|
118
|
+
/** Required prep state (e.g. "diced") or array of prep items */
|
|
119
|
+
prep?: string | string[];
|
|
115
120
|
/** ID of equipment where this ingredient goes */
|
|
116
121
|
destination?: string;
|
|
117
122
|
scaling?: Scaling;
|
|
118
|
-
critical?: boolean;
|
|
119
123
|
optional?: boolean;
|
|
120
124
|
notes?: string;
|
|
125
|
+
temperature?: Temperature;
|
|
126
|
+
metadata?: Record<string, unknown>;
|
|
127
|
+
[k: `x-${string}`]: unknown;
|
|
121
128
|
}
|
|
122
129
|
/**
|
|
123
|
-
* Intelligent Scaling Logic
|
|
130
|
+
* Intelligent Scaling Logic (vNext format)
|
|
124
131
|
* Defines how an ingredient behaves when the recipe yield changes.
|
|
125
132
|
*/
|
|
126
|
-
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingBakersPercentage;
|
|
133
|
+
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingToTaste | ScalingBakersPercentage;
|
|
127
134
|
interface ScalingBase {
|
|
128
135
|
min?: number;
|
|
129
136
|
max?: number;
|
|
130
137
|
}
|
|
131
138
|
interface ScalingLinear extends ScalingBase {
|
|
132
|
-
|
|
139
|
+
mode: "linear";
|
|
133
140
|
}
|
|
134
141
|
interface ScalingDiscrete extends ScalingBase {
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
mode: "discrete";
|
|
143
|
+
step?: number;
|
|
144
|
+
rounding?: "nearest" | "ceil" | "floor";
|
|
137
145
|
}
|
|
138
146
|
interface ScalingProportional extends ScalingBase {
|
|
139
|
-
|
|
147
|
+
mode: "proportional";
|
|
140
148
|
factor?: number;
|
|
141
149
|
}
|
|
142
150
|
interface ScalingFixed extends ScalingBase {
|
|
143
|
-
|
|
151
|
+
mode: "fixed";
|
|
152
|
+
}
|
|
153
|
+
interface ScalingToTaste {
|
|
154
|
+
mode: "toTaste";
|
|
144
155
|
}
|
|
145
|
-
interface ScalingBakersPercentage
|
|
146
|
-
|
|
156
|
+
interface ScalingBakersPercentage {
|
|
157
|
+
mode: "bakersPercent";
|
|
158
|
+
/** The percentage relative to the reference (e.g. 2 for 2%) */
|
|
159
|
+
percent: number;
|
|
147
160
|
/** The ID of the flour/base ingredient this is relative to */
|
|
148
|
-
|
|
149
|
-
/** The percentage relative to the reference (e.g. 0.02 for 2%) */
|
|
150
|
-
factor?: number;
|
|
161
|
+
of: string;
|
|
151
162
|
}
|
|
152
163
|
type InstructionItem = string | Instruction | InstructionSubsection;
|
|
153
164
|
interface InstructionSubsection {
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
section: string;
|
|
166
|
+
steps: InstructionItem[];
|
|
156
167
|
}
|
|
157
168
|
interface SoustackInstruction {
|
|
158
169
|
id?: string;
|
|
159
170
|
text: string;
|
|
160
|
-
destination?: string;
|
|
161
171
|
/** IDs of steps that must complete before this one starts */
|
|
162
172
|
dependsOn?: string[];
|
|
163
173
|
/** IDs of ingredients used in this step */
|
|
164
174
|
inputs?: string[];
|
|
175
|
+
/** IDs of techniques used in this step */
|
|
176
|
+
techniqueIds?: string[];
|
|
177
|
+
/** IDs of equipment used in this step */
|
|
178
|
+
usesEquipment?: string[];
|
|
165
179
|
timing?: StepTiming;
|
|
166
|
-
|
|
167
|
-
|
|
180
|
+
temperature?: Temperature;
|
|
181
|
+
images?: string[];
|
|
182
|
+
videos?: string[];
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
[k: `x-${string}`]: unknown;
|
|
168
185
|
}
|
|
169
186
|
type Instruction = SoustackInstruction;
|
|
170
187
|
interface StepTiming {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
188
|
+
activity: "active" | "passive";
|
|
189
|
+
duration?: DurationMinutes | DurationRange;
|
|
190
|
+
completionCue?: string;
|
|
191
|
+
metadata?: Record<string, unknown>;
|
|
192
|
+
[k: `x-${string}`]: unknown;
|
|
193
|
+
}
|
|
194
|
+
interface DurationRange {
|
|
195
|
+
minMinutes: number;
|
|
196
|
+
maxMinutes: number;
|
|
197
|
+
metadata?: Record<string, unknown>;
|
|
198
|
+
[k: `x-${string}`]: unknown;
|
|
174
199
|
}
|
|
175
200
|
interface Storage {
|
|
176
201
|
roomTemp?: StorageMethod;
|
|
@@ -209,24 +234,11 @@ interface NutritionFacts {
|
|
|
209
234
|
calories?: number;
|
|
210
235
|
protein_g?: number;
|
|
211
236
|
}
|
|
212
|
-
interface
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
interface TaxonomyModule {
|
|
218
|
-
keywords?: string[];
|
|
219
|
-
category?: string;
|
|
220
|
-
cuisine?: string;
|
|
221
|
-
}
|
|
222
|
-
interface MediaModule {
|
|
223
|
-
images?: string[];
|
|
224
|
-
videos?: string[];
|
|
225
|
-
}
|
|
226
|
-
interface TimesModule {
|
|
227
|
-
prepMinutes?: number;
|
|
228
|
-
cookMinutes?: number;
|
|
229
|
-
totalMinutes?: number;
|
|
237
|
+
interface Temperature {
|
|
238
|
+
value: number;
|
|
239
|
+
unit: "celsius" | "fahrenheit";
|
|
240
|
+
metadata?: Record<string, unknown>;
|
|
241
|
+
[k: `x-${string}`]: unknown;
|
|
230
242
|
}
|
|
231
243
|
|
|
232
244
|
interface HowToStep {
|