stagebook 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,1551 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ var _chunkI2WMGA4Qcjs = require('./chunk-I2WMGA4Q.cjs');
12
+
13
+ // src/schemas/treatment.ts
14
+ var _zod = require('zod');
15
+ var fieldPlaceholderSchema = _zod.z.string().regex(/\$\{[a-zA-Z0-9_]+\}/, {
16
+ message: "Field placeholder must be in the format `${fieldKey}` (alphanumeric and underscores only)"
17
+ });
18
+ var nameSchema = _zod.z.string().min(1, "Name is required").max(64).regex(/^(?:[a-zA-Z0-9 _-]|\$\{[a-zA-Z0-9_]+\})+$/, {
19
+ message: "Name must be alphanumeric, cannot have special characters, with optional template fields in the format ${fieldname}"
20
+ });
21
+ var descriptionSchema = _zod.z.string();
22
+ var fileSchema = _zod.z.string().optional();
23
+ var promptFilePathSchema = _zod.z.string().refine((s) => s.endsWith(".prompt.md"), {
24
+ message: 'Prompt files must use the .prompt.md extension (e.g., "myPrompt.prompt.md")'
25
+ });
26
+ var urlSchema = _zod.z.string().url().refine(
27
+ (url) => {
28
+ try {
29
+ const parsed = new URL(url);
30
+ return ["http:", "https:"].includes(parsed.protocol);
31
+ } catch (e2) {
32
+ return false;
33
+ }
34
+ },
35
+ { message: "URL must use http or https protocol" }
36
+ );
37
+ var durationSchema = _zod.z.number().int().positive();
38
+ var displayTimeSchema = _zod.z.number().int().nonnegative();
39
+ var hideTimeSchema = _zod.z.number().int().positive();
40
+ var positionSchema = _zod.z.number().int().nonnegative();
41
+ var positionSelectorSchema = _zod.z.enum(["shared", "player", "all", "any"]).or(positionSchema).default("player");
42
+ var showToPositionsSchema = _zod.z.array(positionSchema, {
43
+ required_error: "Expected an array for `showToPositions`. Make sure each item starts with a dash (`-`) in YAML.",
44
+ invalid_type_error: "Expected an array for `showToPositions`. Make sure each item starts with a dash (`-`) in YAML."
45
+ }).nonempty();
46
+ var hideFromPositionsSchema = _zod.z.array(positionSchema, {
47
+ required_error: "Expected an array for `hideFromPositions`. Make sure each item starts with a dash (`-`) in YAML.",
48
+ invalid_type_error: "Expected an array for `hideFromPositions`. Make sure each item starts with a dash (`-`) in YAML."
49
+ }).nonempty();
50
+ var displayRegionRangeSchema = _zod.z.object({
51
+ first: _zod.z.number().int().nonnegative(),
52
+ last: _zod.z.number().int().nonnegative()
53
+ }).strict().superRefine((value, ctx) => {
54
+ if (value.last < value.first) {
55
+ ctx.addIssue({
56
+ code: _zod.z.ZodIssueCode.custom,
57
+ message: "`last` must be greater than or equal to `first`."
58
+ });
59
+ }
60
+ });
61
+ var displayRegionAxisSchema = _zod.z.union([
62
+ _zod.z.number().int().nonnegative(),
63
+ displayRegionRangeSchema
64
+ ]);
65
+ var displayRegionSchema = _zod.z.object({
66
+ rows: displayRegionAxisSchema,
67
+ cols: displayRegionAxisSchema
68
+ }).strict();
69
+ var feedMediaSchema = _zod.z.object({
70
+ audio: _zod.z.boolean().optional(),
71
+ video: _zod.z.boolean().optional(),
72
+ screen: _zod.z.boolean().optional()
73
+ }).strict();
74
+ var participantSourceSchema = _zod.z.object({
75
+ type: _zod.z.literal("participant"),
76
+ position: positionSchema
77
+ }).strict();
78
+ var selfSourceSchema = _zod.z.object({
79
+ type: _zod.z.literal("self")
80
+ }).strict();
81
+ var otherSourceSchema = _zod.z.object({
82
+ type: _zod.z.string().min(1).refine(
83
+ (value) => value !== "participant" && value !== "self",
84
+ "Provide additional data using a different source type."
85
+ ),
86
+ position: _zod.z.union([positionSchema, _zod.z.string()]).optional()
87
+ }).strict();
88
+ var feedSourceSchema = _zod.z.union([
89
+ participantSourceSchema,
90
+ selfSourceSchema,
91
+ otherSourceSchema
92
+ ]);
93
+ var renderHintSchema = _zod.z.union([
94
+ _zod.z.literal("auto"),
95
+ _zod.z.literal("tile"),
96
+ _zod.z.literal("audioOnlyBadge"),
97
+ _zod.z.literal("hidden"),
98
+ _zod.z.string().min(1)
99
+ ]);
100
+ var feedOptionsSchema = _zod.z.record(_zod.z.string(), _zod.z.unknown());
101
+ var layoutFeedSchema = _zod.z.object({
102
+ source: feedSourceSchema,
103
+ media: feedMediaSchema.optional(),
104
+ displayRegion: displayRegionSchema,
105
+ zOrder: _zod.z.number().int().optional(),
106
+ render: renderHintSchema.optional(),
107
+ label: _zod.z.string().optional(),
108
+ options: feedOptionsSchema.optional()
109
+ }).strict();
110
+ var layoutFeedDefaultsSchema = _zod.z.object({
111
+ media: feedMediaSchema.optional(),
112
+ zOrder: _zod.z.number().int().optional(),
113
+ render: renderHintSchema.optional(),
114
+ label: _zod.z.string().optional(),
115
+ options: feedOptionsSchema.optional()
116
+ }).strict();
117
+ var layoutGridOptionsSchema = _zod.z.object({
118
+ gap: _zod.z.number().nonnegative().optional(),
119
+ background: _zod.z.string().optional()
120
+ }).strict();
121
+ var layoutGridSchema = _zod.z.object({
122
+ rows: _zod.z.number().int().positive(),
123
+ cols: _zod.z.number().int().positive(),
124
+ options: layoutGridOptionsSchema.optional()
125
+ }).strict();
126
+ var layoutDefinitionSchema = _zod.z.object({
127
+ grid: layoutGridSchema,
128
+ feeds: _zod.z.array(layoutFeedSchema).nonempty(),
129
+ defaults: layoutFeedDefaultsSchema.optional()
130
+ }).strict().superRefine((value, ctx) => {
131
+ const gridRows = value.grid.rows;
132
+ const gridCols = value.grid.cols;
133
+ value.feeds.forEach((feed, feedIndex) => {
134
+ const rows = typeof feed.displayRegion.rows === "number" ? { first: feed.displayRegion.rows, last: feed.displayRegion.rows } : feed.displayRegion.rows;
135
+ const cols = typeof feed.displayRegion.cols === "number" ? { first: feed.displayRegion.cols, last: feed.displayRegion.cols } : feed.displayRegion.cols;
136
+ if (rows.first >= gridRows || rows.last >= gridRows) {
137
+ ctx.addIssue({
138
+ code: _zod.z.ZodIssueCode.custom,
139
+ path: ["feeds", feedIndex, "displayRegion", "rows"],
140
+ message: "`rows` indices must be within the grid bounds."
141
+ });
142
+ }
143
+ if (cols.first >= gridCols || cols.last >= gridCols) {
144
+ ctx.addIssue({
145
+ code: _zod.z.ZodIssueCode.custom,
146
+ path: ["feeds", feedIndex, "displayRegion", "cols"],
147
+ message: "`cols` indices must be within the grid bounds."
148
+ });
149
+ }
150
+ });
151
+ });
152
+ var layoutBySeatSchema = _zod.z.record(_zod.z.string(), layoutDefinitionSchema).superRefine((value, ctx) => {
153
+ Object.keys(value).forEach((key) => {
154
+ const seat = Number(key);
155
+ if (!Number.isInteger(seat) || seat < 0) {
156
+ ctx.addIssue({
157
+ code: _zod.z.ZodIssueCode.custom,
158
+ path: [key],
159
+ message: "Layout keys must be zero-based nonnegative integers."
160
+ });
161
+ }
162
+ });
163
+ });
164
+ var discussionRoomSchema = _zod.z.object({
165
+ includePositions: _zod.z.array(positionSchema, {
166
+ required_error: "Expected an array for `includePositions`. Make sure each item starts with a dash (`-`) in YAML.",
167
+ invalid_type_error: "Expected an array for `includePositions`. Make sure each item starts with a dash (`-`) in YAML."
168
+ }).nonempty()
169
+ }).strict();
170
+ var discussionSchema = _zod.z.object({
171
+ chatType: _zod.z.enum(["text", "audio", "video"]),
172
+ showNickname: _zod.z.boolean(),
173
+ showTitle: _zod.z.boolean(),
174
+ showSelfView: _zod.z.boolean().optional().default(true),
175
+ showReportMissing: _zod.z.boolean().optional().default(true),
176
+ showAudioMute: _zod.z.boolean().optional().default(true),
177
+ showVideoMute: _zod.z.boolean().optional().default(true),
178
+ reactionEmojisAvailable: _zod.z.array(_zod.z.string()).optional(),
179
+ reactToSelf: _zod.z.boolean().optional(),
180
+ numReactionsPerMessage: _zod.z.number().int().nonnegative().optional(),
181
+ layout: layoutBySeatSchema.optional(),
182
+ rooms: _zod.z.array(discussionRoomSchema).nonempty().optional(),
183
+ // New: allow discussion-level position-based visibility controls
184
+ showToPositions: showToPositionsSchema.optional(),
185
+ hideFromPositions: hideFromPositionsSchema.optional(),
186
+ conditions: _zod.z.lazy(() => conditionsSchema).optional()
187
+ }).strict().superRefine((data, ctx) => {
188
+ if (data.chatType !== "text") {
189
+ if (data.reactionEmojisAvailable !== void 0) {
190
+ ctx.addIssue({
191
+ code: _zod.z.ZodIssueCode.custom,
192
+ path: ["reactionEmojisAvailable"],
193
+ message: "reactionEmojisAvailable can only be used with chatType 'text'"
194
+ });
195
+ }
196
+ if (data.reactToSelf !== void 0) {
197
+ ctx.addIssue({
198
+ code: _zod.z.ZodIssueCode.custom,
199
+ path: ["reactToSelf"],
200
+ message: "reactToSelf can only be used with chatType 'text'"
201
+ });
202
+ }
203
+ if (data.numReactionsPerMessage !== void 0) {
204
+ ctx.addIssue({
205
+ code: _zod.z.ZodIssueCode.custom,
206
+ path: ["numReactionsPerMessage"],
207
+ message: "numReactionsPerMessage can only be used with chatType 'text'"
208
+ });
209
+ }
210
+ }
211
+ if (data.layout !== void 0 && data.chatType !== "video") {
212
+ ctx.addIssue({
213
+ code: _zod.z.ZodIssueCode.custom,
214
+ path: ["layout"],
215
+ message: "layout can only be used with chatType 'video'"
216
+ });
217
+ }
218
+ if (data.rooms !== void 0 && data.chatType !== "video") {
219
+ ctx.addIssue({
220
+ code: _zod.z.ZodIssueCode.custom,
221
+ path: ["rooms"],
222
+ message: "rooms can only be used with chatType 'video'"
223
+ });
224
+ }
225
+ });
226
+ var templateFieldKeysSchema = _zod.z.string().regex(/^(?!d[0-9]+$)([a-zA-Z0-9_]+|\$\{[a-zA-Z0-9_]+\})$/, {
227
+ message: "Field key must be alphanumeric with underscores only (no hyphens or spaces), or a placeholder `${fieldKey}`. Cannot conflict with reserved keys (d0, d1, etc.)."
228
+ }).min(1).superRefine((val, ctx) => {
229
+ if (val == "type") {
230
+ ctx.addIssue({
231
+ code: _zod.z.ZodIssueCode.custom,
232
+ message: "Field key cannot be 'type', as it is reserved for element types."
233
+ });
234
+ }
235
+ });
236
+ var templateFieldsSchema = _zod.z.record(templateFieldKeysSchema, _zod.z.any());
237
+ var templateBroadcastAxisNameSchema = _zod.z.string().regex(/^d\d+$/, {
238
+ message: "String must start with 'd' followed by a nonnegative integer"
239
+ });
240
+ var templateBroadcastAxisValuesSchema = _zod.z.lazy(
241
+ () => _zod.z.array(templateFieldsSchema).nonempty().or(templateContextSchema).or(templateFieldKeysSchema)
242
+ );
243
+ var templateContextSchema = _zod.z.object({
244
+ template: nameSchema,
245
+ fields: templateFieldsSchema.optional(),
246
+ broadcast: _zod.z.record(
247
+ templateBroadcastAxisNameSchema,
248
+ templateBroadcastAxisValuesSchema
249
+ ).optional()
250
+ }).strict();
251
+ function altTemplateContext(baseSchema) {
252
+ return _zod.z.any().superRefine((data, ctx) => {
253
+ if (data === void 0) {
254
+ return;
255
+ }
256
+ const schemaToUse = data !== null && typeof data === "object" && "template" in data ? templateContextSchema : baseSchema;
257
+ const result = schemaToUse.safeParse(data);
258
+ if (!result.success) {
259
+ result.error.issues.forEach(
260
+ (issue) => ctx.addIssue({
261
+ ...issue,
262
+ path: [...issue.path]
263
+ })
264
+ );
265
+ }
266
+ });
267
+ }
268
+ var referenceSchema = _zod.z.string().transform((str) => str.split(".")).superRefine((arr, ctx) => {
269
+ const [givenType] = arr;
270
+ let name;
271
+ let path;
272
+ switch (givenType) {
273
+ case "survey":
274
+ case "submitButton":
275
+ case "qualtrics":
276
+ [, name, ...path] = arr;
277
+ if (path.length < 1) {
278
+ ctx.addIssue({
279
+ code: _zod.z.ZodIssueCode.custom,
280
+ message: `A path must be provided, e.g. '${givenType}.${name}.object.selectors.here'`,
281
+ path: []
282
+ });
283
+ }
284
+ if (name === void 0 || name.length < 1) {
285
+ ctx.addIssue({
286
+ code: _zod.z.ZodIssueCode.custom,
287
+ message: `A name must be provided, e.g. '${givenType}.elementName.object.selectors.here'`,
288
+ path: []
289
+ });
290
+ }
291
+ break;
292
+ case "discussion":
293
+ case "participantInfo":
294
+ case "prompt":
295
+ case "trackedLink":
296
+ [, name] = arr;
297
+ if (name === void 0 || name.length < 1) {
298
+ ctx.addIssue({
299
+ code: _zod.z.ZodIssueCode.custom,
300
+ message: `A name must be provided, e.g. '${givenType}.elementName'`,
301
+ path: []
302
+ });
303
+ }
304
+ break;
305
+ case "urlParams":
306
+ case "connectionInfo":
307
+ case "browserInfo":
308
+ [, ...path] = arr;
309
+ if (path.length < 1) {
310
+ ctx.addIssue({
311
+ code: _zod.z.ZodIssueCode.custom,
312
+ message: `A path must be provided, e.g. '${givenType}.object.selectors.here.`,
313
+ path: []
314
+ });
315
+ }
316
+ break;
317
+ default:
318
+ ctx.addIssue({
319
+ code: _zod.z.ZodIssueCode.custom,
320
+ message: `Invalid reference type "${givenType}", need to be in form of a valid reference type such as 'survey', 'submitButton', 'qualtrics', 'discussion', 'participantInfo', 'prompt', 'urlParams', 'connectionInfo', or 'browserInfo' followed by a . and name or path.`,
321
+ path: []
322
+ });
323
+ }
324
+ });
325
+ var baseConditionSchema = _zod.z.object({
326
+ reference: referenceSchema,
327
+ position: _zod.z.enum(["shared", "player", "all", "any", "percentAgreement"]).or(_zod.z.number().nonnegative().int()).optional()
328
+ }).strict();
329
+ var conditionExistsSchema = baseConditionSchema.extend({
330
+ comparator: _zod.z.literal("exists"),
331
+ value: _zod.z.undefined()
332
+ }).strict();
333
+ var conditionDoesNotExistSchema = baseConditionSchema.extend({
334
+ comparator: _zod.z.literal("doesNotExist"),
335
+ value: _zod.z.undefined()
336
+ }).strict();
337
+ var conditionEqualsSchema = baseConditionSchema.extend({
338
+ comparator: _zod.z.literal("equals"),
339
+ value: _zod.z.string().or(_zod.z.number()).or(_zod.z.boolean()).or(fieldPlaceholderSchema)
340
+ }).strict();
341
+ var conditionDoesNotEqualSchema = baseConditionSchema.extend({
342
+ comparator: _zod.z.literal("doesNotEqual"),
343
+ value: _zod.z.string().or(_zod.z.number()).or(_zod.z.boolean()).or(fieldPlaceholderSchema)
344
+ }).strict();
345
+ var conditionIsAboveSchema = baseConditionSchema.extend({
346
+ comparator: _zod.z.literal("isAbove"),
347
+ value: _zod.z.number().or(fieldPlaceholderSchema)
348
+ }).strict();
349
+ var conditionIsBelowSchema = baseConditionSchema.extend({
350
+ comparator: _zod.z.literal("isBelow"),
351
+ value: _zod.z.number().or(fieldPlaceholderSchema)
352
+ }).strict();
353
+ var conditionIsAtLeastSchema = baseConditionSchema.extend({
354
+ comparator: _zod.z.literal("isAtLeast"),
355
+ value: _zod.z.number().or(fieldPlaceholderSchema)
356
+ }).strict();
357
+ var conditionIsAtMostSchema = baseConditionSchema.extend({
358
+ comparator: _zod.z.literal("isAtMost"),
359
+ value: _zod.z.number().or(fieldPlaceholderSchema)
360
+ }).strict();
361
+ var conditionHasLengthAtLeastSchema = baseConditionSchema.extend({
362
+ comparator: _zod.z.literal("hasLengthAtLeast"),
363
+ value: _zod.z.number().nonnegative().int().or(fieldPlaceholderSchema)
364
+ }).strict();
365
+ var conditionHasLengthAtMostSchema = baseConditionSchema.extend({
366
+ comparator: _zod.z.literal("hasLengthAtMost"),
367
+ value: _zod.z.number().nonnegative().int().or(fieldPlaceholderSchema)
368
+ }).strict();
369
+ var conditionIncludesSchema = baseConditionSchema.extend({
370
+ comparator: _zod.z.literal("includes"),
371
+ value: _zod.z.string().or(fieldPlaceholderSchema)
372
+ }).strict();
373
+ var conditionDoesNotIncludeSchema = baseConditionSchema.extend({
374
+ comparator: _zod.z.literal("doesNotInclude"),
375
+ value: _zod.z.string().or(fieldPlaceholderSchema)
376
+ }).strict();
377
+ var conditionMatchesSchema = baseConditionSchema.extend({
378
+ comparator: _zod.z.literal("matches"),
379
+ value: _zod.z.string().or(fieldPlaceholderSchema)
380
+ }).strict();
381
+ var conditionDoesNotMatchSchema = baseConditionSchema.extend({
382
+ comparator: _zod.z.literal("doesNotMatch"),
383
+ value: _zod.z.string().or(fieldPlaceholderSchema)
384
+ }).strict();
385
+ var conditionIsOneOfSchema = baseConditionSchema.extend({
386
+ comparator: _zod.z.literal("isOneOf"),
387
+ value: _zod.z.array(_zod.z.string().or(_zod.z.number())).nonempty().or(fieldPlaceholderSchema)
388
+ }).strict();
389
+ var conditionIsNotOneOfSchema = baseConditionSchema.extend({
390
+ comparator: _zod.z.literal("isNotOneOf"),
391
+ value: _zod.z.array(_zod.z.string().or(_zod.z.number())).nonempty().or(fieldPlaceholderSchema)
392
+ }).strict();
393
+ var conditionSchema = altTemplateContext(
394
+ _zod.z.discriminatedUnion("comparator", [
395
+ conditionExistsSchema,
396
+ conditionDoesNotExistSchema,
397
+ conditionEqualsSchema,
398
+ conditionDoesNotEqualSchema,
399
+ conditionIsAboveSchema,
400
+ conditionIsBelowSchema,
401
+ conditionIsAtLeastSchema,
402
+ conditionIsAtMostSchema,
403
+ conditionHasLengthAtLeastSchema,
404
+ conditionHasLengthAtMostSchema,
405
+ conditionIncludesSchema,
406
+ conditionDoesNotIncludeSchema,
407
+ conditionMatchesSchema,
408
+ conditionDoesNotMatchSchema,
409
+ conditionIsOneOfSchema,
410
+ conditionIsNotOneOfSchema
411
+ ])
412
+ );
413
+ var conditionsSchema = altTemplateContext(
414
+ _zod.z.array(conditionSchema, {
415
+ required_error: "Expected an array for `conditions`. Make sure each item starts with a dash (`-`) in YAML.",
416
+ invalid_type_error: "Expected an array for `conditions`. Make sure each item starts with a dash (`-`) in YAML."
417
+ }).nonempty()
418
+ );
419
+ var playerSchema = _zod.z.object({
420
+ desc: descriptionSchema.optional(),
421
+ position: positionSchema,
422
+ title: _zod.z.string().max(25).optional(),
423
+ conditions: _zod.z.array(conditionSchema, {
424
+ invalid_type_error: "Expected an array for `conditions`. Make sure each item starts with a dash (`-`) in YAML."
425
+ }).optional()
426
+ }).strict();
427
+ var elementBaseSchema = _zod.z.object({
428
+ name: nameSchema.optional(),
429
+ desc: descriptionSchema.optional(),
430
+ file: fileSchema.or(fieldPlaceholderSchema).optional(),
431
+ displayTime: displayTimeSchema.or(fieldPlaceholderSchema).optional(),
432
+ hideTime: hideTimeSchema.or(fieldPlaceholderSchema).optional(),
433
+ showToPositions: showToPositionsSchema.or(fieldPlaceholderSchema).optional(),
434
+ hideFromPositions: hideFromPositionsSchema.or(fieldPlaceholderSchema).optional(),
435
+ conditions: conditionsSchema.optional(),
436
+ tags: _zod.z.array(_zod.z.string(), {
437
+ invalid_type_error: "Expected an array for `tags`. Make sure each item starts with a dash (`-`) in YAML."
438
+ }).optional()
439
+ }).strict();
440
+ var audioSchema = elementBaseSchema.extend({
441
+ type: _zod.z.literal("audio"),
442
+ file: fileSchema
443
+ // Todo: check that file exists
444
+ }).strict();
445
+ var imageSchema = elementBaseSchema.extend({
446
+ type: _zod.z.literal("image"),
447
+ file: fileSchema
448
+ // Todo: check that file exists
449
+ }).strict();
450
+ var displaySchema = elementBaseSchema.extend({
451
+ type: _zod.z.literal("display"),
452
+ reference: referenceSchema,
453
+ position: positionSelectorSchema
454
+ }).strict();
455
+ var promptSchema = elementBaseSchema.extend({
456
+ type: _zod.z.literal("prompt"),
457
+ file: promptFilePathSchema,
458
+ shared: _zod.z.boolean().optional()
459
+ }).strict();
460
+ var promptShorthandSchema = promptFilePathSchema.transform((str) => {
461
+ const newElement = {
462
+ type: "prompt",
463
+ file: str,
464
+ name: str
465
+ };
466
+ return newElement;
467
+ });
468
+ var separatorSchema = elementBaseSchema.extend({
469
+ type: _zod.z.literal("separator"),
470
+ style: _zod.z.enum(["thin", "thick", "regular"]).optional()
471
+ }).strict();
472
+ var sharedNotepadSchema = elementBaseSchema.extend({
473
+ type: _zod.z.literal("sharedNotepad")
474
+ }).strict();
475
+ var submitButtonSchema = elementBaseSchema.extend({
476
+ type: _zod.z.literal("submitButton"),
477
+ buttonText: _zod.z.string().max(50).optional()
478
+ }).strict();
479
+ var surveySchema = elementBaseSchema.extend({
480
+ type: _zod.z.literal("survey"),
481
+ surveyName: _zod.z.string()
482
+ // Todo: check that surveyName is a valid survey name
483
+ }).strict();
484
+ var talkMeterSchema = elementBaseSchema.extend({
485
+ type: _zod.z.literal("talkMeter")
486
+ }).strict();
487
+ var timerSchema = elementBaseSchema.extend({
488
+ type: _zod.z.literal("timer"),
489
+ startTime: _zod.z.number().gt(0).optional(),
490
+ endTime: _zod.z.number().gt(0).optional(),
491
+ warnTimeRemaining: _zod.z.number().gt(0).optional()
492
+ // Todo: check that startTime < endTime
493
+ // Todo: check that warnTimeRemaining < endTime - startTime
494
+ }).strict();
495
+ var mediaPlayerControlsSchema = _zod.z.object({
496
+ playPause: _zod.z.boolean().optional(),
497
+ seek: _zod.z.boolean().optional(),
498
+ step: _zod.z.boolean().optional(),
499
+ speed: _zod.z.boolean().optional()
500
+ }).strict().optional();
501
+ var mediaPlayerSchema = elementBaseSchema.extend({
502
+ type: _zod.z.literal("mediaPlayer"),
503
+ url: _zod.z.string(),
504
+ playVideo: _zod.z.boolean().optional(),
505
+ playAudio: _zod.z.boolean().optional(),
506
+ captionsFile: _zod.z.string().optional(),
507
+ startAt: _zod.z.number().nonnegative().optional(),
508
+ stopAt: _zod.z.number().positive().optional(),
509
+ allowScrubOutsideBounds: _zod.z.boolean().optional(),
510
+ stepDuration: _zod.z.number().positive().optional(),
511
+ syncToStageTime: _zod.z.boolean().optional(),
512
+ submitOnComplete: _zod.z.boolean().optional(),
513
+ controls: mediaPlayerControlsSchema
514
+ }).strict();
515
+ var timelineSchema = elementBaseSchema.extend({
516
+ type: _zod.z.literal("timeline"),
517
+ source: nameSchema,
518
+ name: nameSchema,
519
+ selectionType: _zod.z.enum(["range", "point"]),
520
+ selectionScope: _zod.z.enum(["track", "all"]).optional(),
521
+ multiSelect: _zod.z.boolean().optional(),
522
+ showWaveform: _zod.z.boolean().optional(),
523
+ trackLabels: _zod.z.array(_zod.z.string(), {
524
+ invalid_type_error: "Expected an array for `trackLabels`. Make sure each item starts with a dash (`-`) in YAML."
525
+ }).optional()
526
+ }).strict();
527
+ var trackedLinkParamSchema = _zod.z.object({
528
+ key: _zod.z.string().min(1),
529
+ value: _zod.z.union([_zod.z.string(), _zod.z.number(), _zod.z.boolean(), fieldPlaceholderSchema]).optional(),
530
+ reference: referenceSchema.optional(),
531
+ position: positionSelectorSchema.optional()
532
+ }).strict().superRefine((data, ctx) => {
533
+ if (data.value !== void 0 && data.reference !== void 0) {
534
+ ctx.addIssue({
535
+ code: _zod.z.ZodIssueCode.custom,
536
+ message: "Provide either `value` or `reference`, not both.",
537
+ path: ["value"]
538
+ });
539
+ }
540
+ });
541
+ var qualtricsSchema = elementBaseSchema.extend({
542
+ type: _zod.z.literal("qualtrics"),
543
+ url: urlSchema,
544
+ urlParams: _zod.z.array(trackedLinkParamSchema, {
545
+ invalid_type_error: "Expected an array for `urlParams`. Make sure each item starts with a dash (`-`) in YAML."
546
+ }).optional()
547
+ }).strict();
548
+ var trackedLinkSchema = elementBaseSchema.extend({
549
+ type: _zod.z.literal("trackedLink"),
550
+ name: nameSchema,
551
+ url: urlSchema,
552
+ displayText: _zod.z.string().min(1),
553
+ helperText: _zod.z.string().optional(),
554
+ urlParams: _zod.z.array(trackedLinkParamSchema, {
555
+ invalid_type_error: "Expected an array for `urlParams`. Make sure each item starts with a dash (`-`) in YAML."
556
+ }).optional()
557
+ }).strict();
558
+ var elementSchema = altTemplateContext(
559
+ _zod.z.any().superRefine((data, ctx) => {
560
+ const isObject = typeof data === "object" && data !== null;
561
+ const hasTypeKey = isObject && "type" in data;
562
+ const schemaToUse = hasTypeKey ? _zod.z.discriminatedUnion("type", [
563
+ audioSchema,
564
+ displaySchema,
565
+ imageSchema,
566
+ promptSchema,
567
+ qualtricsSchema,
568
+ separatorSchema,
569
+ sharedNotepadSchema,
570
+ submitButtonSchema,
571
+ surveySchema,
572
+ talkMeterSchema,
573
+ timerSchema,
574
+ mediaPlayerSchema,
575
+ timelineSchema,
576
+ trackedLinkSchema
577
+ ]) : promptShorthandSchema;
578
+ const result = schemaToUse.safeParse(data);
579
+ if (!result.success) {
580
+ if (!hasTypeKey && isObject && schemaToUse === promptShorthandSchema) {
581
+ ctx.addIssue({
582
+ code: "invalid_type",
583
+ expected: "string",
584
+ received: "object",
585
+ message: `promptShorthandSchema expects a string, but received object.`
586
+ });
587
+ for (const key of Object.keys(data)) {
588
+ ctx.addIssue({
589
+ code: "unrecognized_keys",
590
+ keys: [key]
591
+ });
592
+ }
593
+ } else {
594
+ result.error.issues.forEach(
595
+ (issue) => ctx.addIssue({
596
+ ...issue,
597
+ path: [...issue.path]
598
+ })
599
+ );
600
+ }
601
+ }
602
+ if (isObject && data.type === "mediaPlayer" && result.success) {
603
+ const mp = data;
604
+ if (mp.startAt !== void 0 && mp.stopAt !== void 0 && mp.stopAt <= mp.startAt) {
605
+ ctx.addIssue({
606
+ code: _zod.z.ZodIssueCode.custom,
607
+ message: "stopAt must be greater than startAt",
608
+ path: ["stopAt"]
609
+ });
610
+ }
611
+ const mpSync = data;
612
+ if (mpSync.syncToStageTime && mpSync.controls) {
613
+ ctx.addIssue({
614
+ code: _zod.z.ZodIssueCode.custom,
615
+ message: "controls cannot be specified when syncToStageTime is true (playback is locked to stage time)",
616
+ path: ["controls"]
617
+ });
618
+ }
619
+ }
620
+ })
621
+ );
622
+ var elementsSchema = altTemplateContext(
623
+ _zod.z.array(elementSchema, {
624
+ required_error: "Expected an array for `elements`. Make sure each item starts with a dash (`-`) in YAML.",
625
+ invalid_type_error: "Expected an array for `elements`. Make sure each item starts with a dash (`-`) in YAML."
626
+ }).nonempty()
627
+ );
628
+ var stageSchema = altTemplateContext(
629
+ _zod.z.object({
630
+ name: nameSchema,
631
+ desc: descriptionSchema.optional(),
632
+ discussion: discussionSchema.optional(),
633
+ duration: durationSchema.or(fieldPlaceholderSchema),
634
+ elements: elementsSchema
635
+ }).strict().superRefine((data, ctx) => {
636
+ if (!data.elements) {
637
+ ctx.addIssue({
638
+ code: _zod.z.ZodIssueCode.custom,
639
+ message: "Stage must have elements field (check elementsSchema)."
640
+ });
641
+ }
642
+ const duration = data.duration;
643
+ if (typeof duration !== "number" || !Array.isArray(data.elements)) return;
644
+ data.elements.forEach(
645
+ (element, elementIndex) => {
646
+ if (!element || typeof element !== "object") return;
647
+ const timeFields = [
648
+ "displayTime",
649
+ "hideTime",
650
+ "startTime",
651
+ "endTime"
652
+ ];
653
+ for (const field of timeFields) {
654
+ const value = element[field];
655
+ if (typeof value === "number" && value > duration) {
656
+ ctx.addIssue({
657
+ code: _zod.z.ZodIssueCode.custom,
658
+ path: ["elements", elementIndex, field],
659
+ message: `${field} (${value}) exceeds stage duration (${duration}) for element "${String(element.name || element.type)}"`
660
+ });
661
+ }
662
+ }
663
+ }
664
+ );
665
+ })
666
+ );
667
+ var stagesSchema = altTemplateContext(
668
+ _zod.z.array(stageSchema, {
669
+ required_error: "Expected an array for `stages`. Make sure each item starts with a dash (`-`) in YAML.",
670
+ invalid_type_error: "Expected an array for `stages`. Make sure each item starts with a dash (`-`) in YAML."
671
+ }).nonempty()
672
+ );
673
+ var introExitStepSchema = altTemplateContext(
674
+ _zod.z.object({
675
+ name: nameSchema,
676
+ desc: descriptionSchema.optional(),
677
+ elements: elementsSchema
678
+ }).strict()
679
+ );
680
+ var introExitStepsBaseSchema = altTemplateContext(
681
+ _zod.z.array(introExitStepSchema, {
682
+ required_error: "Expected an array for `introSteps`. Make sure each item starts with a dash (`-`) in YAML.",
683
+ invalid_type_error: "Expected an array for `introSteps`. Make sure each item starts with a dash (`-`) in YAML."
684
+ }).nonempty()
685
+ );
686
+ var introExitStepsSchema = introExitStepsBaseSchema;
687
+ function isAdvancementElement(element) {
688
+ if (!element || typeof element !== "object") return false;
689
+ const el = element;
690
+ if (el.type === "submitButton") return true;
691
+ if (el.type === "survey") return true;
692
+ if (el.type === "qualtrics") return true;
693
+ if (el.type === "mediaPlayer" && el.submitOnComplete === true) return true;
694
+ return false;
695
+ }
696
+ var introStepsSchema = introExitStepsBaseSchema.superRefine(
697
+ (data, ctx) => {
698
+ _optionalChain([data, 'optionalAccess', _2 => _2.forEach, 'call', _3 => _3((step, stepIdx) => {
699
+ if (Array.isArray(step.elements)) {
700
+ step.elements.forEach((element, elementIdx) => {
701
+ if (element && typeof element === "object" && "shared" in element && element.shared) {
702
+ ctx.addIssue({
703
+ code: _zod.z.ZodIssueCode.custom,
704
+ path: [stepIdx, "elements", elementIdx, "shared"],
705
+ message: `Prompt element in intro/exit steps cannot be shared.`
706
+ });
707
+ }
708
+ if (element && typeof element === "object" && "position" in element) {
709
+ ctx.addIssue({
710
+ code: _zod.z.ZodIssueCode.custom,
711
+ path: [stepIdx, "elements", elementIdx, "position"],
712
+ message: `Elements in intro steps cannot have a 'position' field.`
713
+ });
714
+ }
715
+ if (element && typeof element === "object" && "showToPositions" in element) {
716
+ ctx.addIssue({
717
+ code: _zod.z.ZodIssueCode.custom,
718
+ path: [stepIdx, "elements", elementIdx],
719
+ message: `Elements in intro steps cannot have a 'showToPositions' field.`
720
+ });
721
+ }
722
+ if (element && typeof element === "object" && "hideFromPositions" in element) {
723
+ ctx.addIssue({
724
+ code: _zod.z.ZodIssueCode.custom,
725
+ path: [stepIdx, "elements", elementIdx],
726
+ message: `Elements in intro steps cannot have a 'hideFromPositions' field.`
727
+ });
728
+ }
729
+ });
730
+ if (!step.elements.some(isAdvancementElement)) {
731
+ ctx.addIssue({
732
+ code: _zod.z.ZodIssueCode.custom,
733
+ path: [stepIdx, "elements"],
734
+ message: "Intro/exit step must include at least one advancement element: submitButton, survey, qualtrics, or mediaPlayer with submitOnComplete: true."
735
+ });
736
+ }
737
+ }
738
+ })]);
739
+ }
740
+ );
741
+ var exitStepsSchema = introExitStepsBaseSchema.superRefine(
742
+ (data, ctx) => {
743
+ _optionalChain([data, 'optionalAccess', _4 => _4.forEach, 'call', _5 => _5((step, stepIdx) => {
744
+ if (Array.isArray(step.elements)) {
745
+ step.elements.forEach((element, elementIdx) => {
746
+ if (element && typeof element === "object" && "shared" in element && element.shared) {
747
+ ctx.addIssue({
748
+ code: _zod.z.ZodIssueCode.custom,
749
+ path: [stepIdx, "elements", elementIdx, "shared"],
750
+ message: `Prompt element in intro/exit steps cannot be shared.`
751
+ });
752
+ }
753
+ });
754
+ if (!step.elements.some(isAdvancementElement)) {
755
+ ctx.addIssue({
756
+ code: _zod.z.ZodIssueCode.custom,
757
+ path: [stepIdx, "elements"],
758
+ message: "Intro/exit step must include at least one advancement element: submitButton, survey, qualtrics, or mediaPlayer with submitOnComplete: true."
759
+ });
760
+ }
761
+ }
762
+ })]);
763
+ }
764
+ );
765
+ var introSequenceSchema = altTemplateContext(
766
+ _zod.z.object({
767
+ name: nameSchema,
768
+ desc: descriptionSchema.optional(),
769
+ introSteps: introStepsSchema
770
+ }).strict()
771
+ );
772
+ var introSequencesSchema = altTemplateContext(
773
+ _zod.z.array(introSequenceSchema, {
774
+ required_error: "Expected an array for `introSequence`. Make sure each item starts with a dash (`-`) in YAML.",
775
+ invalid_type_error: "Expected an array for `introSequence`. Make sure each item starts with a dash (`-`) in YAML."
776
+ }).nonempty()
777
+ );
778
+ var baseTreatmentSchema = _zod.z.object({
779
+ name: nameSchema,
780
+ desc: descriptionSchema.optional(),
781
+ playerCount: _zod.z.number(),
782
+ groupComposition: _zod.z.array(playerSchema, {
783
+ invalid_type_error: "Expected an array for `groupComposition`. Make sure each item starts with a dash (`-`) in YAML."
784
+ }).optional(),
785
+ gameStages: stagesSchema,
786
+ exitSequence: exitStepsSchema.optional()
787
+ }).strict();
788
+ var treatmentSchema = altTemplateContext(
789
+ baseTreatmentSchema.superRefine((treatment, ctx) => {
790
+ const baseResult = baseTreatmentSchema.safeParse(treatment);
791
+ if (!baseResult.success) {
792
+ return;
793
+ }
794
+ const { playerCount, groupComposition, gameStages } = treatment;
795
+ _optionalChain([groupComposition, 'optionalAccess', _6 => _6.forEach, 'call', _7 => _7((player, index) => {
796
+ if (typeof player.position === "number" && player.position >= playerCount) {
797
+ ctx.addIssue({
798
+ code: _zod.z.ZodIssueCode.custom,
799
+ path: ["groupComposition", index, "position"],
800
+ message: `Player position index ${player.position} in groupComposition exceeds playerCount of ${playerCount}.`
801
+ });
802
+ }
803
+ })]);
804
+ if (groupComposition) {
805
+ const positions = groupComposition.map((player) => player.position).filter((pos) => typeof pos === "number");
806
+ const uniquePositions = new Set(positions);
807
+ if (uniquePositions.size !== positions.length) {
808
+ ctx.addIssue({
809
+ code: _zod.z.ZodIssueCode.custom,
810
+ path: ["groupComposition"],
811
+ message: `Player positions in groupComposition must be unique.`
812
+ });
813
+ }
814
+ const expectedPositions = Array.from(
815
+ { length: playerCount },
816
+ (_, i) => i
817
+ );
818
+ const missingPositions = expectedPositions.filter(
819
+ (pos) => !uniquePositions.has(pos)
820
+ );
821
+ if (missingPositions.length > 0) {
822
+ ctx.addIssue({
823
+ code: _zod.z.ZodIssueCode.custom,
824
+ path: ["groupComposition"],
825
+ message: `Player positions in groupComposition must include all nonnegative integers below playerCount (${playerCount}). Missing: ${missingPositions.join(", ")}.`
826
+ });
827
+ }
828
+ }
829
+ _optionalChain([gameStages, 'optionalAccess', _8 => _8.forEach, 'call', _9 => _9(
830
+ (stage, stageIndex) => {
831
+ _optionalChain([stage, 'optionalAccess', _10 => _10.elements, 'optionalAccess', _11 => _11.forEach, 'call', _12 => _12(
832
+ (element, elementIndex) => {
833
+ ["showToPositions", "hideFromPositions"].forEach((key) => {
834
+ const positions = element[key];
835
+ if (Array.isArray(positions)) {
836
+ _optionalChain([positions, 'optionalAccess', _13 => _13.forEach, 'call', _14 => _14((pos, posIndex) => {
837
+ if (typeof pos === "number" && pos >= playerCount) {
838
+ ctx.addIssue({
839
+ code: _zod.z.ZodIssueCode.custom,
840
+ path: [
841
+ "gameStages",
842
+ stageIndex,
843
+ "elements",
844
+ elementIndex,
845
+ key,
846
+ posIndex
847
+ ],
848
+ message: `${key} index ${pos} in stage "${stage.name}" exceeds playerCount of ${playerCount}.`
849
+ });
850
+ }
851
+ })]);
852
+ }
853
+ });
854
+ }
855
+ )]);
856
+ const discussion = _optionalChain([stage, 'optionalAccess', _15 => _15.discussion]);
857
+ if (discussion) {
858
+ ["showToPositions", "hideFromPositions"].forEach((key) => {
859
+ const positions = _optionalChain([discussion, 'optionalAccess', _16 => _16[key]]);
860
+ if (Array.isArray(positions)) {
861
+ positions.forEach((pos, posIndex) => {
862
+ if (typeof pos === "number" && pos >= playerCount) {
863
+ ctx.addIssue({
864
+ code: _zod.z.ZodIssueCode.custom,
865
+ path: [
866
+ "gameStages",
867
+ stageIndex,
868
+ "discussion",
869
+ key,
870
+ posIndex
871
+ ],
872
+ message: `${key} index ${pos} in discussion of stage "${stage.name}" exceeds playerCount of ${playerCount}.`
873
+ });
874
+ }
875
+ });
876
+ }
877
+ });
878
+ const { rooms, showToPositions, hideFromPositions } = discussion || {};
879
+ if (Array.isArray(rooms) && rooms.length > 0) {
880
+ const allPositions = Array.from(
881
+ { length: playerCount },
882
+ (_, i) => i
883
+ );
884
+ let candidatePositions = allPositions;
885
+ if (Array.isArray(showToPositions) && showToPositions.length > 0) {
886
+ candidatePositions = candidatePositions.filter(
887
+ (p) => showToPositions.includes(p)
888
+ );
889
+ }
890
+ if (Array.isArray(hideFromPositions) && hideFromPositions.length > 0) {
891
+ candidatePositions = candidatePositions.filter(
892
+ (p) => !hideFromPositions.includes(p)
893
+ );
894
+ }
895
+ const assigned = /* @__PURE__ */ new Set();
896
+ rooms.forEach(
897
+ (room, roomIndex) => {
898
+ const inc = _optionalChain([room, 'optionalAccess', _17 => _17.includePositions]);
899
+ if (Array.isArray(inc)) {
900
+ inc.forEach((pos, posIndex) => {
901
+ if (typeof pos === "number") {
902
+ assigned.add(pos);
903
+ if (pos >= playerCount) {
904
+ ctx.addIssue({
905
+ code: _zod.z.ZodIssueCode.custom,
906
+ path: [
907
+ "gameStages",
908
+ stageIndex,
909
+ "discussion",
910
+ "rooms",
911
+ roomIndex,
912
+ "includePositions",
913
+ posIndex
914
+ ],
915
+ message: `includePositions index ${pos} in discussion room exceeds playerCount of ${playerCount}.`
916
+ });
917
+ }
918
+ }
919
+ });
920
+ }
921
+ }
922
+ );
923
+ const missing = candidatePositions.filter(
924
+ (p) => !assigned.has(p)
925
+ );
926
+ if (missing.length > 0) {
927
+ ctx.addIssue({
928
+ code: _zod.z.ZodIssueCode.custom,
929
+ path: ["gameStages", stageIndex, "discussion", "rooms"],
930
+ message: `Rooms defined but the following visible player positions are not assigned to any room: ${missing.join(
931
+ ", "
932
+ )}. Each visible position (respecting showToPositions/hideFromPositions) must appear in one includePositions array.`
933
+ });
934
+ }
935
+ }
936
+ }
937
+ }
938
+ )]);
939
+ })
940
+ );
941
+ var treatmentsSchema = altTemplateContext(
942
+ _zod.z.array(treatmentSchema, {
943
+ required_error: "Expected an array for `treatments`. Make sure each item starts with a dash (`-`) in YAML.",
944
+ invalid_type_error: "Expected an array for `treatments`. Make sure each item starts with a dash (`-`) in YAML."
945
+ }).nonempty()
946
+ );
947
+ var templateContentSchema = _zod.z.any().superRefine((data, ctx) => {
948
+ const schemas = [
949
+ { schema: introSequenceSchema, name: "Intro Sequence" },
950
+ { schema: introSequencesSchema, name: "Intro Sequences" },
951
+ { schema: elementsSchema, name: "Elements" },
952
+ { schema: elementSchema, name: "Element" },
953
+ { schema: stageSchema, name: "Stage" },
954
+ { schema: stagesSchema, name: "Stages" },
955
+ { schema: treatmentSchema, name: "Treatment" },
956
+ { schema: treatmentsSchema, name: "Treatments" },
957
+ { schema: referenceSchema, name: "Reference" },
958
+ { schema: conditionSchema, name: "Condition" },
959
+ { schema: playerSchema, name: "Player" },
960
+ // specify intro step or exit step, not both
961
+ { schema: introExitStepSchema, name: "Intro Exit Step" },
962
+ { schema: exitStepsSchema, name: "Exit Steps" },
963
+ //commented out for now, matches too many schemas
964
+ {
965
+ schema: templateBroadcastAxisValuesSchema,
966
+ name: "Template Broadcast Axis Values"
967
+ }
968
+ ];
969
+ let bestSchemaResult = null;
970
+ let fewestUnmatchedKeys = Infinity;
971
+ for (const { schema, name } of schemas) {
972
+ const result = schema.safeParse(data);
973
+ if (result.success) {
974
+ console.log(`Schema "${name}" matched successfully.`);
975
+ return;
976
+ } else {
977
+ const rootTypeError = result.error.issues.find(
978
+ (issue) => issue.code === "invalid_type" && issue.path.length === 0
979
+ );
980
+ if (rootTypeError) {
981
+ continue;
982
+ }
983
+ const discriminatorIssue = result.error.issues.find(
984
+ (issue) => issue.code === "invalid_union_discriminator" && issue.path.length === 1
985
+ );
986
+ const promptShorthandIssue = result.error.issues.find(
987
+ (issue) => issue.code === "invalid_type" && issue.expected === "string" && issue.received === "object" && issue.message === "promptShorthandSchema expects a string, but received object."
988
+ );
989
+ if (discriminatorIssue !== void 0) {
990
+ continue;
991
+ }
992
+ const unmatchedKeysCount = result.error.issues.filter((issue) => issue.code === "unrecognized_keys").reduce(
993
+ (sum, issue) => sum + (issue.keys ? issue.keys.length : 0),
994
+ 0
995
+ );
996
+ if (unmatchedKeysCount < fewestUnmatchedKeys) {
997
+ if (promptShorthandIssue) {
998
+ continue;
999
+ }
1000
+ fewestUnmatchedKeys = unmatchedKeysCount;
1001
+ bestSchemaResult = { result, name };
1002
+ }
1003
+ }
1004
+ }
1005
+ if (bestSchemaResult) {
1006
+ console.log(
1007
+ `Best schema match is "${bestSchemaResult.name}" with ${fewestUnmatchedKeys} unmatched keys.`
1008
+ );
1009
+ bestSchemaResult.result.error.issues.forEach((issue) => {
1010
+ ctx.addIssue({
1011
+ ...issue,
1012
+ path: issue.path,
1013
+ message: `Closest schema match: ${bestSchemaResult.name}. ${issue.message}`
1014
+ });
1015
+ });
1016
+ } else {
1017
+ ctx.addIssue({
1018
+ code: _zod.z.ZodIssueCode.custom,
1019
+ message: "No schema matched the provided data."
1020
+ });
1021
+ }
1022
+ });
1023
+ var templateSchema = _zod.z.object({
1024
+ templateName: nameSchema,
1025
+ contentType: _zod.z.enum([
1026
+ "introSequence",
1027
+ "introSequences",
1028
+ "elements",
1029
+ "element",
1030
+ "stage",
1031
+ "stages",
1032
+ "treatment",
1033
+ "treatments",
1034
+ "reference",
1035
+ "condition",
1036
+ "player",
1037
+ "introExitStep",
1038
+ "exitSteps",
1039
+ "other"
1040
+ ]).optional(),
1041
+ templateDesc: descriptionSchema.optional(),
1042
+ templateContent: _zod.z.any()
1043
+ }).strict().superRefine((data, ctx) => {
1044
+ if (!data.contentType) {
1045
+ const res = templateContentSchema.safeParse(data.templateContent);
1046
+ if (!res.success) {
1047
+ res.error.issues.forEach(
1048
+ (issue) => ctx.addIssue({
1049
+ ...issue,
1050
+ path: ["templateContent", ...issue.path]
1051
+ })
1052
+ );
1053
+ }
1054
+ ctx.addIssue({
1055
+ code: _zod.z.ZodIssueCode.custom,
1056
+ message: "contentType field is required. Please specify a valid content type. Valid content types are 'introSequence', 'introSequences', 'elements', 'element', 'stage', 'stages', 'treatment', 'treatments', 'reference', 'condition', 'player', 'introExitStep', or 'exitSteps'."
1057
+ });
1058
+ return;
1059
+ } else if (data.contentType === "other") {
1060
+ ctx.addIssue({
1061
+ code: _zod.z.ZodIssueCode.custom,
1062
+ message: "contentType 'other' cannot be validated. Only use when custom content is required that does not match any of the other defined content types. Please use at your own discretion."
1063
+ });
1064
+ return;
1065
+ }
1066
+ const result = matchContentType(data.contentType).safeParse(
1067
+ data.templateContent
1068
+ );
1069
+ if (!result.success) {
1070
+ result.error.issues.forEach(
1071
+ (issue) => ctx.addIssue({
1072
+ ...issue,
1073
+ path: ["templateContent", ...issue.path],
1074
+ message: `Invalid template content for content type '${data.contentType}': ${issue.message}`
1075
+ })
1076
+ );
1077
+ }
1078
+ });
1079
+ function matchContentType(contentType) {
1080
+ switch (contentType) {
1081
+ case "introSequence":
1082
+ return introSequenceSchema;
1083
+ case "introSequences":
1084
+ return introSequencesSchema;
1085
+ case "elements":
1086
+ return elementsSchema;
1087
+ case "element":
1088
+ return elementSchema;
1089
+ case "stage":
1090
+ return stageSchema;
1091
+ case "stages":
1092
+ return stagesSchema;
1093
+ case "treatment":
1094
+ return treatmentSchema;
1095
+ case "treatments":
1096
+ return treatmentsSchema;
1097
+ case "reference":
1098
+ return referenceSchema;
1099
+ case "condition":
1100
+ return conditionSchema;
1101
+ case "player":
1102
+ return playerSchema;
1103
+ case "introExitStep":
1104
+ return introExitStepSchema;
1105
+ case "exitSteps":
1106
+ return exitStepsSchema;
1107
+ default:
1108
+ throw new Error(`Unknown content type: ${contentType}`);
1109
+ }
1110
+ }
1111
+ var treatmentFileSchema = _zod.z.object({
1112
+ templates: _zod.z.array(templateSchema).min(1, "Templates cannot be empty").optional(),
1113
+ introSequences: introSequencesSchema,
1114
+ treatments: treatmentsSchema
1115
+ });
1116
+
1117
+ // src/schemas/resolved.ts
1118
+
1119
+ var resolvedConditionSchema = _zod.z.object({
1120
+ reference: referenceSchema,
1121
+ position: _zod.z.enum(["shared", "player", "all", "any", "percentAgreement"]).or(_zod.z.number().nonnegative().int()).optional(),
1122
+ comparator: _zod.z.enum([
1123
+ "exists",
1124
+ "doesNotExist",
1125
+ "equals",
1126
+ "doesNotEqual",
1127
+ "isAbove",
1128
+ "isBelow",
1129
+ "isAtLeast",
1130
+ "isAtMost",
1131
+ "hasLengthAtLeast",
1132
+ "hasLengthAtMost",
1133
+ "includes",
1134
+ "doesNotInclude",
1135
+ "matches",
1136
+ "doesNotMatch",
1137
+ "isOneOf",
1138
+ "isNotOneOf"
1139
+ ]),
1140
+ value: _zod.z.union([
1141
+ _zod.z.string(),
1142
+ _zod.z.number(),
1143
+ _zod.z.boolean(),
1144
+ _zod.z.array(_zod.z.string().or(_zod.z.number()))
1145
+ ]).optional()
1146
+ }).strict();
1147
+ var resolvedConditionsSchema = _zod.z.array(resolvedConditionSchema).optional();
1148
+ var resolvedElementBaseSchema = _zod.z.object({
1149
+ type: _zod.z.string(),
1150
+ name: nameSchema.optional(),
1151
+ desc: descriptionSchema.optional(),
1152
+ file: _zod.z.string().optional(),
1153
+ displayTime: displayTimeSchema.optional(),
1154
+ hideTime: hideTimeSchema.optional(),
1155
+ showToPositions: showToPositionsSchema.optional(),
1156
+ hideFromPositions: hideFromPositionsSchema.optional(),
1157
+ conditions: resolvedConditionsSchema,
1158
+ tags: _zod.z.array(_zod.z.string()).optional(),
1159
+ // Allow additional fields for specific element types
1160
+ shared: _zod.z.boolean().optional(),
1161
+ buttonText: _zod.z.string().optional(),
1162
+ url: _zod.z.string().optional(),
1163
+ displayText: _zod.z.string().optional(),
1164
+ helperText: _zod.z.string().optional(),
1165
+ reference: _zod.z.string().optional(),
1166
+ position: positionSelectorSchema.optional(),
1167
+ surveyName: _zod.z.string().optional(),
1168
+ startTime: _zod.z.number().optional(),
1169
+ endTime: _zod.z.number().optional(),
1170
+ warnTimeRemaining: _zod.z.number().optional(),
1171
+ style: _zod.z.enum(["thin", "regular", "thick", ""]).optional(),
1172
+ width: _zod.z.number().optional(),
1173
+ urlParams: _zod.z.array(
1174
+ _zod.z.object({
1175
+ key: _zod.z.string(),
1176
+ value: _zod.z.union([_zod.z.string(), _zod.z.number(), _zod.z.boolean()]).optional(),
1177
+ reference: _zod.z.string().optional(),
1178
+ position: positionSelectorSchema.optional()
1179
+ })
1180
+ ).optional(),
1181
+ // mediaPlayer fields
1182
+ syncToStageTime: _zod.z.boolean().optional(),
1183
+ submitOnComplete: _zod.z.boolean().optional(),
1184
+ playVideo: _zod.z.boolean().optional(),
1185
+ playAudio: _zod.z.boolean().optional(),
1186
+ captionsFile: _zod.z.string().optional(),
1187
+ startAt: _zod.z.number().optional(),
1188
+ stopAt: _zod.z.number().optional(),
1189
+ allowScrubOutsideBounds: _zod.z.boolean().optional(),
1190
+ stepDuration: _zod.z.number().optional(),
1191
+ controls: _zod.z.object({
1192
+ playPause: _zod.z.boolean().optional(),
1193
+ seek: _zod.z.boolean().optional(),
1194
+ step: _zod.z.boolean().optional(),
1195
+ speed: _zod.z.boolean().optional()
1196
+ }).optional()
1197
+ });
1198
+ var resolvedElementSchema = resolvedElementBaseSchema;
1199
+ var resolvedStageSchema = _zod.z.object({
1200
+ name: nameSchema,
1201
+ desc: descriptionSchema.optional(),
1202
+ discussion: discussionSchema.optional(),
1203
+ duration: durationSchema,
1204
+ elements: _zod.z.array(resolvedElementSchema).nonempty()
1205
+ });
1206
+ var resolvedIntroExitStepSchema = _zod.z.object({
1207
+ name: nameSchema,
1208
+ desc: descriptionSchema.optional(),
1209
+ elements: _zod.z.array(resolvedElementSchema).nonempty()
1210
+ });
1211
+ var resolvedTreatmentSchema = _zod.z.object({
1212
+ name: nameSchema,
1213
+ desc: descriptionSchema.optional(),
1214
+ playerCount: _zod.z.number(),
1215
+ groupComposition: _zod.z.array(
1216
+ _zod.z.object({
1217
+ desc: descriptionSchema.optional(),
1218
+ position: positionSchema,
1219
+ title: _zod.z.string().max(25).optional(),
1220
+ conditions: resolvedConditionsSchema
1221
+ })
1222
+ ).optional(),
1223
+ gameStages: _zod.z.array(resolvedStageSchema).nonempty(),
1224
+ exitSequence: _zod.z.array(resolvedIntroExitStepSchema).optional()
1225
+ });
1226
+
1227
+ // src/utils/reference.ts
1228
+ function getNestedValueByPath(obj, path = []) {
1229
+ return path.reduce(
1230
+ (acc, key) => acc !== null && acc !== void 0 ? acc[key] : void 0,
1231
+ obj
1232
+ );
1233
+ }
1234
+ function getReferenceKeyAndPath(reference) {
1235
+ const segments = reference.split(".");
1236
+ const [type, ...rest] = segments;
1237
+ let name;
1238
+ let path = [];
1239
+ let referenceKey;
1240
+ if (["survey", "submitButton", "qualtrics"].includes(type)) {
1241
+ [name, ...path] = rest;
1242
+ referenceKey = `${type}_${name}`;
1243
+ } else if (type === "prompt") {
1244
+ [name] = rest;
1245
+ referenceKey = `${type}_${name}`;
1246
+ path = ["value"];
1247
+ } else if (type === "trackedLink") {
1248
+ [name, ...path] = rest;
1249
+ referenceKey = `trackedLink_${name}`;
1250
+ } else if (["urlParams", "connectionInfo", "browserInfo"].includes(type)) {
1251
+ path = rest;
1252
+ referenceKey = type;
1253
+ } else if (["participantInfo", "discussion"].includes(type)) {
1254
+ [name, ...path] = rest;
1255
+ referenceKey = name;
1256
+ } else {
1257
+ throw new Error(`Invalid reference type: ${type}`);
1258
+ }
1259
+ if (!referenceKey || !name && [
1260
+ "survey",
1261
+ "submitButton",
1262
+ "qualtrics",
1263
+ "prompt",
1264
+ "trackedLink",
1265
+ "participantInfo",
1266
+ "discussion"
1267
+ ].includes(type)) {
1268
+ throw new Error(`Reference ${reference} is missing a name segment.`);
1269
+ }
1270
+ return { referenceKey, path };
1271
+ }
1272
+
1273
+ // src/templates/fillTemplates.ts
1274
+ function escapeRegExp(str) {
1275
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1276
+ }
1277
+ var FIELD_PLACEHOLDER_REGEX = /\$\{([a-zA-Z0-9_]+)\}/g;
1278
+ function substituteFields({
1279
+ templateContent,
1280
+ fields
1281
+ }) {
1282
+ let expandedTemplate = JSON.parse(JSON.stringify(templateContent));
1283
+ for (const [key, value] of Object.entries(fields)) {
1284
+ if (value === void 0) continue;
1285
+ let stringifiedTemplate = JSON.stringify(expandedTemplate);
1286
+ const stringifiedValue = JSON.stringify(value);
1287
+ const escapedKey = escapeRegExp(key);
1288
+ const objectReplacementRegex = new RegExp(`"\\$\\{${escapedKey}\\}"`, "g");
1289
+ stringifiedTemplate = stringifiedTemplate.replace(
1290
+ objectReplacementRegex,
1291
+ stringifiedValue
1292
+ );
1293
+ if (typeof value === "string") {
1294
+ const stringReplacementRegex = new RegExp(`\\$\\{${escapedKey}\\}`, "g");
1295
+ stringifiedTemplate = stringifiedTemplate.replace(
1296
+ stringReplacementRegex,
1297
+ value
1298
+ );
1299
+ }
1300
+ expandedTemplate = JSON.parse(stringifiedTemplate);
1301
+ }
1302
+ return expandedTemplate;
1303
+ }
1304
+ function expandTemplate({
1305
+ templates,
1306
+ context
1307
+ }) {
1308
+ const newContext = JSON.parse(JSON.stringify(context));
1309
+ if (newContext.fields) {
1310
+ newContext.fields = recursivelyFillTemplates({
1311
+ obj: newContext.fields,
1312
+ templates
1313
+ });
1314
+ }
1315
+ if (newContext.broadcast) {
1316
+ newContext.broadcast = recursivelyFillTemplates({
1317
+ obj: newContext.broadcast,
1318
+ templates
1319
+ });
1320
+ }
1321
+ const template = templates.find(
1322
+ (t) => t.templateName === newContext.template
1323
+ );
1324
+ if (!template) {
1325
+ throw new Error(`Template "${newContext.template}" not found`);
1326
+ }
1327
+ let expandedTemplate = JSON.parse(JSON.stringify(template.templateContent));
1328
+ if (newContext.fields) {
1329
+ expandedTemplate = substituteFields({
1330
+ templateContent: expandedTemplate,
1331
+ fields: newContext.fields
1332
+ });
1333
+ }
1334
+ function flattenBroadcast(dimensions) {
1335
+ const dimensionIndices = Object.keys(dimensions);
1336
+ const dimensionNumbers = dimensionIndices.map((i) => parseInt(i.slice(1)));
1337
+ const lowestDimension = Math.min(...dimensionNumbers);
1338
+ const currentDimension = dimensions[`d${lowestDimension}`];
1339
+ const remainingDimensions = JSON.parse(JSON.stringify(dimensions));
1340
+ delete remainingDimensions[`d${lowestDimension}`];
1341
+ let partialFields = [{}];
1342
+ if (Object.keys(remainingDimensions).length > 0) {
1343
+ partialFields = flattenBroadcast(remainingDimensions);
1344
+ }
1345
+ const flatFields = [];
1346
+ for (const [index, entry] of currentDimension.entries()) {
1347
+ for (const partialField of partialFields) {
1348
+ const newField = { ...entry, ...partialField };
1349
+ newField[`d${lowestDimension}`] = `${index}`;
1350
+ flatFields.push(newField);
1351
+ }
1352
+ }
1353
+ return flatFields;
1354
+ }
1355
+ if (newContext.broadcast) {
1356
+ const broadcastFieldsArray = flattenBroadcast(newContext.broadcast);
1357
+ const returnObjects = [];
1358
+ for (const broadcastFields of broadcastFieldsArray) {
1359
+ const newObj = substituteFields({
1360
+ templateContent: expandedTemplate,
1361
+ fields: broadcastFields
1362
+ });
1363
+ if (Array.isArray(newObj)) {
1364
+ returnObjects.push(...newObj);
1365
+ } else if (typeof newObj === "object") {
1366
+ returnObjects.push(newObj);
1367
+ } else {
1368
+ throw new Error("Unexpected type in broadcast fields");
1369
+ }
1370
+ }
1371
+ return returnObjects;
1372
+ }
1373
+ return expandedTemplate;
1374
+ }
1375
+ var MAX_TEMPLATE_DEPTH = 100;
1376
+ function recursivelyFillTemplates({
1377
+ obj,
1378
+ templates,
1379
+ depth = 0,
1380
+ templateChain = []
1381
+ }) {
1382
+ if (depth > MAX_TEMPLATE_DEPTH) {
1383
+ const chain = templateChain.length > 0 ? ` Template chain: ${templateChain.slice(-10).join(" \u2192 ")}` : "";
1384
+ throw new Error(
1385
+ `Maximum template nesting depth (${MAX_TEMPLATE_DEPTH}) exceeded.${chain} Check for circular template references in your treatment file.`
1386
+ );
1387
+ }
1388
+ let newObj;
1389
+ try {
1390
+ newObj = JSON.parse(JSON.stringify(obj));
1391
+ } catch (e) {
1392
+ console.log("Error parsing", obj);
1393
+ throw e;
1394
+ }
1395
+ if (!Array.isArray(newObj) && typeof newObj === "object") {
1396
+ if (newObj && newObj.template) {
1397
+ const templateName = newObj.template;
1398
+ const context = templateContextSchema.parse(newObj);
1399
+ newObj = expandTemplate({ templates, context });
1400
+ newObj = recursivelyFillTemplates({
1401
+ obj: newObj,
1402
+ templates,
1403
+ depth: depth + 1,
1404
+ templateChain: [...templateChain, templateName]
1405
+ });
1406
+ } else {
1407
+ for (const key in newObj) {
1408
+ if (newObj[key] == null) {
1409
+ console.log(`key ${key} is undefined in`, newObj);
1410
+ }
1411
+ newObj[key] = recursivelyFillTemplates({
1412
+ obj: newObj[key],
1413
+ templates,
1414
+ depth: depth + 1,
1415
+ templateChain
1416
+ });
1417
+ }
1418
+ }
1419
+ } else if (Array.isArray(newObj)) {
1420
+ for (const [index, item] of newObj.entries()) {
1421
+ if (item.template) {
1422
+ const context = templateContextSchema.parse(item);
1423
+ const expandedItem = expandTemplate({ templates, context });
1424
+ if (Array.isArray(expandedItem)) {
1425
+ newObj.splice(index, 1, ...expandedItem);
1426
+ } else if (typeof expandedItem === "object") {
1427
+ newObj[index] = expandedItem;
1428
+ } else {
1429
+ throw new Error("Unexpected type in expanded item");
1430
+ }
1431
+ } else {
1432
+ newObj[index] = recursivelyFillTemplates({
1433
+ obj: item,
1434
+ templates,
1435
+ depth: depth + 1,
1436
+ templateChain
1437
+ });
1438
+ }
1439
+ }
1440
+ }
1441
+ return newObj;
1442
+ }
1443
+ function fillTemplates({
1444
+ obj,
1445
+ templates,
1446
+ additionalFields,
1447
+ allowUnresolved = false
1448
+ }) {
1449
+ let newObj = recursivelyFillTemplates({ obj, templates });
1450
+ const templatesRemainingRegex = /"template":/g;
1451
+ let templatesRemaining = JSON.stringify(newObj).match(
1452
+ templatesRemainingRegex
1453
+ );
1454
+ while (templatesRemaining) {
1455
+ newObj = recursivelyFillTemplates({ obj: newObj, templates });
1456
+ templatesRemaining = JSON.stringify(newObj).match(templatesRemainingRegex);
1457
+ }
1458
+ if (additionalFields && Object.keys(additionalFields).length > 0) {
1459
+ newObj = substituteFields({
1460
+ templateContent: newObj,
1461
+ fields: additionalFields
1462
+ });
1463
+ }
1464
+ const matches = JSON.stringify(newObj).matchAll(
1465
+ new RegExp(FIELD_PLACEHOLDER_REGEX.source, "g")
1466
+ );
1467
+ const unresolvedSet = /* @__PURE__ */ new Set();
1468
+ for (const match of matches) {
1469
+ unresolvedSet.add(match[1]);
1470
+ }
1471
+ const unresolvedFields = [...unresolvedSet];
1472
+ if (!allowUnresolved && unresolvedFields.length > 0) {
1473
+ throw new Error(
1474
+ `Missing fields: ${unresolvedFields.map((f) => `\${${f}}`).join(", ")}`
1475
+ );
1476
+ }
1477
+ return { result: newObj, unresolvedFields };
1478
+ }
1479
+ function getUnresolvedFields({
1480
+ obj,
1481
+ templates
1482
+ }) {
1483
+ const { unresolvedFields } = fillTemplates({
1484
+ obj,
1485
+ templates,
1486
+ allowUnresolved: true
1487
+ });
1488
+ return unresolvedFields;
1489
+ }
1490
+
1491
+
1492
+
1493
+
1494
+
1495
+
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+
1511
+
1512
+
1513
+
1514
+
1515
+
1516
+
1517
+
1518
+
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+
1525
+
1526
+
1527
+
1528
+
1529
+
1530
+
1531
+
1532
+
1533
+
1534
+
1535
+
1536
+
1537
+
1538
+
1539
+
1540
+
1541
+
1542
+
1543
+
1544
+
1545
+
1546
+
1547
+
1548
+
1549
+
1550
+ exports.baseTreatmentSchema = baseTreatmentSchema; exports.compare = _chunkI2WMGA4Qcjs.compare; exports.computeWatchedRanges = _chunkI2WMGA4Qcjs.computeWatchedRanges; exports.conditionSchema = conditionSchema; exports.conditionsSchema = conditionsSchema; exports.descriptionSchema = descriptionSchema; exports.discussionSchema = discussionSchema; exports.displayRegionSchema = displayRegionSchema; exports.displayTimeSchema = displayTimeSchema; exports.durationSchema = durationSchema; exports.elementSchema = elementSchema; exports.elementsSchema = elementsSchema; exports.evaluateCondition = _chunkI2WMGA4Qcjs.evaluateCondition; exports.evaluateConditions = _chunkI2WMGA4Qcjs.evaluateConditions; exports.exitStepsSchema = exitStepsSchema; exports.expandTemplate = expandTemplate; exports.fileSchema = fileSchema; exports.fillTemplates = fillTemplates; exports.getNestedValueByPath = getNestedValueByPath; exports.getReferenceKeyAndPath = getReferenceKeyAndPath; exports.getUnresolvedFields = getUnresolvedFields; exports.hideFromPositionsSchema = hideFromPositionsSchema; exports.hideTimeSchema = hideTimeSchema; exports.introExitStepSchema = introExitStepSchema; exports.introExitStepsBaseSchema = introExitStepsBaseSchema; exports.introExitStepsSchema = introExitStepsSchema; exports.introSequenceSchema = introSequenceSchema; exports.introSequencesSchema = introSequencesSchema; exports.introStepsSchema = introStepsSchema; exports.matchContentType = matchContentType; exports.metadataLogicalSchema = _chunkI2WMGA4Qcjs.metadataLogicalSchema; exports.metadataRefineSchema = _chunkI2WMGA4Qcjs.metadataRefineSchema; exports.metadataTypeSchema = _chunkI2WMGA4Qcjs.metadataTypeSchema; exports.nameSchema = nameSchema; exports.playerSchema = playerSchema; exports.positionSchema = positionSchema; exports.positionSelectorSchema = positionSelectorSchema; exports.promptFileSchema = _chunkI2WMGA4Qcjs.promptFileSchema; exports.promptSchema = promptSchema; exports.recursivelyFillTemplates = recursivelyFillTemplates; exports.referenceSchema = referenceSchema; exports.resolvedConditionSchema = resolvedConditionSchema; exports.resolvedConditionsSchema = resolvedConditionsSchema; exports.resolvedElementSchema = resolvedElementSchema; exports.resolvedIntroExitStepSchema = resolvedIntroExitStepSchema; exports.resolvedStageSchema = resolvedStageSchema; exports.resolvedTreatmentSchema = resolvedTreatmentSchema; exports.showToPositionsSchema = showToPositionsSchema; exports.stageSchema = stageSchema; exports.substituteFields = substituteFields; exports.templateContentSchema = templateContentSchema; exports.templateContextSchema = templateContextSchema; exports.templateSchema = templateSchema; exports.timelineSchema = timelineSchema; exports.treatmentFileSchema = treatmentFileSchema; exports.treatmentSchema = treatmentSchema; exports.treatmentsSchema = treatmentsSchema; exports.urlSchema = urlSchema; exports.validateSliderLabels = _chunkI2WMGA4Qcjs.validateSliderLabels;
1551
+ //# sourceMappingURL=index.cjs.map