soustack 0.1.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.
@@ -0,0 +1,305 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "http://soustack.org/schema/v0.1",
4
+ "title": "Soustack Recipe Schema v0.1",
5
+ "description": "A portable, scalable, interoperable recipe format.",
6
+ "type": "object",
7
+ "required": ["name", "ingredients", "instructions"],
8
+ "properties": {
9
+ "id": {
10
+ "type": "string",
11
+ "description": "Unique identifier (slug or UUID)"
12
+ },
13
+ "name": {
14
+ "type": "string",
15
+ "description": "The title of the recipe"
16
+ },
17
+ "version": {
18
+ "type": "string",
19
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
20
+ "description": "Semantic versioning (e.g., 1.0.0)"
21
+ },
22
+ "description": {
23
+ "type": "string"
24
+ },
25
+ "category": {
26
+ "type": "string",
27
+ "examples": ["Main Course", "Dessert"]
28
+ },
29
+ "tags": {
30
+ "type": "array",
31
+ "items": { "type": "string" }
32
+ },
33
+ "image": {
34
+ "type": "string",
35
+ "format": "uri"
36
+ },
37
+ "dateAdded": {
38
+ "type": "string",
39
+ "format": "date-time"
40
+ },
41
+ "source": {
42
+ "type": "object",
43
+ "properties": {
44
+ "author": { "type": "string" },
45
+ "url": { "type": "string", "format": "uri" },
46
+ "name": { "type": "string" },
47
+ "adapted": { "type": "boolean" }
48
+ }
49
+ },
50
+ "yield": {
51
+ "$ref": "#/definitions/yield"
52
+ },
53
+ "time": {
54
+ "$ref": "#/definitions/time"
55
+ },
56
+ "equipment": {
57
+ "type": "array",
58
+ "items": { "$ref": "#/definitions/equipment" }
59
+ },
60
+ "ingredients": {
61
+ "type": "array",
62
+ "items": {
63
+ "anyOf": [
64
+ { "type": "string" },
65
+ { "$ref": "#/definitions/ingredient" },
66
+ { "$ref": "#/definitions/ingredientSubsection" }
67
+ ]
68
+ }
69
+ },
70
+ "instructions": {
71
+ "type": "array",
72
+ "items": {
73
+ "anyOf": [
74
+ { "type": "string" },
75
+ { "$ref": "#/definitions/instruction" },
76
+ { "$ref": "#/definitions/instructionSubsection" }
77
+ ]
78
+ }
79
+ },
80
+ "storage": {
81
+ "$ref": "#/definitions/storage"
82
+ },
83
+ "substitutions": {
84
+ "type": "array",
85
+ "items": { "$ref": "#/definitions/substitution" }
86
+ }
87
+ },
88
+ "definitions": {
89
+ "yield": {
90
+ "type": "object",
91
+ "required": ["amount", "unit"],
92
+ "properties": {
93
+ "amount": { "type": "number" },
94
+ "unit": { "type": "string" },
95
+ "servings": { "type": "number" },
96
+ "description": { "type": "string" }
97
+ }
98
+ },
99
+ "time": {
100
+ "oneOf": [
101
+ {
102
+ "type": "object",
103
+ "properties": {
104
+ "prep": { "type": "number" },
105
+ "active": { "type": "number" },
106
+ "passive": { "type": "number" },
107
+ "total": { "type": "number" }
108
+ }
109
+ },
110
+ {
111
+ "type": "object",
112
+ "properties": {
113
+ "prepTime": { "type": "string" },
114
+ "cookTime": { "type": "string" }
115
+ }
116
+ }
117
+ ]
118
+ },
119
+ "quantity": {
120
+ "type": "object",
121
+ "required": ["amount"],
122
+ "properties": {
123
+ "amount": { "type": "number" },
124
+ "unit": { "type": ["string", "null"] }
125
+ }
126
+ },
127
+ "scaling": {
128
+ "type": "object",
129
+ "required": ["type"],
130
+ "properties": {
131
+ "type": {
132
+ "type": "string",
133
+ "enum": ["linear", "discrete", "proportional", "fixed", "bakers_percentage"]
134
+ },
135
+ "factor": { "type": "number" },
136
+ "referenceId": { "type": "string" },
137
+ "roundTo": { "type": "number" },
138
+ "min": { "type": "number" },
139
+ "max": { "type": "number" }
140
+ },
141
+ "if": {
142
+ "properties": { "type": { "const": "bakers_percentage" } }
143
+ },
144
+ "then": {
145
+ "required": ["referenceId"]
146
+ }
147
+ },
148
+ "ingredient": {
149
+ "type": "object",
150
+ "required": ["item"],
151
+ "properties": {
152
+ "id": { "type": "string" },
153
+ "item": { "type": "string" },
154
+ "quantity": { "$ref": "#/definitions/quantity" },
155
+ "name": { "type": "string" },
156
+ "aisle": { "type": "string" },
157
+ "prep": { "type": "string" },
158
+ "prepAction": { "type": "string" },
159
+ "prepTime": { "type": "number" },
160
+ "destination": { "type": "string" },
161
+ "scaling": { "$ref": "#/definitions/scaling" },
162
+ "critical": { "type": "boolean" },
163
+ "optional": { "type": "boolean" },
164
+ "notes": { "type": "string" }
165
+ }
166
+ },
167
+ "ingredientSubsection": {
168
+ "type": "object",
169
+ "required": ["subsection", "items"],
170
+ "properties": {
171
+ "subsection": { "type": "string" },
172
+ "items": {
173
+ "type": "array",
174
+ "items": { "$ref": "#/definitions/ingredient" }
175
+ }
176
+ }
177
+ },
178
+ "equipment": {
179
+ "type": "object",
180
+ "required": ["name"],
181
+ "properties": {
182
+ "id": { "type": "string" },
183
+ "name": { "type": "string" },
184
+ "required": { "type": "boolean" },
185
+ "label": { "type": "string" },
186
+ "capacity": { "$ref": "#/definitions/quantity" },
187
+ "scalingLimit": { "type": "number" },
188
+ "alternatives": {
189
+ "type": "array",
190
+ "items": { "type": "string" }
191
+ }
192
+ }
193
+ },
194
+ "instruction": {
195
+ "type": "object",
196
+ "required": ["text"],
197
+ "properties": {
198
+ "id": { "type": "string" },
199
+ "text": { "type": "string" },
200
+ "destination": { "type": "string" },
201
+ "dependsOn": {
202
+ "type": "array",
203
+ "items": { "type": "string" }
204
+ },
205
+ "inputs": {
206
+ "type": "array",
207
+ "items": { "type": "string" }
208
+ },
209
+ "timing": {
210
+ "type": "object",
211
+ "required": ["duration", "type"],
212
+ "properties": {
213
+ "duration": { "type": "number" },
214
+ "type": { "type": "string", "enum": ["active", "passive"] },
215
+ "scaling": { "type": "string", "enum": ["linear", "fixed", "sqrt"] }
216
+ }
217
+ }
218
+ }
219
+ },
220
+ "instructionSubsection": {
221
+ "type": "object",
222
+ "required": ["subsection", "items"],
223
+ "properties": {
224
+ "subsection": { "type": "string" },
225
+ "items": {
226
+ "type": "array",
227
+ "items": {
228
+ "anyOf": [
229
+ { "type": "string" },
230
+ { "$ref": "#/definitions/instruction" }
231
+ ]
232
+ }
233
+ }
234
+ }
235
+ },
236
+ "storage": {
237
+ "type": "object",
238
+ "properties": {
239
+ "roomTemp": { "$ref": "#/definitions/storageMethod" },
240
+ "refrigerated": { "$ref": "#/definitions/storageMethod" },
241
+ "frozen": {
242
+ "allOf": [
243
+ { "$ref": "#/definitions/storageMethod" },
244
+ {
245
+ "type": "object",
246
+ "properties": { "thawing": { "type": "string" } }
247
+ }
248
+ ]
249
+ },
250
+ "reheating": { "type": "string" },
251
+ "makeAhead": {
252
+ "type": "array",
253
+ "items": {
254
+ "allOf": [
255
+ { "$ref": "#/definitions/storageMethod" },
256
+ {
257
+ "type": "object",
258
+ "required": ["component", "storage"],
259
+ "properties": {
260
+ "component": { "type": "string" },
261
+ "storage": { "type": "string", "enum": ["roomTemp", "refrigerated", "frozen"] }
262
+ }
263
+ }
264
+ ]
265
+ }
266
+ }
267
+ }
268
+ },
269
+ "storageMethod": {
270
+ "type": "object",
271
+ "required": ["duration"],
272
+ "properties": {
273
+ "duration": { "type": "string", "pattern": "^P" },
274
+ "method": { "type": "string" },
275
+ "notes": { "type": "string" }
276
+ }
277
+ },
278
+ "substitution": {
279
+ "type": "object",
280
+ "required": ["ingredient"],
281
+ "properties": {
282
+ "ingredient": { "type": "string" },
283
+ "critical": { "type": "boolean" },
284
+ "notes": { "type": "string" },
285
+ "alternatives": {
286
+ "type": "array",
287
+ "items": {
288
+ "type": "object",
289
+ "required": ["name", "ratio"],
290
+ "properties": {
291
+ "name": { "type": "string" },
292
+ "ratio": { "type": "string" },
293
+ "notes": { "type": "string" },
294
+ "impact": { "type": "string" },
295
+ "dietary": {
296
+ "type": "array",
297
+ "items": { "type": "string" }
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }