soustack 0.2.3 → 0.4.0

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/index.d.mts CHANGED
@@ -1,10 +1,26 @@
1
1
  /**
2
- * Soustack Recipe Schema v0.2.1
2
+ * Soustack Recipe Schema v0.3.0
3
3
  * A portable, scalable, interoperable recipe format.
4
4
  */
5
5
  interface SoustackRecipe {
6
+ /** Document marker for Soustack recipes */
7
+ '@type'?: 'Recipe';
6
8
  /** Optional $schema pointer for profile-aware validation */
7
9
  $schema?: string;
10
+ /** Optional declared validation profile */
11
+ profile?: string;
12
+ /** Recipe level: "lite" or "base" */
13
+ level?: "lite" | "base";
14
+ /** Stack declarations as a map: Record<stackName, versionNumber> */
15
+ 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;
8
24
  /** Unique identifier (slug or UUID) */
9
25
  id?: string;
10
26
  /** Optional display title */
@@ -77,25 +93,25 @@ interface Equipment {
77
93
  name: string;
78
94
  required?: boolean;
79
95
  label?: string;
80
- capacity?: Quantity;
96
+ capacity?: Quantity$1;
81
97
  scalingLimit?: number;
82
98
  alternatives?: string[];
83
99
  }
84
- interface Quantity {
100
+ interface Quantity$1 {
85
101
  amount: number;
86
102
  /** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
87
103
  unit: string | null;
88
104
  }
89
- type IngredientItem = string | Ingredient | IngredientSubsection;
105
+ type IngredientItem = string | Ingredient$1 | IngredientSubsection;
90
106
  interface IngredientSubsection {
91
107
  subsection: string;
92
- items: (string | Ingredient)[];
108
+ items: (string | Ingredient$1)[];
93
109
  }
94
- interface Ingredient {
110
+ interface Ingredient$1 {
95
111
  id?: string;
96
112
  /** Full human-readable text (e.g. "2 cups flour") */
97
113
  item: string;
98
- quantity?: Quantity;
114
+ quantity?: Quantity$1;
99
115
  name?: string;
100
116
  aisle?: string;
101
117
  /** Required prep state (e.g. "diced") */
@@ -208,15 +224,27 @@ interface Alternative {
208
224
  dietary?: string[];
209
225
  }
210
226
  interface NutritionFacts {
211
- calories?: string;
212
- fatContent?: string;
213
- carbohydrateContent?: string;
214
- proteinContent?: string;
215
- fiberContent?: string;
216
- sugarContent?: string;
217
- sodiumContent?: string;
218
- servingSize?: string;
219
- [key: string]: string | number | null | string[] | undefined;
227
+ calories?: number;
228
+ protein_g?: number;
229
+ }
230
+ interface AttributionModule {
231
+ url?: string;
232
+ author?: string;
233
+ datePublished?: string;
234
+ }
235
+ interface TaxonomyModule {
236
+ keywords?: string[];
237
+ category?: string;
238
+ cuisine?: string;
239
+ }
240
+ interface MediaModule {
241
+ images?: string[];
242
+ videos?: string[];
243
+ }
244
+ interface TimesModule {
245
+ prepMinutes?: number;
246
+ cookMinutes?: number;
247
+ totalMinutes?: number;
220
248
  }
221
249
 
222
250
  interface ScaleRecipeOptions {
@@ -228,32 +256,76 @@ interface ScaleRecipeOptions {
228
256
  }
229
257
  declare function scaleRecipe(recipe: Recipe, options?: ScaleRecipeOptions): Recipe;
230
258
 
231
- type ProfileName = "base" | "cookable" | "scalable" | "quantified" | "illustrated" | "schedulable";
232
- interface NormalizedError {
259
+ type ConformanceSeverity = "error" | "warning";
260
+ interface ConformanceIssue {
261
+ code: string;
233
262
  path: string;
234
263
  message: string;
235
- keyword?: string;
264
+ severity: ConformanceSeverity;
236
265
  }
237
- interface NormalizedWarning {
266
+
267
+ type ProfileName = "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed" | "minimal" | "core";
268
+ interface NormalizedError {
238
269
  path: string;
239
270
  message: string;
271
+ keyword?: string;
240
272
  }
273
+ /**
274
+ * Validation modes for recipe validation.
275
+ * - "schema": JSON Schema only
276
+ * - "full": JSON Schema + semantic conformance checks
277
+ */
278
+ type ValidateMode = "schema" | "full";
241
279
  interface ValidateOptions {
242
280
  profile?: ProfileName;
243
281
  schema?: string;
244
282
  collectAllErrors?: boolean;
283
+ mode?: ValidateMode;
284
+ includeNormalized?: boolean;
245
285
  }
246
- interface ValidationResult {
247
- valid: boolean;
248
- errors: NormalizedError[];
249
- warnings: NormalizedWarning[];
250
- normalized?: Recipe;
286
+ /**
287
+ * Result payload for recipe validation. Schema validation always runs first;
288
+ * conformance issues are only included when running in full mode.
289
+ */
290
+ interface ValidateResult {
291
+ ok: boolean;
292
+ schemaErrors: NormalizedError[];
293
+ conformanceIssues: ConformanceIssue[];
294
+ warnings: string[];
295
+ normalizedRecipe?: Recipe;
251
296
  }
252
- declare function validateRecipe(input: any, options?: ValidateOptions): ValidationResult;
297
+ /**
298
+ * Legacy validateRecipe function - now uses the new validateRecipeSchema internally
299
+ * but maintains backward compatibility with profile/stack-based validation
300
+ * Also includes semantic conformance validation.
301
+ */
302
+ /**
303
+ * Validates a recipe with explicit validation modes.
304
+ * - mode="schema": JSON Schema only
305
+ * - mode="full": schema + semantic conformance (only if schema passes)
306
+ */
307
+ declare function validateRecipe(input: any, options?: ValidateOptions): ValidateResult;
253
308
  declare function detectProfiles(recipe: any): ProfileName[];
254
309
 
255
310
  declare function fromSchemaOrg(input: unknown): Recipe | null;
256
311
 
312
+ interface NormalizationResult {
313
+ recipe: Recipe;
314
+ warnings: string[];
315
+ }
316
+ /**
317
+ * Normalizes a recipe input to the current spec format:
318
+ * - Rejects inputs with legacy field (unsupported)
319
+ * - Converts legacy `stacks` array format to map format
320
+ * - Ensures `stacks` exists even if empty
321
+ * - Preserves existing `stacks` map format
322
+ *
323
+ * @param input - Raw recipe input (may have legacy formats)
324
+ * @returns Normalized recipe with warnings for any issues encountered
325
+ * @throws Error if input contains legacy field
326
+ */
327
+ declare function normalizeRecipe(input: unknown): NormalizationResult;
328
+
257
329
  interface SchemaOrgRecipe$1 {
258
330
  '@context'?: string | Array<string | Record<string, unknown>> | Record<string, unknown>;
259
331
  '@type'?: string | string[];
@@ -276,6 +348,7 @@ interface SchemaOrgRecipe$1 {
276
348
  datePublished?: string;
277
349
  dateModified?: string;
278
350
  nutrition?: NutritionInformation;
351
+ video?: SchemaOrgImage;
279
352
  '@graph'?: unknown;
280
353
  }
281
354
  type SchemaOrgIngredientList = string | string[];
@@ -321,6 +394,14 @@ interface NutritionInformation {
321
394
  [key: string]: string | number | null | undefined;
322
395
  }
323
396
 
397
+ /**
398
+ * Convert a Soustack recipe to Schema.org JSON-LD format.
399
+ *
400
+ * BREAKING CHANGE in v0.3.0: This function now targets the "minimal" profile
401
+ * and only includes stacks that are schemaOrgMappable (as defined in the
402
+ * stacks registry). Non-mappable stacks (e.g., nutrition@1, schedule@1)
403
+ * are excluded from the conversion.
404
+ */
324
405
  declare function toSchemaOrg(recipe: Recipe): SchemaOrgRecipe$1;
325
406
 
326
407
  interface HowToStep {
@@ -348,6 +429,69 @@ interface SchemaOrgRecipe {
348
429
 
349
430
  declare function extractSchemaOrgRecipeFromHTML(html: string): SchemaOrgRecipe | null;
350
431
 
351
- declare const SOUSTACK_SPEC_VERSION = "0.2.1";
432
+ declare const SOUSTACK_SPEC_VERSION = "0.3.0";
433
+
434
+ type ConvertTarget = 'metric';
435
+ type ConvertMode = 'volume' | 'mass';
436
+ type RoundMode = 'none' | 'sane';
437
+ interface LineItem {
438
+ ingredient: string;
439
+ quantity: number;
440
+ unit: string | null;
441
+ }
442
+ interface ConvertedLineItem extends LineItem {
443
+ notes?: string;
444
+ }
445
+ declare class UnknownUnitError extends Error {
446
+ readonly unit: string;
447
+ constructor(unit: string);
448
+ }
449
+ declare class UnsupportedConversionError extends Error {
450
+ readonly unit: string;
451
+ readonly mode: ConvertMode;
452
+ constructor(unit: string, mode: ConvertMode);
453
+ }
454
+ declare class MissingEquivalencyError extends Error {
455
+ readonly ingredient: string;
456
+ readonly unit: string;
457
+ constructor(ingredient: string, unit: string);
458
+ }
459
+ declare function convertLineItemToMetric(item: LineItem, mode: ConvertMode, opts?: {
460
+ round?: RoundMode;
461
+ }): ConvertedLineItem;
462
+
463
+ interface Quantity {
464
+ amount: number;
465
+ unit?: string | null;
466
+ }
467
+ interface Ingredient {
468
+ id?: string;
469
+ item: string;
470
+ quantity?: Quantity;
471
+ name?: string;
472
+ prep?: string;
473
+ prepAction?: string;
474
+ prepActions?: string[];
475
+ form?: string;
476
+ prepTime?: number;
477
+ optional?: boolean;
478
+ notes?: string;
479
+ }
480
+ interface MiseEnPlaceTask {
481
+ category: 'prep' | 'state' | 'measure' | 'other';
482
+ action?: string;
483
+ form?: string;
484
+ items: Array<{
485
+ ingredient: string;
486
+ quantity?: Quantity;
487
+ optional?: boolean;
488
+ notes?: string;
489
+ }>;
490
+ }
491
+ interface MiseEnPlacePlan {
492
+ tasks: MiseEnPlaceTask[];
493
+ ungrouped: Ingredient[];
494
+ }
495
+ declare function miseEnPlace(ingredients: Ingredient[]): MiseEnPlacePlan;
352
496
 
353
- export { type Alternative, type Equipment, type FrozenStorageMethod, type Ingredient, type IngredientItem, type IngredientSubsection, type Instruction, type InstructionItem, type InstructionSubsection, type MakeAheadComponent, type NutritionFacts, type ParsedIngredient, type ParsedYield, type Quantity, type Recipe, SOUSTACK_SPEC_VERSION, type Scaling, type ScalingBakersPercentage, type ScalingBase, type ScalingDiscrete, type ScalingFixed, type ScalingLinear, type ScalingProportional, type SimpleTime, type Source, type SoustackInstruction, type SoustackRecipe, type StepTiming, type Storage, type StorageMethod, type StructuredTime, type Substitution, type Time, type Yield, detectProfiles, extractSchemaOrgRecipeFromHTML, fromSchemaOrg, scaleRecipe, toSchemaOrg, validateRecipe };
497
+ export { type Alternative, type AttributionModule, type ConvertMode, type ConvertTarget, type ConvertedLineItem, type Equipment, type FrozenStorageMethod, type Ingredient$1 as Ingredient, type IngredientItem, type IngredientSubsection, type Instruction, type InstructionItem, type InstructionSubsection, type LineItem, type MakeAheadComponent, type MediaModule, type Ingredient as MiseEnPlaceIngredient, type MiseEnPlacePlan, type Quantity as MiseEnPlaceQuantity, type MiseEnPlaceTask, MissingEquivalencyError, type NormalizationResult, type NutritionFacts, type ParsedIngredient, type ParsedYield, type Quantity$1 as Quantity, type Recipe, type RoundMode, SOUSTACK_SPEC_VERSION, type Scaling, type ScalingBakersPercentage, type ScalingBase, type ScalingDiscrete, type ScalingFixed, type ScalingLinear, type ScalingProportional, type SimpleTime, type Source, type SoustackInstruction, type SoustackRecipe, type StepTiming, type Storage, type StorageMethod, type StructuredTime, type Substitution, type TaxonomyModule, type Time, type TimesModule, UnknownUnitError, UnsupportedConversionError, type ValidateMode, type ValidateResult, type Yield, convertLineItemToMetric, detectProfiles, extractSchemaOrgRecipeFromHTML, fromSchemaOrg, miseEnPlace, normalizeRecipe, scaleRecipe, toSchemaOrg, validateRecipe };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,26 @@
1
1
  /**
2
- * Soustack Recipe Schema v0.2.1
2
+ * Soustack Recipe Schema v0.3.0
3
3
  * A portable, scalable, interoperable recipe format.
4
4
  */
5
5
  interface SoustackRecipe {
6
+ /** Document marker for Soustack recipes */
7
+ '@type'?: 'Recipe';
6
8
  /** Optional $schema pointer for profile-aware validation */
7
9
  $schema?: string;
10
+ /** Optional declared validation profile */
11
+ profile?: string;
12
+ /** Recipe level: "lite" or "base" */
13
+ level?: "lite" | "base";
14
+ /** Stack declarations as a map: Record<stackName, versionNumber> */
15
+ 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;
8
24
  /** Unique identifier (slug or UUID) */
9
25
  id?: string;
10
26
  /** Optional display title */
@@ -77,25 +93,25 @@ interface Equipment {
77
93
  name: string;
78
94
  required?: boolean;
79
95
  label?: string;
80
- capacity?: Quantity;
96
+ capacity?: Quantity$1;
81
97
  scalingLimit?: number;
82
98
  alternatives?: string[];
83
99
  }
84
- interface Quantity {
100
+ interface Quantity$1 {
85
101
  amount: number;
86
102
  /** Unit string (e.g. "g", "cup") or null for count-based items (e.g. "2 eggs") */
87
103
  unit: string | null;
88
104
  }
89
- type IngredientItem = string | Ingredient | IngredientSubsection;
105
+ type IngredientItem = string | Ingredient$1 | IngredientSubsection;
90
106
  interface IngredientSubsection {
91
107
  subsection: string;
92
- items: (string | Ingredient)[];
108
+ items: (string | Ingredient$1)[];
93
109
  }
94
- interface Ingredient {
110
+ interface Ingredient$1 {
95
111
  id?: string;
96
112
  /** Full human-readable text (e.g. "2 cups flour") */
97
113
  item: string;
98
- quantity?: Quantity;
114
+ quantity?: Quantity$1;
99
115
  name?: string;
100
116
  aisle?: string;
101
117
  /** Required prep state (e.g. "diced") */
@@ -208,15 +224,27 @@ interface Alternative {
208
224
  dietary?: string[];
209
225
  }
210
226
  interface NutritionFacts {
211
- calories?: string;
212
- fatContent?: string;
213
- carbohydrateContent?: string;
214
- proteinContent?: string;
215
- fiberContent?: string;
216
- sugarContent?: string;
217
- sodiumContent?: string;
218
- servingSize?: string;
219
- [key: string]: string | number | null | string[] | undefined;
227
+ calories?: number;
228
+ protein_g?: number;
229
+ }
230
+ interface AttributionModule {
231
+ url?: string;
232
+ author?: string;
233
+ datePublished?: string;
234
+ }
235
+ interface TaxonomyModule {
236
+ keywords?: string[];
237
+ category?: string;
238
+ cuisine?: string;
239
+ }
240
+ interface MediaModule {
241
+ images?: string[];
242
+ videos?: string[];
243
+ }
244
+ interface TimesModule {
245
+ prepMinutes?: number;
246
+ cookMinutes?: number;
247
+ totalMinutes?: number;
220
248
  }
221
249
 
222
250
  interface ScaleRecipeOptions {
@@ -228,32 +256,76 @@ interface ScaleRecipeOptions {
228
256
  }
229
257
  declare function scaleRecipe(recipe: Recipe, options?: ScaleRecipeOptions): Recipe;
230
258
 
231
- type ProfileName = "base" | "cookable" | "scalable" | "quantified" | "illustrated" | "schedulable";
232
- interface NormalizedError {
259
+ type ConformanceSeverity = "error" | "warning";
260
+ interface ConformanceIssue {
261
+ code: string;
233
262
  path: string;
234
263
  message: string;
235
- keyword?: string;
264
+ severity: ConformanceSeverity;
236
265
  }
237
- interface NormalizedWarning {
266
+
267
+ type ProfileName = "base" | "equipped" | "illustrated" | "lite" | "prepped" | "scalable" | "timed" | "minimal" | "core";
268
+ interface NormalizedError {
238
269
  path: string;
239
270
  message: string;
271
+ keyword?: string;
240
272
  }
273
+ /**
274
+ * Validation modes for recipe validation.
275
+ * - "schema": JSON Schema only
276
+ * - "full": JSON Schema + semantic conformance checks
277
+ */
278
+ type ValidateMode = "schema" | "full";
241
279
  interface ValidateOptions {
242
280
  profile?: ProfileName;
243
281
  schema?: string;
244
282
  collectAllErrors?: boolean;
283
+ mode?: ValidateMode;
284
+ includeNormalized?: boolean;
245
285
  }
246
- interface ValidationResult {
247
- valid: boolean;
248
- errors: NormalizedError[];
249
- warnings: NormalizedWarning[];
250
- normalized?: Recipe;
286
+ /**
287
+ * Result payload for recipe validation. Schema validation always runs first;
288
+ * conformance issues are only included when running in full mode.
289
+ */
290
+ interface ValidateResult {
291
+ ok: boolean;
292
+ schemaErrors: NormalizedError[];
293
+ conformanceIssues: ConformanceIssue[];
294
+ warnings: string[];
295
+ normalizedRecipe?: Recipe;
251
296
  }
252
- declare function validateRecipe(input: any, options?: ValidateOptions): ValidationResult;
297
+ /**
298
+ * Legacy validateRecipe function - now uses the new validateRecipeSchema internally
299
+ * but maintains backward compatibility with profile/stack-based validation
300
+ * Also includes semantic conformance validation.
301
+ */
302
+ /**
303
+ * Validates a recipe with explicit validation modes.
304
+ * - mode="schema": JSON Schema only
305
+ * - mode="full": schema + semantic conformance (only if schema passes)
306
+ */
307
+ declare function validateRecipe(input: any, options?: ValidateOptions): ValidateResult;
253
308
  declare function detectProfiles(recipe: any): ProfileName[];
254
309
 
255
310
  declare function fromSchemaOrg(input: unknown): Recipe | null;
256
311
 
312
+ interface NormalizationResult {
313
+ recipe: Recipe;
314
+ warnings: string[];
315
+ }
316
+ /**
317
+ * Normalizes a recipe input to the current spec format:
318
+ * - Rejects inputs with legacy field (unsupported)
319
+ * - Converts legacy `stacks` array format to map format
320
+ * - Ensures `stacks` exists even if empty
321
+ * - Preserves existing `stacks` map format
322
+ *
323
+ * @param input - Raw recipe input (may have legacy formats)
324
+ * @returns Normalized recipe with warnings for any issues encountered
325
+ * @throws Error if input contains legacy field
326
+ */
327
+ declare function normalizeRecipe(input: unknown): NormalizationResult;
328
+
257
329
  interface SchemaOrgRecipe$1 {
258
330
  '@context'?: string | Array<string | Record<string, unknown>> | Record<string, unknown>;
259
331
  '@type'?: string | string[];
@@ -276,6 +348,7 @@ interface SchemaOrgRecipe$1 {
276
348
  datePublished?: string;
277
349
  dateModified?: string;
278
350
  nutrition?: NutritionInformation;
351
+ video?: SchemaOrgImage;
279
352
  '@graph'?: unknown;
280
353
  }
281
354
  type SchemaOrgIngredientList = string | string[];
@@ -321,6 +394,14 @@ interface NutritionInformation {
321
394
  [key: string]: string | number | null | undefined;
322
395
  }
323
396
 
397
+ /**
398
+ * Convert a Soustack recipe to Schema.org JSON-LD format.
399
+ *
400
+ * BREAKING CHANGE in v0.3.0: This function now targets the "minimal" profile
401
+ * and only includes stacks that are schemaOrgMappable (as defined in the
402
+ * stacks registry). Non-mappable stacks (e.g., nutrition@1, schedule@1)
403
+ * are excluded from the conversion.
404
+ */
324
405
  declare function toSchemaOrg(recipe: Recipe): SchemaOrgRecipe$1;
325
406
 
326
407
  interface HowToStep {
@@ -348,6 +429,69 @@ interface SchemaOrgRecipe {
348
429
 
349
430
  declare function extractSchemaOrgRecipeFromHTML(html: string): SchemaOrgRecipe | null;
350
431
 
351
- declare const SOUSTACK_SPEC_VERSION = "0.2.1";
432
+ declare const SOUSTACK_SPEC_VERSION = "0.3.0";
433
+
434
+ type ConvertTarget = 'metric';
435
+ type ConvertMode = 'volume' | 'mass';
436
+ type RoundMode = 'none' | 'sane';
437
+ interface LineItem {
438
+ ingredient: string;
439
+ quantity: number;
440
+ unit: string | null;
441
+ }
442
+ interface ConvertedLineItem extends LineItem {
443
+ notes?: string;
444
+ }
445
+ declare class UnknownUnitError extends Error {
446
+ readonly unit: string;
447
+ constructor(unit: string);
448
+ }
449
+ declare class UnsupportedConversionError extends Error {
450
+ readonly unit: string;
451
+ readonly mode: ConvertMode;
452
+ constructor(unit: string, mode: ConvertMode);
453
+ }
454
+ declare class MissingEquivalencyError extends Error {
455
+ readonly ingredient: string;
456
+ readonly unit: string;
457
+ constructor(ingredient: string, unit: string);
458
+ }
459
+ declare function convertLineItemToMetric(item: LineItem, mode: ConvertMode, opts?: {
460
+ round?: RoundMode;
461
+ }): ConvertedLineItem;
462
+
463
+ interface Quantity {
464
+ amount: number;
465
+ unit?: string | null;
466
+ }
467
+ interface Ingredient {
468
+ id?: string;
469
+ item: string;
470
+ quantity?: Quantity;
471
+ name?: string;
472
+ prep?: string;
473
+ prepAction?: string;
474
+ prepActions?: string[];
475
+ form?: string;
476
+ prepTime?: number;
477
+ optional?: boolean;
478
+ notes?: string;
479
+ }
480
+ interface MiseEnPlaceTask {
481
+ category: 'prep' | 'state' | 'measure' | 'other';
482
+ action?: string;
483
+ form?: string;
484
+ items: Array<{
485
+ ingredient: string;
486
+ quantity?: Quantity;
487
+ optional?: boolean;
488
+ notes?: string;
489
+ }>;
490
+ }
491
+ interface MiseEnPlacePlan {
492
+ tasks: MiseEnPlaceTask[];
493
+ ungrouped: Ingredient[];
494
+ }
495
+ declare function miseEnPlace(ingredients: Ingredient[]): MiseEnPlacePlan;
352
496
 
353
- export { type Alternative, type Equipment, type FrozenStorageMethod, type Ingredient, type IngredientItem, type IngredientSubsection, type Instruction, type InstructionItem, type InstructionSubsection, type MakeAheadComponent, type NutritionFacts, type ParsedIngredient, type ParsedYield, type Quantity, type Recipe, SOUSTACK_SPEC_VERSION, type Scaling, type ScalingBakersPercentage, type ScalingBase, type ScalingDiscrete, type ScalingFixed, type ScalingLinear, type ScalingProportional, type SimpleTime, type Source, type SoustackInstruction, type SoustackRecipe, type StepTiming, type Storage, type StorageMethod, type StructuredTime, type Substitution, type Time, type Yield, detectProfiles, extractSchemaOrgRecipeFromHTML, fromSchemaOrg, scaleRecipe, toSchemaOrg, validateRecipe };
497
+ export { type Alternative, type AttributionModule, type ConvertMode, type ConvertTarget, type ConvertedLineItem, type Equipment, type FrozenStorageMethod, type Ingredient$1 as Ingredient, type IngredientItem, type IngredientSubsection, type Instruction, type InstructionItem, type InstructionSubsection, type LineItem, type MakeAheadComponent, type MediaModule, type Ingredient as MiseEnPlaceIngredient, type MiseEnPlacePlan, type Quantity as MiseEnPlaceQuantity, type MiseEnPlaceTask, MissingEquivalencyError, type NormalizationResult, type NutritionFacts, type ParsedIngredient, type ParsedYield, type Quantity$1 as Quantity, type Recipe, type RoundMode, SOUSTACK_SPEC_VERSION, type Scaling, type ScalingBakersPercentage, type ScalingBase, type ScalingDiscrete, type ScalingFixed, type ScalingLinear, type ScalingProportional, type SimpleTime, type Source, type SoustackInstruction, type SoustackRecipe, type StepTiming, type Storage, type StorageMethod, type StructuredTime, type Substitution, type TaxonomyModule, type Time, type TimesModule, UnknownUnitError, UnsupportedConversionError, type ValidateMode, type ValidateResult, type Yield, convertLineItemToMetric, detectProfiles, extractSchemaOrgRecipeFromHTML, fromSchemaOrg, miseEnPlace, normalizeRecipe, scaleRecipe, toSchemaOrg, validateRecipe };