soustack 0.3.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 +44 -27
- package/dist/cli/index.js +5225 -992
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +163 -91
- package/dist/index.d.ts +163 -91
- package/dist/index.js +5077 -1007
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5076 -1007
- package/dist/index.mjs.map +1 -1
- package/dist/{scrape.d.mts → scrape/index.d.mts} +88 -74
- package/dist/{scrape.d.ts → scrape/index.d.ts} +88 -74
- package/dist/{scrape.js → scrape/index.js} +255 -124
- package/dist/scrape/index.js.map +1 -0
- package/dist/{scrape.mjs → scrape/index.mjs} +255 -124
- package/dist/scrape/index.mjs.map +1 -0
- package/package.json +21 -9
- 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/dist/scrape.js.map +0 -1
- package/dist/scrape.mjs.map +0 -1
- package/src/profiles/cookable.schema.json +0 -18
- package/src/profiles/quantified.schema.json +0 -43
- package/src/profiles/schedulable.schema.json +0 -43
|
@@ -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,18 +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
|
-
/**
|
|
13
|
-
|
|
14
|
-
/** Attribution module payload */
|
|
15
|
-
attribution?: AttributionModule;
|
|
16
|
-
/** Taxonomy module payload */
|
|
17
|
-
taxonomy?: TaxonomyModule;
|
|
18
|
-
/** Media module payload */
|
|
19
|
-
media?: MediaModule;
|
|
20
|
-
/** Times module payload */
|
|
21
|
-
times?: TimesModule;
|
|
10
|
+
/** Optional declared validation profile (vNext only) */
|
|
11
|
+
profile?: "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed";
|
|
12
|
+
/** Stack declarations as a map: Record<stackName, versionNumber> */
|
|
13
|
+
stacks?: Record<string, number>;
|
|
22
14
|
/** Unique identifier (slug or UUID) */
|
|
23
15
|
id?: string;
|
|
24
16
|
/** Optional display title */
|
|
@@ -35,6 +27,10 @@ interface SoustackRecipe {
|
|
|
35
27
|
/** Additional tags for filtering */
|
|
36
28
|
tags?: string[];
|
|
37
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 */
|
|
38
34
|
image?: string | string[];
|
|
39
35
|
/** ISO 8601 date string */
|
|
40
36
|
dateAdded?: string;
|
|
@@ -66,19 +62,18 @@ interface Yield {
|
|
|
66
62
|
description?: string;
|
|
67
63
|
}
|
|
68
64
|
/**
|
|
69
|
-
* Time
|
|
70
|
-
*
|
|
65
|
+
* Time uses DurationMinutes format (vNext).
|
|
66
|
+
* Required total field with minutes.
|
|
71
67
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
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;
|
|
82
77
|
}
|
|
83
78
|
interface Equipment {
|
|
84
79
|
id?: string;
|
|
@@ -88,87 +83,119 @@ interface Equipment {
|
|
|
88
83
|
capacity?: Quantity;
|
|
89
84
|
scalingLimit?: number;
|
|
90
85
|
alternatives?: string[];
|
|
86
|
+
count?: number;
|
|
87
|
+
countScaling?: EquipmentCountScaling;
|
|
88
|
+
upgrades?: EquipmentUpgradeRule[];
|
|
91
89
|
}
|
|
92
90
|
interface Quantity {
|
|
93
91
|
amount: number;
|
|
94
92
|
/** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
|
|
95
93
|
unit: string | null;
|
|
96
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
|
+
}
|
|
97
108
|
type IngredientItem = string | Ingredient | IngredientSubsection;
|
|
98
109
|
interface IngredientSubsection {
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
section: string;
|
|
111
|
+
ingredients: IngredientItem[];
|
|
101
112
|
}
|
|
102
113
|
interface Ingredient {
|
|
103
114
|
id?: string;
|
|
104
|
-
/**
|
|
105
|
-
|
|
115
|
+
/** Ingredient name (required in vNext) */
|
|
116
|
+
name: string;
|
|
106
117
|
quantity?: Quantity;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/** Required prep state (e.g. "diced") */
|
|
110
|
-
prep?: string;
|
|
111
|
-
prepAction?: string;
|
|
112
|
-
prepTime?: number;
|
|
118
|
+
/** Required prep state (e.g. "diced") or array of prep items */
|
|
119
|
+
prep?: string | string[];
|
|
113
120
|
/** ID of equipment where this ingredient goes */
|
|
114
121
|
destination?: string;
|
|
115
122
|
scaling?: Scaling;
|
|
116
|
-
critical?: boolean;
|
|
117
123
|
optional?: boolean;
|
|
118
124
|
notes?: string;
|
|
125
|
+
temperature?: Temperature;
|
|
126
|
+
metadata?: Record<string, unknown>;
|
|
127
|
+
[k: `x-${string}`]: unknown;
|
|
119
128
|
}
|
|
120
129
|
/**
|
|
121
|
-
* Intelligent Scaling Logic
|
|
130
|
+
* Intelligent Scaling Logic (vNext format)
|
|
122
131
|
* Defines how an ingredient behaves when the recipe yield changes.
|
|
123
132
|
*/
|
|
124
|
-
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingBakersPercentage;
|
|
133
|
+
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingToTaste | ScalingBakersPercentage;
|
|
125
134
|
interface ScalingBase {
|
|
126
135
|
min?: number;
|
|
127
136
|
max?: number;
|
|
128
137
|
}
|
|
129
138
|
interface ScalingLinear extends ScalingBase {
|
|
130
|
-
|
|
139
|
+
mode: "linear";
|
|
131
140
|
}
|
|
132
141
|
interface ScalingDiscrete extends ScalingBase {
|
|
133
|
-
|
|
134
|
-
|
|
142
|
+
mode: "discrete";
|
|
143
|
+
step?: number;
|
|
144
|
+
rounding?: "nearest" | "ceil" | "floor";
|
|
135
145
|
}
|
|
136
146
|
interface ScalingProportional extends ScalingBase {
|
|
137
|
-
|
|
147
|
+
mode: "proportional";
|
|
138
148
|
factor?: number;
|
|
139
149
|
}
|
|
140
150
|
interface ScalingFixed extends ScalingBase {
|
|
141
|
-
|
|
151
|
+
mode: "fixed";
|
|
152
|
+
}
|
|
153
|
+
interface ScalingToTaste {
|
|
154
|
+
mode: "toTaste";
|
|
142
155
|
}
|
|
143
|
-
interface ScalingBakersPercentage
|
|
144
|
-
|
|
156
|
+
interface ScalingBakersPercentage {
|
|
157
|
+
mode: "bakersPercent";
|
|
158
|
+
/** The percentage relative to the reference (e.g. 2 for 2%) */
|
|
159
|
+
percent: number;
|
|
145
160
|
/** The ID of the flour/base ingredient this is relative to */
|
|
146
|
-
|
|
147
|
-
/** The percentage relative to the reference (e.g. 0.02 for 2%) */
|
|
148
|
-
factor?: number;
|
|
161
|
+
of: string;
|
|
149
162
|
}
|
|
150
163
|
type InstructionItem = string | Instruction | InstructionSubsection;
|
|
151
164
|
interface InstructionSubsection {
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
section: string;
|
|
166
|
+
steps: InstructionItem[];
|
|
154
167
|
}
|
|
155
168
|
interface SoustackInstruction {
|
|
156
169
|
id?: string;
|
|
157
170
|
text: string;
|
|
158
|
-
destination?: string;
|
|
159
171
|
/** IDs of steps that must complete before this one starts */
|
|
160
172
|
dependsOn?: string[];
|
|
161
173
|
/** IDs of ingredients used in this step */
|
|
162
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[];
|
|
163
179
|
timing?: StepTiming;
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
temperature?: Temperature;
|
|
181
|
+
images?: string[];
|
|
182
|
+
videos?: string[];
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
[k: `x-${string}`]: unknown;
|
|
166
185
|
}
|
|
167
186
|
type Instruction = SoustackInstruction;
|
|
168
187
|
interface StepTiming {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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;
|
|
172
199
|
}
|
|
173
200
|
interface Storage {
|
|
174
201
|
roomTemp?: StorageMethod;
|
|
@@ -207,24 +234,11 @@ interface NutritionFacts {
|
|
|
207
234
|
calories?: number;
|
|
208
235
|
protein_g?: number;
|
|
209
236
|
}
|
|
210
|
-
interface
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
interface TaxonomyModule {
|
|
216
|
-
keywords?: string[];
|
|
217
|
-
category?: string;
|
|
218
|
-
cuisine?: string;
|
|
219
|
-
}
|
|
220
|
-
interface MediaModule {
|
|
221
|
-
images?: string[];
|
|
222
|
-
videos?: string[];
|
|
223
|
-
}
|
|
224
|
-
interface TimesModule {
|
|
225
|
-
prepMinutes?: number;
|
|
226
|
-
cookMinutes?: number;
|
|
227
|
-
totalMinutes?: number;
|
|
237
|
+
interface Temperature {
|
|
238
|
+
value: number;
|
|
239
|
+
unit: "celsius" | "fahrenheit";
|
|
240
|
+
metadata?: Record<string, unknown>;
|
|
241
|
+
[k: `x-${string}`]: unknown;
|
|
228
242
|
}
|
|
229
243
|
|
|
230
244
|
interface HowToStep {
|
|
@@ -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,18 +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
|
-
/**
|
|
13
|
-
|
|
14
|
-
/** Attribution module payload */
|
|
15
|
-
attribution?: AttributionModule;
|
|
16
|
-
/** Taxonomy module payload */
|
|
17
|
-
taxonomy?: TaxonomyModule;
|
|
18
|
-
/** Media module payload */
|
|
19
|
-
media?: MediaModule;
|
|
20
|
-
/** Times module payload */
|
|
21
|
-
times?: TimesModule;
|
|
10
|
+
/** Optional declared validation profile (vNext only) */
|
|
11
|
+
profile?: "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed";
|
|
12
|
+
/** Stack declarations as a map: Record<stackName, versionNumber> */
|
|
13
|
+
stacks?: Record<string, number>;
|
|
22
14
|
/** Unique identifier (slug or UUID) */
|
|
23
15
|
id?: string;
|
|
24
16
|
/** Optional display title */
|
|
@@ -35,6 +27,10 @@ interface SoustackRecipe {
|
|
|
35
27
|
/** Additional tags for filtering */
|
|
36
28
|
tags?: string[];
|
|
37
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 */
|
|
38
34
|
image?: string | string[];
|
|
39
35
|
/** ISO 8601 date string */
|
|
40
36
|
dateAdded?: string;
|
|
@@ -66,19 +62,18 @@ interface Yield {
|
|
|
66
62
|
description?: string;
|
|
67
63
|
}
|
|
68
64
|
/**
|
|
69
|
-
* Time
|
|
70
|
-
*
|
|
65
|
+
* Time uses DurationMinutes format (vNext).
|
|
66
|
+
* Required total field with minutes.
|
|
71
67
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
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;
|
|
82
77
|
}
|
|
83
78
|
interface Equipment {
|
|
84
79
|
id?: string;
|
|
@@ -88,87 +83,119 @@ interface Equipment {
|
|
|
88
83
|
capacity?: Quantity;
|
|
89
84
|
scalingLimit?: number;
|
|
90
85
|
alternatives?: string[];
|
|
86
|
+
count?: number;
|
|
87
|
+
countScaling?: EquipmentCountScaling;
|
|
88
|
+
upgrades?: EquipmentUpgradeRule[];
|
|
91
89
|
}
|
|
92
90
|
interface Quantity {
|
|
93
91
|
amount: number;
|
|
94
92
|
/** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
|
|
95
93
|
unit: string | null;
|
|
96
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
|
+
}
|
|
97
108
|
type IngredientItem = string | Ingredient | IngredientSubsection;
|
|
98
109
|
interface IngredientSubsection {
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
section: string;
|
|
111
|
+
ingredients: IngredientItem[];
|
|
101
112
|
}
|
|
102
113
|
interface Ingredient {
|
|
103
114
|
id?: string;
|
|
104
|
-
/**
|
|
105
|
-
|
|
115
|
+
/** Ingredient name (required in vNext) */
|
|
116
|
+
name: string;
|
|
106
117
|
quantity?: Quantity;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/** Required prep state (e.g. "diced") */
|
|
110
|
-
prep?: string;
|
|
111
|
-
prepAction?: string;
|
|
112
|
-
prepTime?: number;
|
|
118
|
+
/** Required prep state (e.g. "diced") or array of prep items */
|
|
119
|
+
prep?: string | string[];
|
|
113
120
|
/** ID of equipment where this ingredient goes */
|
|
114
121
|
destination?: string;
|
|
115
122
|
scaling?: Scaling;
|
|
116
|
-
critical?: boolean;
|
|
117
123
|
optional?: boolean;
|
|
118
124
|
notes?: string;
|
|
125
|
+
temperature?: Temperature;
|
|
126
|
+
metadata?: Record<string, unknown>;
|
|
127
|
+
[k: `x-${string}`]: unknown;
|
|
119
128
|
}
|
|
120
129
|
/**
|
|
121
|
-
* Intelligent Scaling Logic
|
|
130
|
+
* Intelligent Scaling Logic (vNext format)
|
|
122
131
|
* Defines how an ingredient behaves when the recipe yield changes.
|
|
123
132
|
*/
|
|
124
|
-
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingBakersPercentage;
|
|
133
|
+
type Scaling = ScalingLinear | ScalingDiscrete | ScalingProportional | ScalingFixed | ScalingToTaste | ScalingBakersPercentage;
|
|
125
134
|
interface ScalingBase {
|
|
126
135
|
min?: number;
|
|
127
136
|
max?: number;
|
|
128
137
|
}
|
|
129
138
|
interface ScalingLinear extends ScalingBase {
|
|
130
|
-
|
|
139
|
+
mode: "linear";
|
|
131
140
|
}
|
|
132
141
|
interface ScalingDiscrete extends ScalingBase {
|
|
133
|
-
|
|
134
|
-
|
|
142
|
+
mode: "discrete";
|
|
143
|
+
step?: number;
|
|
144
|
+
rounding?: "nearest" | "ceil" | "floor";
|
|
135
145
|
}
|
|
136
146
|
interface ScalingProportional extends ScalingBase {
|
|
137
|
-
|
|
147
|
+
mode: "proportional";
|
|
138
148
|
factor?: number;
|
|
139
149
|
}
|
|
140
150
|
interface ScalingFixed extends ScalingBase {
|
|
141
|
-
|
|
151
|
+
mode: "fixed";
|
|
152
|
+
}
|
|
153
|
+
interface ScalingToTaste {
|
|
154
|
+
mode: "toTaste";
|
|
142
155
|
}
|
|
143
|
-
interface ScalingBakersPercentage
|
|
144
|
-
|
|
156
|
+
interface ScalingBakersPercentage {
|
|
157
|
+
mode: "bakersPercent";
|
|
158
|
+
/** The percentage relative to the reference (e.g. 2 for 2%) */
|
|
159
|
+
percent: number;
|
|
145
160
|
/** The ID of the flour/base ingredient this is relative to */
|
|
146
|
-
|
|
147
|
-
/** The percentage relative to the reference (e.g. 0.02 for 2%) */
|
|
148
|
-
factor?: number;
|
|
161
|
+
of: string;
|
|
149
162
|
}
|
|
150
163
|
type InstructionItem = string | Instruction | InstructionSubsection;
|
|
151
164
|
interface InstructionSubsection {
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
section: string;
|
|
166
|
+
steps: InstructionItem[];
|
|
154
167
|
}
|
|
155
168
|
interface SoustackInstruction {
|
|
156
169
|
id?: string;
|
|
157
170
|
text: string;
|
|
158
|
-
destination?: string;
|
|
159
171
|
/** IDs of steps that must complete before this one starts */
|
|
160
172
|
dependsOn?: string[];
|
|
161
173
|
/** IDs of ingredients used in this step */
|
|
162
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[];
|
|
163
179
|
timing?: StepTiming;
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
temperature?: Temperature;
|
|
181
|
+
images?: string[];
|
|
182
|
+
videos?: string[];
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
[k: `x-${string}`]: unknown;
|
|
166
185
|
}
|
|
167
186
|
type Instruction = SoustackInstruction;
|
|
168
187
|
interface StepTiming {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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;
|
|
172
199
|
}
|
|
173
200
|
interface Storage {
|
|
174
201
|
roomTemp?: StorageMethod;
|
|
@@ -207,24 +234,11 @@ interface NutritionFacts {
|
|
|
207
234
|
calories?: number;
|
|
208
235
|
protein_g?: number;
|
|
209
236
|
}
|
|
210
|
-
interface
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
interface TaxonomyModule {
|
|
216
|
-
keywords?: string[];
|
|
217
|
-
category?: string;
|
|
218
|
-
cuisine?: string;
|
|
219
|
-
}
|
|
220
|
-
interface MediaModule {
|
|
221
|
-
images?: string[];
|
|
222
|
-
videos?: string[];
|
|
223
|
-
}
|
|
224
|
-
interface TimesModule {
|
|
225
|
-
prepMinutes?: number;
|
|
226
|
-
cookMinutes?: number;
|
|
227
|
-
totalMinutes?: number;
|
|
237
|
+
interface Temperature {
|
|
238
|
+
value: number;
|
|
239
|
+
unit: "celsius" | "fahrenheit";
|
|
240
|
+
metadata?: Record<string, unknown>;
|
|
241
|
+
[k: `x-${string}`]: unknown;
|
|
228
242
|
}
|
|
229
243
|
|
|
230
244
|
interface HowToStep {
|