@examplary/schemas 1.15.1 → 1.16.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.
@@ -12,5 +12,7 @@ export * from "./question-type-scanning-options";
12
12
  export type * from "./question-type-scanning-options";
13
13
  export * from "./question-type-capabilities";
14
14
  export type * from "./question-type-capabilities";
15
+ export * from "./question-type-response-processing";
16
+ export type * from "./question-type-response-processing";
15
17
  export * from "./question-type-qti3";
16
18
  export type * from "./question-type-qti3";
@@ -21,4 +21,5 @@ __exportStar(require("./question-type-generation-options"), exports);
21
21
  __exportStar(require("./question-type-grading-options"), exports);
22
22
  __exportStar(require("./question-type-scanning-options"), exports);
23
23
  __exportStar(require("./question-type-capabilities"), exports);
24
+ __exportStar(require("./question-type-response-processing"), exports);
24
25
  __exportStar(require("./question-type-qti3"), exports);
@@ -0,0 +1,47 @@
1
+ import { z } from "zod";
2
+ export declare const QuestionTypeResponseProcessing: z.ZodObject<{
3
+ condition: z.ZodString;
4
+ testCases: z.ZodOptional<z.ZodArray<z.ZodObject<{
5
+ answer: z.ZodObject<{
6
+ value: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>]>>>>;
7
+ }, z.core.$loose>;
8
+ question: z.ZodObject<{
9
+ id: z.ZodOptional<z.ZodString>;
10
+ type: z.ZodOptional<z.ZodString>;
11
+ title: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
12
+ description: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
13
+ settings: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
14
+ scoring: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
15
+ rubricType: z.ZodOptional<z.ZodNullable<z.ZodEnum<typeof import("..").RubricType>>>;
16
+ criteria: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
17
+ id: z.ZodString;
18
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
19
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
20
+ points: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
21
+ minPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
22
+ maxPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
23
+ levels: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
24
+ id: z.ZodString;
25
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ points: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
28
+ minPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
29
+ maxPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
30
+ }, z.core.$strip>>>>;
31
+ }, z.core.$strip>>>>;
32
+ exactValuesCaseInsensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
33
+ guidance: z.ZodOptional<z.ZodNullable<z.ZodString>>;
34
+ modelAnswer: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ templateId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
36
+ }, z.core.$strip>>>>;
37
+ tags: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>>;
38
+ externalId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
39
+ metadata: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>>>>;
40
+ v: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
41
+ questionBankItemId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
42
+ traceIds: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>>;
43
+ }, z.core.$loose>;
44
+ expectedOutcome: z.ZodBoolean;
45
+ }, z.core.$strip>>>;
46
+ }, z.core.$strip>;
47
+ export type QuestionTypeResponseProcessingType = z.infer<typeof QuestionTypeResponseProcessing>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuestionTypeResponseProcessing = void 0;
4
+ const zod_1 = require("zod");
5
+ const question_1 = require("../question/question");
6
+ const AnswerSchema = zod_1.z.looseObject({
7
+ // TODO: this is a partial answer schema, should we move the Answer schema to this package?
8
+ value: zod_1.z
9
+ .union([zod_1.z.string(), zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.null()]))])
10
+ .nullish(),
11
+ });
12
+ const QuestionTypeResponseProcessingTestCase = zod_1.z.object({
13
+ answer: AnswerSchema.partial(),
14
+ question: question_1.QuestionSchema.partial(),
15
+ expectedOutcome: zod_1.z.boolean(),
16
+ });
17
+ exports.QuestionTypeResponseProcessing = zod_1.z
18
+ .object({
19
+ condition: zod_1.z
20
+ .string()
21
+ .regex(/^=/, "Response processing condition must start with '='")
22
+ .describe("JSONata expression string starting with '=' that evaluates to a boolean to determine if the response is correct"),
23
+ testCases: zod_1.z
24
+ .array(QuestionTypeResponseProcessingTestCase)
25
+ .optional()
26
+ .describe("Array of test cases to validate the response processing logic for this question type"),
27
+ })
28
+ .describe("Options for response processing");
@@ -14,9 +14,9 @@ export declare const QuestionTypeSetting: z.ZodObject<{
14
14
  boolean: "boolean";
15
15
  enum: "enum";
16
16
  custom: "custom";
17
+ tags: "tags";
17
18
  "string-array": "string-array";
18
19
  "scoring-criteria": "scoring-criteria";
19
- tags: "tags";
20
20
  "question-type": "question-type";
21
21
  }>;
22
22
  index: z.ZodOptional<z.ZodNumber>;
@@ -14,6 +14,51 @@ export declare const QuestionTypeSchema: z.ZodObject<{
14
14
  enabled: z.ZodBoolean;
15
15
  instructions: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;
16
16
  }, z.core.$strip>>;
17
+ responseProcessing: z.ZodOptional<z.ZodObject<{
18
+ condition: z.ZodString;
19
+ testCases: z.ZodOptional<z.ZodArray<z.ZodObject<{
20
+ answer: z.ZodObject<{
21
+ value: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>]>>>>;
22
+ }, z.core.$loose>;
23
+ question: z.ZodObject<{
24
+ id: z.ZodOptional<z.ZodString>;
25
+ type: z.ZodOptional<z.ZodString>;
26
+ title: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
27
+ description: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
28
+ settings: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
29
+ scoring: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
30
+ rubricType: z.ZodOptional<z.ZodNullable<z.ZodEnum<typeof import("..").RubricType>>>;
31
+ criteria: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
32
+ id: z.ZodString;
33
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
34
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ points: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
36
+ minPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
37
+ maxPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
38
+ levels: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
39
+ id: z.ZodString;
40
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
41
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
42
+ points: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
43
+ minPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
44
+ maxPoints: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
45
+ }, z.core.$strip>>>>;
46
+ }, z.core.$strip>>>>;
47
+ exactValuesCaseInsensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
48
+ guidance: z.ZodOptional<z.ZodNullable<z.ZodString>>;
49
+ modelAnswer: z.ZodOptional<z.ZodNullable<z.ZodString>>;
50
+ templateId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
51
+ }, z.core.$strip>>>>;
52
+ tags: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>>;
53
+ externalId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
54
+ metadata: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>>>>;
55
+ v: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
56
+ questionBankItemId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
57
+ traceIds: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>>;
58
+ }, z.core.$loose>;
59
+ expectedOutcome: z.ZodBoolean;
60
+ }, z.core.$strip>>>;
61
+ }, z.core.$strip>>;
17
62
  scanning: z.ZodOptional<z.ZodObject<{
18
63
  instructions: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;
19
64
  }, z.core.$strip>>;
@@ -48,9 +93,9 @@ export declare const QuestionTypeSchema: z.ZodObject<{
48
93
  boolean: "boolean";
49
94
  enum: "enum";
50
95
  custom: "custom";
96
+ tags: "tags";
51
97
  "string-array": "string-array";
52
98
  "scoring-criteria": "scoring-criteria";
53
- tags: "tags";
54
99
  "question-type": "question-type";
55
100
  }>;
56
101
  index: z.ZodOptional<z.ZodNumber>;
@@ -7,6 +7,7 @@ const question_type_components_1 = require("./question-type-components");
7
7
  const question_type_generation_options_1 = require("./question-type-generation-options");
8
8
  const question_type_grading_options_1 = require("./question-type-grading-options");
9
9
  const question_type_qti3_1 = require("./question-type-qti3");
10
+ const question_type_response_processing_1 = require("./question-type-response-processing");
10
11
  const question_type_scanning_options_1 = require("./question-type-scanning-options");
11
12
  const question_type_setting_1 = require("./question-type-setting");
12
13
  const scalar_1 = require("../common/scalar");
@@ -28,6 +29,7 @@ exports.QuestionTypeSchema = zod_1.z
28
29
  .describe("Keyboard shortcut for quick access to this question type"),
29
30
  generation: question_type_generation_options_1.QuestionTypeGenerationOptions.optional(),
30
31
  grading: question_type_grading_options_1.QuestionTypeGradingOptions.optional(),
32
+ responseProcessing: question_type_response_processing_1.QuestionTypeResponseProcessing.optional(),
31
33
  scanning: question_type_scanning_options_1.QuestionTypeScanningOptions.optional(),
32
34
  timeEstimateMinutes: zod_1.z
33
35
  .number()
@@ -116,6 +116,436 @@
116
116
  "additionalProperties": false,
117
117
  "description": "Options for AI question grading"
118
118
  },
119
+ "responseProcessing": {
120
+ "type": "object",
121
+ "properties": {
122
+ "condition": {
123
+ "type": "string",
124
+ "pattern": "^=",
125
+ "description": "JSONata expression string starting with '=' that evaluates to a boolean to determine if the response is correct"
126
+ },
127
+ "testCases": {
128
+ "description": "Array of test cases to validate the response processing logic for this question type",
129
+ "type": "array",
130
+ "items": {
131
+ "type": "object",
132
+ "properties": {
133
+ "answer": {
134
+ "type": "object",
135
+ "properties": {
136
+ "value": {
137
+ "anyOf": [
138
+ {
139
+ "anyOf": [
140
+ {
141
+ "type": "string"
142
+ },
143
+ {
144
+ "type": "array",
145
+ "items": {
146
+ "anyOf": [
147
+ {
148
+ "type": "string"
149
+ },
150
+ {
151
+ "type": "null"
152
+ }
153
+ ]
154
+ }
155
+ }
156
+ ]
157
+ },
158
+ {
159
+ "type": "null"
160
+ }
161
+ ]
162
+ }
163
+ },
164
+ "additionalProperties": {}
165
+ },
166
+ "question": {
167
+ "type": "object",
168
+ "properties": {
169
+ "id": {
170
+ "type": "string",
171
+ "description": "Question ID"
172
+ },
173
+ "type": {
174
+ "type": "string",
175
+ "description": "ID of the question type"
176
+ },
177
+ "title": {
178
+ "description": "Title for the question (stem)",
179
+ "anyOf": [
180
+ {
181
+ "type": "string"
182
+ },
183
+ {
184
+ "type": "null"
185
+ }
186
+ ]
187
+ },
188
+ "description": {
189
+ "description": "Optional description for the question",
190
+ "anyOf": [
191
+ {
192
+ "type": "string"
193
+ },
194
+ {
195
+ "type": "null"
196
+ }
197
+ ]
198
+ },
199
+ "settings": {
200
+ "type": "object",
201
+ "properties": {},
202
+ "additionalProperties": {},
203
+ "description": "Settings for the question, often specific to the question type"
204
+ },
205
+ "scoring": {
206
+ "description": "Scoring configuration for the question",
207
+ "anyOf": [
208
+ {
209
+ "type": "object",
210
+ "properties": {
211
+ "rubricType": {
212
+ "description": "The type of rubric. Different rubric types have different shapes.",
213
+ "anyOf": [
214
+ {
215
+ "type": "string",
216
+ "enum": [
217
+ "simple",
218
+ "analytical",
219
+ "holistic",
220
+ "exact-values"
221
+ ]
222
+ },
223
+ {
224
+ "type": "null"
225
+ }
226
+ ]
227
+ },
228
+ "criteria": {
229
+ "description": "The criteria for scoring the question. For 'simple' rubric type, criteria have no levels, and their points stack (total = sum of points for all criteria that apply). For 'analytical' rubric type, there should be at least one criteria, with levels. For each criteria, a matching level is picked. For 'holistic' rubric type, there should be multiple criteria, without levels (score = single selected criteria). For 'exact-values' rubric type, each criteria represents a specific value that must be matched exactly.",
230
+ "anyOf": [
231
+ {
232
+ "type": "array",
233
+ "items": {
234
+ "type": "object",
235
+ "properties": {
236
+ "id": {
237
+ "type": "string"
238
+ },
239
+ "title": {
240
+ "description": "The title of the scoring criterion or level. Only applies to analytical levels and holistic criteria.",
241
+ "anyOf": [
242
+ {
243
+ "type": "string"
244
+ },
245
+ {
246
+ "type": "null"
247
+ }
248
+ ]
249
+ },
250
+ "description": {
251
+ "description": "The description of the scoring criterion or level. For analytical levels, this describes the specific requirements to earn the points for that level. For holistic criteria, this describes the overall requirement to earn the points for that criterion.",
252
+ "anyOf": [
253
+ {
254
+ "type": "string"
255
+ },
256
+ {
257
+ "type": "null"
258
+ }
259
+ ]
260
+ },
261
+ "points": {
262
+ "description": "The default amount of points to assign if this criterion or level is selected.",
263
+ "anyOf": [
264
+ {
265
+ "type": "number"
266
+ },
267
+ {
268
+ "type": "null"
269
+ }
270
+ ]
271
+ },
272
+ "minPoints": {
273
+ "description": "The minimum amount of points that can be assigned if this criterion or level is selected.",
274
+ "anyOf": [
275
+ {
276
+ "type": "number"
277
+ },
278
+ {
279
+ "type": "null"
280
+ }
281
+ ]
282
+ },
283
+ "maxPoints": {
284
+ "description": "The maximum amount of points that can be assigned if this criterion or level is selected.",
285
+ "anyOf": [
286
+ {
287
+ "type": "number"
288
+ },
289
+ {
290
+ "type": "null"
291
+ }
292
+ ]
293
+ },
294
+ "levels": {
295
+ "description": "The levels of a analytical rubric criterion. Each level represents a different point value and description for the same criterion.",
296
+ "anyOf": [
297
+ {
298
+ "type": "array",
299
+ "items": {
300
+ "type": "object",
301
+ "properties": {
302
+ "id": {
303
+ "type": "string"
304
+ },
305
+ "title": {
306
+ "description": "The title of the scoring criterion or level. Only applies to analytical levels and holistic criteria.",
307
+ "anyOf": [
308
+ {
309
+ "type": "string"
310
+ },
311
+ {
312
+ "type": "null"
313
+ }
314
+ ]
315
+ },
316
+ "description": {
317
+ "description": "The description of the scoring criterion or level. For analytical levels, this describes the specific requirements to earn the points for that level. For holistic criteria, this describes the overall requirement to earn the points for that criterion.",
318
+ "anyOf": [
319
+ {
320
+ "type": "string"
321
+ },
322
+ {
323
+ "type": "null"
324
+ }
325
+ ]
326
+ },
327
+ "points": {
328
+ "description": "The default amount of points to assign if this criterion or level is selected.",
329
+ "anyOf": [
330
+ {
331
+ "type": "number"
332
+ },
333
+ {
334
+ "type": "null"
335
+ }
336
+ ]
337
+ },
338
+ "minPoints": {
339
+ "description": "The minimum amount of points that can be assigned if this criterion or level is selected.",
340
+ "anyOf": [
341
+ {
342
+ "type": "number"
343
+ },
344
+ {
345
+ "type": "null"
346
+ }
347
+ ]
348
+ },
349
+ "maxPoints": {
350
+ "description": "The maximum amount of points that can be assigned if this criterion or level is selected.",
351
+ "anyOf": [
352
+ {
353
+ "type": "number"
354
+ },
355
+ {
356
+ "type": "null"
357
+ }
358
+ ]
359
+ }
360
+ },
361
+ "required": [
362
+ "id"
363
+ ],
364
+ "additionalProperties": false
365
+ }
366
+ },
367
+ {
368
+ "type": "null"
369
+ }
370
+ ]
371
+ }
372
+ },
373
+ "required": [
374
+ "id"
375
+ ],
376
+ "additionalProperties": false
377
+ }
378
+ },
379
+ {
380
+ "type": "null"
381
+ }
382
+ ]
383
+ },
384
+ "exactValuesCaseInsensitive": {
385
+ "description": "Whether exact values matching should be case insensitive. Only applicable for 'exact-values' rubric type.",
386
+ "anyOf": [
387
+ {
388
+ "type": "boolean"
389
+ },
390
+ {
391
+ "type": "null"
392
+ }
393
+ ]
394
+ },
395
+ "guidance": {
396
+ "description": "Optional additional grading guidance text.",
397
+ "anyOf": [
398
+ {
399
+ "type": "string"
400
+ },
401
+ {
402
+ "type": "null"
403
+ }
404
+ ]
405
+ },
406
+ "modelAnswer": {
407
+ "description": "Optional example model answer text to show to graders.",
408
+ "anyOf": [
409
+ {
410
+ "type": "string"
411
+ },
412
+ {
413
+ "type": "null"
414
+ }
415
+ ]
416
+ },
417
+ "templateId": {
418
+ "description": "The ID of the scoring template applied, if any.",
419
+ "anyOf": [
420
+ {
421
+ "type": "string"
422
+ },
423
+ {
424
+ "type": "null"
425
+ }
426
+ ]
427
+ }
428
+ },
429
+ "additionalProperties": false
430
+ },
431
+ {
432
+ "type": "null"
433
+ }
434
+ ]
435
+ },
436
+ "tags": {
437
+ "description": "Tags associated with the question for categorization and search",
438
+ "anyOf": [
439
+ {
440
+ "type": "array",
441
+ "items": {
442
+ "type": "string"
443
+ }
444
+ },
445
+ {
446
+ "type": "null"
447
+ }
448
+ ]
449
+ },
450
+ "externalId": {
451
+ "description": "Optional external ID for the question, used to link to external systems",
452
+ "anyOf": [
453
+ {
454
+ "type": "string"
455
+ },
456
+ {
457
+ "type": "null"
458
+ }
459
+ ]
460
+ },
461
+ "metadata": {
462
+ "description": "Metadata for the question",
463
+ "anyOf": [
464
+ {
465
+ "type": "object",
466
+ "propertyNames": {
467
+ "type": "string"
468
+ },
469
+ "additionalProperties": {
470
+ "anyOf": [
471
+ {
472
+ "type": "string"
473
+ },
474
+ {
475
+ "type": "number"
476
+ },
477
+ {
478
+ "type": "boolean"
479
+ },
480
+ {
481
+ "type": "null"
482
+ }
483
+ ]
484
+ }
485
+ },
486
+ {
487
+ "type": "null"
488
+ }
489
+ ]
490
+ },
491
+ "v": {
492
+ "description": "Version number, incremented when question is edited",
493
+ "anyOf": [
494
+ {
495
+ "type": "number"
496
+ },
497
+ {
498
+ "type": "null"
499
+ }
500
+ ]
501
+ },
502
+ "questionBankItemId": {
503
+ "description": "ID of the question in the question bank",
504
+ "anyOf": [
505
+ {
506
+ "type": "string"
507
+ },
508
+ {
509
+ "type": "null"
510
+ }
511
+ ]
512
+ },
513
+ "traceIds": {
514
+ "description": "Trace IDs for internal tracking of AI generation processes",
515
+ "anyOf": [
516
+ {
517
+ "type": "array",
518
+ "items": {
519
+ "type": "string"
520
+ }
521
+ },
522
+ {
523
+ "type": "null"
524
+ }
525
+ ]
526
+ }
527
+ },
528
+ "additionalProperties": {}
529
+ },
530
+ "expectedOutcome": {
531
+ "type": "boolean"
532
+ }
533
+ },
534
+ "required": [
535
+ "answer",
536
+ "question",
537
+ "expectedOutcome"
538
+ ],
539
+ "additionalProperties": false
540
+ }
541
+ }
542
+ },
543
+ "required": [
544
+ "condition"
545
+ ],
546
+ "additionalProperties": false,
547
+ "description": "Options for response processing"
548
+ },
119
549
  "scanning": {
120
550
  "type": "object",
121
551
  "properties": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@examplary/schemas",
3
3
  "packageManager": "yarn@4.8.1",
4
- "version": "1.15.1",
4
+ "version": "1.16.0",
5
5
  "description": "Schemas for the Examplary platform.",
6
6
  "scripts": {
7
7
  "build:schema": "tsx ./scripts/build.ts",