@kubuild/schema 0.0.1 → 0.2.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.js CHANGED
@@ -1,49 +1,390 @@
1
1
  // src/document.ts
2
+ import { z as z3 } from "zod";
3
+
4
+ // src/actions.ts
2
5
  import { z } from "zod";
6
+ var ActionTriggerTypeSchema = z.enum([
7
+ "click",
8
+ "submit",
9
+ "change",
10
+ "blur",
11
+ "focus",
12
+ "load"
13
+ ]);
14
+ var ActionTriggerSchema = ActionTriggerTypeSchema;
15
+ var ActionStepTypeSchema = z.enum([
16
+ "api_request",
17
+ "navigate",
18
+ "set_state",
19
+ "reset_form",
20
+ "show_toast",
21
+ "open_modal",
22
+ "close_modal",
23
+ "copy_clipboard",
24
+ "custom_event"
25
+ ]);
26
+ var ConditionOperatorSchema = z.enum([
27
+ "equals",
28
+ "not_equals",
29
+ "contains",
30
+ "not_contains",
31
+ "is_truthy",
32
+ "is_falsy",
33
+ "gt",
34
+ "gte",
35
+ "lt",
36
+ "lte",
37
+ "regex"
38
+ ]);
39
+ var ActionStepConditionSchema = z.object({
40
+ field: z.string().min(1, "Condition field cannot be empty"),
41
+ operator: ConditionOperatorSchema,
42
+ value: z.unknown().optional()
43
+ });
44
+ var DANGEROUS_URL_PATTERN = /(javascript:|vbscript:|data:text\/html)/i;
45
+ var DANGEROUS_SCRIPT_PATTERN = /<\s*script/i;
46
+ function isSafeActionUrl(url) {
47
+ if (!url || typeof url !== "string") return false;
48
+ const trimmed = url.trim();
49
+ if (DANGEROUS_URL_PATTERN.test(trimmed)) return false;
50
+ if (DANGEROUS_SCRIPT_PATTERN.test(trimmed)) return false;
51
+ return true;
52
+ }
53
+ var SafeUrlStringSchema = z.string().min(1, "URL cannot be empty").refine(isSafeActionUrl, {
54
+ message: "URL contains disallowed or unsafe protocol/script pattern"
55
+ });
56
+ var SafeEventNameSchema = z.string().min(1, "Event name cannot be empty").regex(/^[a-zA-Z0-9_\-:]+$/, {
57
+ message: "Event name must contain only alphanumeric characters, dashes, colons, or underscores"
58
+ });
59
+ var ApiRequestStepPayloadSchema = z.object({
60
+ url: SafeUrlStringSchema,
61
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).default("GET"),
62
+ headers: z.record(z.string(), z.string()).optional(),
63
+ queryParams: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
64
+ body: z.union([z.string(), z.record(z.string(), z.unknown()), z.array(z.unknown())]).optional(),
65
+ bodyFormat: z.enum(["json", "form-data", "formData", "urlencoded", "url-encoded", "raw", "text"]).optional(),
66
+ bodyType: z.enum(["json", "form-data", "formData", "urlencoded", "url-encoded", "raw", "text"]).optional(),
67
+ timeout: z.number().positive("Timeout must be greater than 0 ms").optional(),
68
+ responseMapping: z.record(z.string(), z.string()).optional()
69
+ });
70
+ var NavigateStepPayloadSchema = z.object({
71
+ url: SafeUrlStringSchema,
72
+ target: z.enum(["_self", "_blank", "_parent", "_top"]).optional().default("_self"),
73
+ replace: z.boolean().optional(),
74
+ scroll: z.boolean().optional(),
75
+ behavior: z.enum(["smooth", "auto"]).optional()
76
+ });
77
+ var SetStateStepPayloadSchema = z.object({
78
+ key: z.string().min(1, "State key cannot be empty"),
79
+ value: z.unknown(),
80
+ scope: z.enum(["runtime", "document", "session", "local"]).optional().default("runtime")
81
+ });
82
+ var ResetFormStepPayloadSchema = z.object({
83
+ formId: z.string().optional()
84
+ });
85
+ var ShowToastStepPayloadSchema = z.object({
86
+ message: z.string().min(1, "Toast message cannot be empty"),
87
+ type: z.enum(["success", "error", "warning", "info"]).optional().default("info"),
88
+ variant: z.enum(["success", "error", "warning", "info"]).optional(),
89
+ title: z.string().optional(),
90
+ duration: z.number().nonnegative("Duration must be >= 0 ms").optional(),
91
+ position: z.enum(["top-right", "top-left", "bottom-right", "bottom-left", "top-center", "bottom-center"]).optional()
92
+ });
93
+ var OpenModalStepPayloadSchema = z.object({
94
+ modalId: z.string().optional(),
95
+ modalNodeId: z.string().optional()
96
+ }).refine((data) => Boolean(data.modalId || data.modalNodeId), {
97
+ message: "Modal ID or Modal Node ID cannot be empty"
98
+ });
99
+ var CloseModalStepPayloadSchema = z.object({
100
+ modalId: z.string().optional(),
101
+ modalNodeId: z.string().optional()
102
+ });
103
+ var CopyClipboardStepPayloadSchema = z.object({
104
+ text: z.string().optional(),
105
+ value: z.unknown().optional(),
106
+ notify: z.boolean().optional(),
107
+ toastMessage: z.string().optional()
108
+ });
109
+ var CustomEventStepPayloadSchema = z.object({
110
+ eventName: SafeEventNameSchema,
111
+ detail: z.record(z.string(), z.unknown()).optional(),
112
+ bubbles: z.boolean().optional().default(true),
113
+ cancelable: z.boolean().optional().default(true)
114
+ });
115
+ var StepPayloadSchemas = {
116
+ api_request: ApiRequestStepPayloadSchema,
117
+ navigate: NavigateStepPayloadSchema,
118
+ set_state: SetStateStepPayloadSchema,
119
+ reset_form: ResetFormStepPayloadSchema,
120
+ show_toast: ShowToastStepPayloadSchema,
121
+ open_modal: OpenModalStepPayloadSchema,
122
+ close_modal: CloseModalStepPayloadSchema,
123
+ copy_clipboard: CopyClipboardStepPayloadSchema,
124
+ custom_event: CustomEventStepPayloadSchema
125
+ };
126
+ var ActionStepSchema = z.lazy(
127
+ () => z.object({
128
+ id: z.string().min(1, "Step ID cannot be empty"),
129
+ type: ActionStepTypeSchema,
130
+ label: z.string().optional(),
131
+ payload: z.record(z.string(), z.unknown()).optional().default({}),
132
+ condition: ActionStepConditionSchema.optional(),
133
+ timeout: z.number().positive().optional(),
134
+ continueOnError: z.boolean().optional(),
135
+ onSuccess: z.array(ActionStepSchema).optional(),
136
+ onError: z.array(ActionStepSchema).optional()
137
+ })
138
+ );
139
+ var ActionPipelineSchema = z.object({
140
+ id: z.string().min(1, "Pipeline ID cannot be empty"),
141
+ trigger: ActionTriggerTypeSchema,
142
+ label: z.string().optional(),
143
+ debounceMs: z.number().nonnegative("Debounce ms must be >= 0").optional(),
144
+ preventDuplicate: z.boolean().optional(),
145
+ enabled: z.boolean().optional().default(true),
146
+ steps: z.array(ActionStepSchema).min(1, "Action pipeline must contain at least one step")
147
+ });
148
+ function isActionTriggerType(value) {
149
+ return ActionTriggerTypeSchema.safeParse(value).success;
150
+ }
151
+ function isActionStepType(value) {
152
+ return ActionStepTypeSchema.safeParse(value).success;
153
+ }
154
+ function isConditionOperator(value) {
155
+ return ConditionOperatorSchema.safeParse(value).success;
156
+ }
157
+ function isActionStepCondition(value) {
158
+ return ActionStepConditionSchema.safeParse(value).success;
159
+ }
160
+ function isActionStep(value) {
161
+ return ActionStepSchema.safeParse(value).success;
162
+ }
163
+ function isActionPipeline(value) {
164
+ return ActionPipelineSchema.safeParse(value).success;
165
+ }
166
+ function validateActionStepPayload(type, payload) {
167
+ const schema = StepPayloadSchemas[type];
168
+ if (!schema) {
169
+ return {
170
+ success: false,
171
+ error: new z.ZodError([
172
+ {
173
+ code: z.ZodIssueCode.custom,
174
+ message: `Unknown step type: ${type}`,
175
+ path: ["type"]
176
+ }
177
+ ])
178
+ };
179
+ }
180
+ const result = schema.safeParse(payload);
181
+ if (result.success) {
182
+ return { success: true, data: result.data };
183
+ }
184
+ return { success: false, error: result.error };
185
+ }
186
+ function sanitizeActionUrl(url, fallback = "") {
187
+ if (typeof url !== "string") return fallback;
188
+ const trimmed = url.trim();
189
+ if (!isSafeActionUrl(trimmed)) {
190
+ return fallback;
191
+ }
192
+ return trimmed;
193
+ }
194
+ function sanitizeActionString(value, fallback = "") {
195
+ if (typeof value !== "string") return fallback;
196
+ if (DANGEROUS_SCRIPT_PATTERN.test(value)) {
197
+ return value.replace(/<\s*script[^>]*>[\s\S]*?<\s*\/\s*script\s*>/gi, "").replace(/<\s*script[^>]*>/gi, "");
198
+ }
199
+ return value;
200
+ }
201
+ function sanitizeActionValue(value) {
202
+ if (value === null || value === void 0) return value;
203
+ if (typeof value === "string") {
204
+ const trimmed = value.trim();
205
+ if (DANGEROUS_URL_PATTERN.test(trimmed)) {
206
+ return "";
207
+ }
208
+ return sanitizeActionString(value);
209
+ }
210
+ if (Array.isArray(value)) {
211
+ return value.map((item) => sanitizeActionValue(item));
212
+ }
213
+ if (typeof value === "object") {
214
+ const result = {};
215
+ for (const [k, v] of Object.entries(value)) {
216
+ if (/^(url|href|src|endpoint|targetUrl)$/i.test(k) && typeof v === "string") {
217
+ result[k] = sanitizeActionUrl(v);
218
+ } else {
219
+ result[k] = sanitizeActionValue(v);
220
+ }
221
+ }
222
+ return result;
223
+ }
224
+ return value;
225
+ }
226
+ function sanitizeActionPayload(payload) {
227
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
228
+ return {};
229
+ }
230
+ return sanitizeActionValue(payload);
231
+ }
232
+ function sanitizeActionStep(step) {
233
+ const sanitized = {
234
+ ...step,
235
+ label: step.label ? sanitizeActionString(step.label) : step.label,
236
+ payload: sanitizeActionPayload(step.payload)
237
+ };
238
+ if (step.condition && step.condition.value !== void 0) {
239
+ sanitized.condition = {
240
+ ...step.condition,
241
+ value: sanitizeActionValue(step.condition.value)
242
+ };
243
+ }
244
+ if (step.onSuccess && Array.isArray(step.onSuccess)) {
245
+ sanitized.onSuccess = step.onSuccess.map((s) => sanitizeActionStep(s));
246
+ }
247
+ if (step.onError && Array.isArray(step.onError)) {
248
+ sanitized.onError = step.onError.map((s) => sanitizeActionStep(s));
249
+ }
250
+ return sanitized;
251
+ }
252
+ function sanitizeActionPipeline(pipeline) {
253
+ return {
254
+ ...pipeline,
255
+ label: pipeline.label ? sanitizeActionString(pipeline.label) : pipeline.label,
256
+ steps: Array.isArray(pipeline.steps) ? pipeline.steps.map((s) => sanitizeActionStep(s)) : []
257
+ };
258
+ }
259
+
260
+ // src/form.ts
261
+ import { z as z2 } from "zod";
262
+ var ValidationRuleTypeSchema = z2.enum([
263
+ "required",
264
+ "email",
265
+ "url",
266
+ "min_length",
267
+ "max_length",
268
+ "numeric_min",
269
+ "numeric_max",
270
+ "pattern",
271
+ "match_field",
272
+ "custom_regex"
273
+ ]);
274
+ var ValidateOnEventSchema = z2.enum(["blur", "change", "submit"]);
275
+ var ValidationRuleSchema = z2.object({
276
+ type: ValidationRuleTypeSchema,
277
+ value: z2.unknown().optional(),
278
+ message: z2.string().min(1, "Validation error message cannot be empty")
279
+ });
280
+ var FormFieldBindingSchema = z2.object({
281
+ name: z2.string().min(1, "Field name cannot be empty"),
282
+ label: z2.string().optional(),
283
+ defaultValue: z2.unknown().optional(),
284
+ rules: z2.array(ValidationRuleSchema).optional().default([]),
285
+ validateOn: ValidateOnEventSchema.optional().default("blur"),
286
+ transform: z2.enum(["trim", "lowercase", "uppercase", "number"]).optional(),
287
+ disabled: z2.boolean().optional(),
288
+ required: z2.boolean().optional()
289
+ });
290
+ var FormConfigSchema = z2.object({
291
+ formId: z2.string().min(1, "Form ID cannot be empty"),
292
+ resetOnSubmit: z2.boolean().optional().default(false),
293
+ scrollToFirstError: z2.boolean().optional().default(true),
294
+ validateOn: ValidateOnEventSchema.optional().default("blur"),
295
+ initialValues: z2.record(z2.string(), z2.unknown()).optional(),
296
+ rules: z2.array(ValidationRuleSchema).optional()
297
+ });
298
+ function isValidationRuleType(value) {
299
+ return ValidationRuleTypeSchema.safeParse(value).success;
300
+ }
301
+ function isValidationRule(value) {
302
+ return ValidationRuleSchema.safeParse(value).success;
303
+ }
304
+ function isValidateOnEvent(value) {
305
+ return ValidateOnEventSchema.safeParse(value).success;
306
+ }
307
+ function isFormFieldBinding(value) {
308
+ return FormFieldBindingSchema.safeParse(value).success;
309
+ }
310
+ function isFormConfig(value) {
311
+ return FormConfigSchema.safeParse(value).success;
312
+ }
313
+
314
+ // src/document.ts
3
315
  var SCHEMA_NAME = "stora.page";
4
316
  var CURRENT_SCHEMA_VERSION = "1.0.0";
5
- var AssetReferenceSchema = z.object({
6
- type: z.literal("asset"),
7
- assetId: z.string().min(1, "Asset ID cannot be empty"),
8
- filename: z.string().optional(),
9
- mimeType: z.string().optional(),
10
- fallbackUrl: z.string().url().optional()
317
+ var AssetReferenceSchema = z3.object({
318
+ type: z3.literal("asset"),
319
+ assetId: z3.string().min(1, "Asset ID cannot be empty"),
320
+ filename: z3.string().optional(),
321
+ mimeType: z3.string().optional(),
322
+ fallbackUrl: z3.string().url().optional()
11
323
  });
12
- var VariableBindingSchema = z.object({
13
- type: z.literal("variable"),
14
- key: z.string().min(1, "Variable key cannot be empty"),
15
- fallback: z.unknown().optional()
324
+ var VariableBindingSchema = z3.object({
325
+ type: z3.literal("variable"),
326
+ key: z3.string().min(1, "Variable key cannot be empty"),
327
+ fallback: z3.unknown().optional()
16
328
  });
17
- var ActionBindingSchema = z.object({
18
- type: z.string().min(1, "Action type cannot be empty"),
19
- payload: z.record(z.string(), z.unknown()).optional()
329
+ var ActionBindingSchema = z3.object({
330
+ type: z3.string().min(1, "Action type cannot be empty"),
331
+ payload: z3.record(z3.string(), z3.unknown()).optional()
20
332
  });
21
333
  var DANGEROUS_STYLE_VALUE_PATTERN = /javascript:|expression\(|@import|<script|vbscript:|data:text\/html/i;
22
- var StyleValueSchema = z.union([
23
- z.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
334
+ var StyleValueSchema = z3.union([
335
+ z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
24
336
  message: "Style value contains a disallowed or unsafe pattern"
25
337
  }),
26
- z.number(),
27
- z.boolean(),
28
- z.null(),
29
- z.undefined()
338
+ z3.number(),
339
+ z3.boolean(),
340
+ z3.null(),
341
+ z3.undefined()
30
342
  ]);
31
- var StyleDefinitionSchema = z.record(z.string(), StyleValueSchema);
32
- var PseudoStateStylesSchema = z.record(z.string(), StyleDefinitionSchema);
33
- var ResponsiveStylesSchema = z.object({
343
+ var StyleDefinitionSchema = z3.record(z3.string(), StyleValueSchema);
344
+ var PseudoStateStylesSchema = z3.record(z3.string(), StyleDefinitionSchema);
345
+ var ResponsiveStylesSchema = z3.object({
34
346
  base: StyleDefinitionSchema.optional(),
35
347
  desktop: StyleDefinitionSchema.optional(),
36
348
  tablet: StyleDefinitionSchema.optional(),
37
349
  mobile: StyleDefinitionSchema.optional(),
38
350
  states: PseudoStateStylesSchema.optional()
39
- }).catchall(StyleDefinitionSchema).default({});
40
- var NodeSchema = z.lazy(
41
- () => z.object({
42
- id: z.string().min(1, "Node ID must be a non-empty string"),
43
- type: z.string().min(1, "Node type must be a non-empty string"),
44
- props: z.record(z.string(), z.unknown()).optional().default({}),
351
+ }).passthrough().default({});
352
+ var AnimationConfigSchema = z3.object({
353
+ type: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
354
+ message: "Animation type contains a disallowed or unsafe pattern"
355
+ }).optional().default("none"),
356
+ duration: z3.number().min(0, "Duration must be non-negative").optional().default(600),
357
+ delay: z3.number().min(0, "Delay must be non-negative").optional().default(0),
358
+ easing: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
359
+ message: "Animation easing contains a disallowed or unsafe pattern"
360
+ }).optional().default("ease-out"),
361
+ once: z3.boolean().optional().default(true),
362
+ hoverEffect: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
363
+ message: "Hover effect contains a disallowed or unsafe pattern"
364
+ }).optional().default("none"),
365
+ loopEffect: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
366
+ message: "Loop effect contains a disallowed or unsafe pattern"
367
+ }).optional().default("none")
368
+ });
369
+ var DEFAULT_ANIMATION_CONFIG = {
370
+ type: "none",
371
+ duration: 600,
372
+ delay: 0,
373
+ easing: "ease-out",
374
+ once: true,
375
+ hoverEffect: "none",
376
+ loopEffect: "none"
377
+ };
378
+ var NodeSchema = z3.lazy(
379
+ () => z3.object({
380
+ id: z3.string().min(1, "Node ID must be a non-empty string"),
381
+ type: z3.string().min(1, "Node type must be a non-empty string"),
382
+ props: z3.record(z3.string(), z3.unknown()).optional().default({}),
45
383
  styles: ResponsiveStylesSchema.optional().default({}),
46
- children: z.array(NodeSchema).optional().default([])
384
+ animation: AnimationConfigSchema.optional(),
385
+ actions: z3.array(ActionPipelineSchema).optional(),
386
+ formConfig: FormConfigSchema.optional(),
387
+ children: z3.array(NodeSchema).optional().default([])
47
388
  })
48
389
  );
49
390
  var RootPageNodeSchema = NodeSchema.refine(
@@ -53,20 +394,20 @@ var RootPageNodeSchema = NodeSchema.refine(
53
394
  path: ["type"]
54
395
  }
55
396
  );
56
- var DocumentMetadataSchema = z.object({
57
- title: z.string().min(1, "Title is required").default("Untitled Page"),
58
- description: z.string().optional().default(""),
59
- author: z.string().optional().default(""),
60
- createdAt: z.string().optional(),
61
- updatedAt: z.string().optional(),
62
- tags: z.array(z.string()).optional().default([]),
63
- category: z.string().optional().default("general"),
64
- version: z.string().optional().default("1.0.0"),
65
- custom: z.record(z.string(), z.unknown()).optional()
397
+ var DocumentMetadataSchema = z3.object({
398
+ title: z3.string().min(1, "Title is required").default("Untitled Page"),
399
+ description: z3.string().optional().default(""),
400
+ author: z3.string().optional().default(""),
401
+ createdAt: z3.string().optional(),
402
+ updatedAt: z3.string().optional(),
403
+ tags: z3.array(z3.string()).optional().default([]),
404
+ category: z3.string().optional().default("general"),
405
+ version: z3.string().optional().default("1.0.0"),
406
+ custom: z3.record(z3.string(), z3.unknown()).optional()
66
407
  });
67
- var PageDocumentSchema = z.object({
68
- schema: z.literal(SCHEMA_NAME),
69
- version: z.string().min(1, "Schema version is required").default(CURRENT_SCHEMA_VERSION),
408
+ var PageDocumentSchema = z3.object({
409
+ schema: z3.literal(SCHEMA_NAME),
410
+ version: z3.string().min(1, "Schema version is required").default(CURRENT_SCHEMA_VERSION),
70
411
  metadata: DocumentMetadataSchema.optional(),
71
412
  document: RootPageNodeSchema
72
413
  });
@@ -79,6 +420,9 @@ function isVariableBinding(value) {
79
420
  function isActionBinding(value) {
80
421
  return ActionBindingSchema.safeParse(value).success;
81
422
  }
423
+ function isAnimationConfig(value) {
424
+ return AnimationConfigSchema.safeParse(value).success;
425
+ }
82
426
  function generateDeterministicNodeId(prefix, indexOrKey) {
83
427
  const cleanPrefix = prefix.toLowerCase().replace(/[^a-z0-9_-]/g, "-");
84
428
  return `${cleanPrefix}_${indexOrKey}`;
@@ -110,30 +454,30 @@ function validateNodeIdUniqueness(node) {
110
454
  }
111
455
 
112
456
  // src/manifest.ts
113
- import { z as z2 } from "zod";
114
- var ManifestAssetItemSchema = z2.object({
115
- id: z2.string().min(1, "Asset ID cannot be empty"),
116
- path: z2.string().min(1, "Asset archive path cannot be empty"),
117
- mimeType: z2.string().min(1, "MIME type cannot be empty"),
118
- size: z2.number().nonnegative("Asset size must be non-negative"),
119
- checksum: z2.string().optional()
457
+ import { z as z4 } from "zod";
458
+ var ManifestAssetItemSchema = z4.object({
459
+ id: z4.string().min(1, "Asset ID cannot be empty"),
460
+ path: z4.string().min(1, "Asset archive path cannot be empty"),
461
+ mimeType: z4.string().min(1, "MIME type cannot be empty"),
462
+ size: z4.number().nonnegative("Asset size must be non-negative"),
463
+ checksum: z4.string().optional()
120
464
  });
121
- var ManifestSchema = z2.object({
122
- schema: z2.literal(SCHEMA_NAME).default(SCHEMA_NAME),
123
- schemaVersion: z2.string().min(1, "Schema version cannot be empty").default("1.0.0"),
124
- packageVersion: z2.string().min(1, "Package version cannot be empty").default("1.0.0"),
125
- builderCompatibility: z2.string().default(">=0.1.0"),
126
- requiredComponents: z2.array(z2.string()).default([]),
127
- requiredCapabilities: z2.array(z2.string()).default([]),
128
- assets: z2.array(ManifestAssetItemSchema).default([]),
129
- createdAt: z2.string().optional()
465
+ var ManifestSchema = z4.object({
466
+ schema: z4.literal(SCHEMA_NAME).default(SCHEMA_NAME),
467
+ schemaVersion: z4.string().min(1, "Schema version cannot be empty").default("1.0.0"),
468
+ packageVersion: z4.string().min(1, "Package version cannot be empty").default("1.0.0"),
469
+ builderCompatibility: z4.string().default(">=0.1.0"),
470
+ requiredComponents: z4.array(z4.string()).default([]),
471
+ requiredCapabilities: z4.array(z4.string()).default([]),
472
+ assets: z4.array(ManifestAssetItemSchema).default([]),
473
+ createdAt: z4.string().optional()
130
474
  });
131
475
  function isManifest(value) {
132
476
  return ManifestSchema.safeParse(value).success;
133
477
  }
134
478
 
135
479
  // src/template.ts
136
- import { z as z3 } from "zod";
480
+ import { z as z5 } from "zod";
137
481
  var DANGEROUS_URI_PATTERN = /^(javascript:|vbscript:|data:(?!image\/))|<script/i;
138
482
  function isSafeThumbnailUrl(url) {
139
483
  if (!url || typeof url !== "string") return false;
@@ -142,49 +486,49 @@ function isSafeThumbnailUrl(url) {
142
486
  if (DANGEROUS_URI_PATTERN.test(trimmed)) return false;
143
487
  return true;
144
488
  }
145
- var SafeThumbnailUrlSchema = z3.string().min(1, "Thumbnail URL cannot be empty").refine(
489
+ var SafeThumbnailUrlSchema = z5.string().min(1, "Thumbnail URL cannot be empty").refine(
146
490
  (url) => isSafeThumbnailUrl(url),
147
491
  { message: "Thumbnail URL contains an unsafe protocol or payload" }
148
492
  );
149
- var SafeThumbnailObjectSchema = z3.object({
493
+ var SafeThumbnailObjectSchema = z5.object({
150
494
  url: SafeThumbnailUrlSchema,
151
- alt: z3.string().optional(),
152
- width: z3.number().positive().optional(),
153
- height: z3.number().positive().optional()
495
+ alt: z5.string().optional(),
496
+ width: z5.number().positive().optional(),
497
+ height: z5.number().positive().optional()
154
498
  });
155
- var SafeThumbnailSchema = z3.union([
499
+ var SafeThumbnailSchema = z5.union([
156
500
  AssetReferenceSchema,
157
501
  SafeThumbnailObjectSchema,
158
502
  SafeThumbnailUrlSchema
159
503
  ]);
160
- var TemplatePackageRefSchema = z3.object({
161
- path: z3.string().optional(),
504
+ var TemplatePackageRefSchema = z5.object({
505
+ path: z5.string().optional(),
162
506
  url: SafeThumbnailUrlSchema.optional(),
163
- checksum: z3.string().optional(),
164
- format: z3.enum(["stora", "json"]).default("stora")
507
+ checksum: z5.string().optional(),
508
+ format: z5.enum(["stora", "json"]).default("stora")
165
509
  });
166
- var TemplateRequirementsSchema = z3.object({
167
- requiredComponents: z3.array(z3.string()).default([]),
168
- requiredCapabilities: z3.array(z3.string()).default([])
510
+ var TemplateRequirementsSchema = z5.object({
511
+ requiredComponents: z5.array(z5.string()).default([]),
512
+ requiredCapabilities: z5.array(z5.string()).default([])
169
513
  });
170
- var TemplateRecordSchema = z3.object({
171
- id: z3.string().min(1, "Template ID must be a non-empty string"),
172
- name: z3.string().min(1, "Template name must be a non-empty string"),
173
- description: z3.string().optional().default(""),
174
- category: z3.string().optional().default("general"),
175
- tags: z3.array(z3.string()).optional().default([]),
514
+ var TemplateRecordSchema = z5.object({
515
+ id: z5.string().min(1, "Template ID must be a non-empty string"),
516
+ name: z5.string().min(1, "Template name must be a non-empty string"),
517
+ description: z5.string().optional().default(""),
518
+ category: z5.string().optional().default("general"),
519
+ tags: z5.array(z5.string()).optional().default([]),
176
520
  thumbnail: SafeThumbnailSchema.optional(),
177
- author: z3.string().optional().default(""),
178
- version: z3.string().optional().default("1.0.0"),
521
+ author: z5.string().optional().default(""),
522
+ version: z5.string().optional().default("1.0.0"),
179
523
  document: PageDocumentSchema.optional(),
180
524
  packageReference: TemplatePackageRefSchema.optional(),
181
525
  requirements: TemplateRequirementsSchema.default({
182
526
  requiredComponents: [],
183
527
  requiredCapabilities: []
184
528
  }),
185
- createdAt: z3.string().optional(),
186
- updatedAt: z3.string().optional(),
187
- custom: z3.record(z3.string(), z3.unknown()).optional()
529
+ createdAt: z5.string().optional(),
530
+ updatedAt: z5.string().optional(),
531
+ custom: z5.record(z5.string(), z5.unknown()).optional()
188
532
  });
189
533
  function isTemplateRecord(value) {
190
534
  return TemplateRecordSchema.safeParse(value).success;
@@ -461,6 +805,154 @@ var PAGE_DOCUMENT_JSON_SCHEMA_V1 = {
461
805
  },
462
806
  additionalProperties: false
463
807
  },
808
+ animationConfig: {
809
+ type: "object",
810
+ properties: {
811
+ type: {
812
+ type: "string",
813
+ default: "none",
814
+ description: "Scroll entrance animation type (e.g. fade, fade-up, zoom-in, slide-left)"
815
+ },
816
+ duration: {
817
+ type: "number",
818
+ minimum: 0,
819
+ default: 600,
820
+ description: "Animation duration in milliseconds"
821
+ },
822
+ delay: {
823
+ type: "number",
824
+ minimum: 0,
825
+ default: 0,
826
+ description: "Animation delay in milliseconds"
827
+ },
828
+ easing: {
829
+ type: "string",
830
+ default: "ease-out",
831
+ description: "CSS animation easing / transition timing function"
832
+ },
833
+ once: {
834
+ type: "boolean",
835
+ default: true,
836
+ description: "Whether scroll animation plays only once when entering viewport"
837
+ },
838
+ hoverEffect: {
839
+ type: "string",
840
+ default: "none",
841
+ description: "Hover micro-interaction effect (e.g. lift, scale, glow, tilt)"
842
+ },
843
+ loopEffect: {
844
+ type: "string",
845
+ default: "none",
846
+ description: "Continuous loop animation effect (e.g. pulse, bounce, spin, float)"
847
+ }
848
+ },
849
+ additionalProperties: false
850
+ },
851
+ actionStep: {
852
+ type: "object",
853
+ required: ["id", "type"],
854
+ properties: {
855
+ id: {
856
+ type: "string",
857
+ minLength: 1
858
+ },
859
+ type: {
860
+ type: "string",
861
+ enum: [
862
+ "api_request",
863
+ "navigate",
864
+ "set_state",
865
+ "reset_form",
866
+ "show_toast",
867
+ "open_modal",
868
+ "close_modal",
869
+ "copy_clipboard",
870
+ "custom_event"
871
+ ]
872
+ },
873
+ label: { type: "string" },
874
+ payload: { type: "object" },
875
+ condition: {
876
+ type: "object",
877
+ required: ["field", "operator"],
878
+ properties: {
879
+ field: { type: "string", minLength: 1 },
880
+ operator: {
881
+ type: "string",
882
+ enum: [
883
+ "equals",
884
+ "not_equals",
885
+ "contains",
886
+ "not_contains",
887
+ "is_truthy",
888
+ "is_falsy",
889
+ "gt",
890
+ "gte",
891
+ "lt",
892
+ "lte",
893
+ "regex"
894
+ ]
895
+ },
896
+ value: {}
897
+ },
898
+ additionalProperties: false
899
+ },
900
+ timeout: { type: "number", minimum: 1 },
901
+ continueOnError: { type: "boolean" },
902
+ onSuccess: {
903
+ type: "array",
904
+ items: { $ref: "#/definitions/actionStep" }
905
+ },
906
+ onError: {
907
+ type: "array",
908
+ items: { $ref: "#/definitions/actionStep" }
909
+ }
910
+ },
911
+ additionalProperties: false
912
+ },
913
+ actionPipeline: {
914
+ type: "object",
915
+ required: ["id", "trigger", "steps"],
916
+ properties: {
917
+ id: {
918
+ type: "string",
919
+ minLength: 1
920
+ },
921
+ trigger: {
922
+ type: "string",
923
+ enum: ["click", "submit", "change", "blur", "focus", "load"]
924
+ },
925
+ label: { type: "string" },
926
+ debounceMs: { type: "number", minimum: 0 },
927
+ preventDuplicate: { type: "boolean" },
928
+ enabled: { type: "boolean", default: true },
929
+ steps: {
930
+ type: "array",
931
+ items: { $ref: "#/definitions/actionStep" },
932
+ minItems: 1
933
+ }
934
+ },
935
+ additionalProperties: false
936
+ },
937
+ formConfig: {
938
+ type: "object",
939
+ required: ["formId"],
940
+ properties: {
941
+ formId: {
942
+ type: "string",
943
+ minLength: 1
944
+ },
945
+ resetOnSubmit: { type: "boolean", default: false },
946
+ scrollToFirstError: { type: "boolean", default: true },
947
+ validateOn: {
948
+ type: "string",
949
+ enum: ["blur", "change", "submit"],
950
+ default: "blur"
951
+ },
952
+ initialValues: { type: "object" }
953
+ },
954
+ additionalProperties: false
955
+ },
464
956
  node: {
465
957
  type: "object",
466
958
  required: ["id", "type"],
@@ -483,6 +975,20 @@ var PAGE_DOCUMENT_JSON_SCHEMA_V1 = {
483
975
  styles: {
484
976
  $ref: "#/definitions/responsiveStyles"
485
977
  },
978
+ animation: {
979
+ $ref: "#/definitions/animationConfig"
980
+ },
981
+ actions: {
982
+ type: "array",
983
+ items: {
984
+ $ref: "#/definitions/actionPipeline"
985
+ },
986
+ description: "Multi-step action pipelines bound to component events"
987
+ },
988
+ formConfig: {
989
+ $ref: "#/definitions/formConfig",
990
+ description: "Form container configuration and behavior"
991
+ },
486
992
  children: {
487
993
  type: "array",
488
994
  items: {
@@ -819,44 +1325,325 @@ var TEMPLATE_RECORD_JSON_SCHEMA_V1 = {
819
1325
  function getTemplateRecordJsonSchema() {
820
1326
  return TEMPLATE_RECORD_JSON_SCHEMA_V1;
821
1327
  }
1328
+ var ACTION_PIPELINE_JSON_SCHEMA_V1 = {
1329
+ $schema: "http://json-schema.org/draft-07/schema#",
1330
+ $id: "https://schema.stora.page/v1/action-pipeline.json",
1331
+ title: "StoraActionPipeline",
1332
+ description: "Action Pipeline schema definition for KUBUILD event workflows",
1333
+ type: "object",
1334
+ required: ["id", "trigger", "steps"],
1335
+ additionalProperties: false,
1336
+ properties: {
1337
+ id: {
1338
+ type: "string",
1339
+ minLength: 1,
1340
+ description: "Unique pipeline identifier"
1341
+ },
1342
+ trigger: {
1343
+ type: "string",
1344
+ enum: ["click", "submit", "change", "blur", "focus", "load"],
1345
+ description: "DOM or component event that triggers the action pipeline"
1346
+ },
1347
+ label: {
1348
+ type: "string",
1349
+ description: "Human readable label for the action pipeline"
1350
+ },
1351
+ debounceMs: {
1352
+ type: "number",
1353
+ minimum: 0,
1354
+ description: "Debounce duration in milliseconds"
1355
+ },
1356
+ preventDuplicate: {
1357
+ type: "boolean",
1358
+ description: "Prevent concurrent duplicate pipeline executions"
1359
+ },
1360
+ enabled: {
1361
+ type: "boolean",
1362
+ default: true,
1363
+ description: "Whether the pipeline is currently active"
1364
+ },
1365
+ steps: {
1366
+ type: "array",
1367
+ items: { $ref: "#/definitions/actionStep" },
1368
+ minItems: 1,
1369
+ description: "Ordered sequence of action steps to execute"
1370
+ }
1371
+ },
1372
+ definitions: {
1373
+ actionStep: {
1374
+ type: "object",
1375
+ required: ["id", "type"],
1376
+ properties: {
1377
+ id: {
1378
+ type: "string",
1379
+ minLength: 1
1380
+ },
1381
+ type: {
1382
+ type: "string",
1383
+ enum: [
1384
+ "api_request",
1385
+ "navigate",
1386
+ "set_state",
1387
+ "reset_form",
1388
+ "show_toast",
1389
+ "open_modal",
1390
+ "close_modal",
1391
+ "copy_clipboard",
1392
+ "custom_event"
1393
+ ]
1394
+ },
1395
+ label: { type: "string" },
1396
+ payload: { type: "object" },
1397
+ condition: {
1398
+ type: "object",
1399
+ required: ["field", "operator"],
1400
+ properties: {
1401
+ field: { type: "string", minLength: 1 },
1402
+ operator: {
1403
+ type: "string",
1404
+ enum: [
1405
+ "equals",
1406
+ "not_equals",
1407
+ "contains",
1408
+ "not_contains",
1409
+ "is_truthy",
1410
+ "is_falsy",
1411
+ "gt",
1412
+ "gte",
1413
+ "lt",
1414
+ "lte",
1415
+ "regex"
1416
+ ]
1417
+ },
1418
+ value: {}
1419
+ },
1420
+ additionalProperties: false
1421
+ },
1422
+ timeout: { type: "number", minimum: 1 },
1423
+ continueOnError: { type: "boolean" },
1424
+ onSuccess: {
1425
+ type: "array",
1426
+ items: { $ref: "#/definitions/actionStep" }
1427
+ },
1428
+ onError: {
1429
+ type: "array",
1430
+ items: { $ref: "#/definitions/actionStep" }
1431
+ }
1432
+ },
1433
+ additionalProperties: false
1434
+ }
1435
+ }
1436
+ };
1437
+ function getActionPipelineJsonSchema() {
1438
+ return ACTION_PIPELINE_JSON_SCHEMA_V1;
1439
+ }
1440
+ var FORM_CONFIG_JSON_SCHEMA_V1 = {
1441
+ $schema: "http://json-schema.org/draft-07/schema#",
1442
+ $id: "https://schema.stora.page/v1/form-config.json",
1443
+ title: "StoraFormConfig",
1444
+ description: "Form container configuration and behavior definition for KUBUILD",
1445
+ type: "object",
1446
+ required: ["formId"],
1447
+ additionalProperties: false,
1448
+ properties: {
1449
+ formId: {
1450
+ type: "string",
1451
+ minLength: 1,
1452
+ description: "Unique identifier for the form boundary"
1453
+ },
1454
+ resetOnSubmit: {
1455
+ type: "boolean",
1456
+ default: false,
1457
+ description: "Whether to reset form field values after successful submission"
1458
+ },
1459
+ scrollToFirstError: {
1460
+ type: "boolean",
1461
+ default: true,
1462
+ description: "Auto-scroll viewport to the first invalid input on validation failure"
1463
+ },
1464
+ validateOn: {
1465
+ type: "string",
1466
+ enum: ["blur", "change", "submit"],
1467
+ default: "blur",
1468
+ description: "Default trigger event for field validation evaluation"
1469
+ },
1470
+ initialValues: {
1471
+ type: "object",
1472
+ description: "Initial state values populated in form fields"
1473
+ }
1474
+ }
1475
+ };
1476
+ function getFormConfigJsonSchema() {
1477
+ return FORM_CONFIG_JSON_SCHEMA_V1;
1478
+ }
1479
+ var FORM_FIELD_BINDING_JSON_SCHEMA_V1 = {
1480
+ $schema: "http://json-schema.org/draft-07/schema#",
1481
+ $id: "https://schema.stora.page/v1/form-field-binding.json",
1482
+ title: "StoraFormFieldBinding",
1483
+ description: "Form field binding definition connecting input elements to form state runtime",
1484
+ type: "object",
1485
+ required: ["name"],
1486
+ additionalProperties: false,
1487
+ properties: {
1488
+ name: {
1489
+ type: "string",
1490
+ minLength: 1,
1491
+ description: "Field state property key"
1492
+ },
1493
+ label: {
1494
+ type: "string",
1495
+ description: "Display label for the field"
1496
+ },
1497
+ defaultValue: {
1498
+ description: "Initial default value if not overridden by form initialValues"
1499
+ },
1500
+ rules: {
1501
+ type: "array",
1502
+ items: { $ref: "#/definitions/validationRule" },
1503
+ default: [],
1504
+ description: "Validation rules applied to the field value"
1505
+ },
1506
+ validateOn: {
1507
+ type: "string",
1508
+ enum: ["blur", "change", "submit"],
1509
+ default: "blur",
1510
+ description: "Field-specific validation trigger timing"
1511
+ },
1512
+ transform: {
1513
+ type: "string",
1514
+ enum: ["trim", "lowercase", "uppercase", "number"],
1515
+ description: "Value transformation applied prior to validation and state storage"
1516
+ },
1517
+ disabled: {
1518
+ type: "boolean",
1519
+ description: "Whether the field is disabled"
1520
+ },
1521
+ required: {
1522
+ type: "boolean",
1523
+ description: "Whether the field is required (shorthand rule)"
1524
+ }
1525
+ },
1526
+ definitions: {
1527
+ validationRule: {
1528
+ type: "object",
1529
+ required: ["type", "message"],
1530
+ properties: {
1531
+ type: {
1532
+ type: "string",
1533
+ enum: [
1534
+ "required",
1535
+ "email",
1536
+ "url",
1537
+ "min_length",
1538
+ "max_length",
1539
+ "numeric_min",
1540
+ "numeric_max",
1541
+ "pattern",
1542
+ "match_field",
1543
+ "custom_regex"
1544
+ ]
1545
+ },
1546
+ value: {},
1547
+ message: {
1548
+ type: "string",
1549
+ minLength: 1
1550
+ }
1551
+ },
1552
+ additionalProperties: false
1553
+ }
1554
+ }
1555
+ };
1556
+ function getFormFieldBindingJsonSchema() {
1557
+ return FORM_FIELD_BINDING_JSON_SCHEMA_V1;
1558
+ }
822
1559
  export {
1560
+ ACTION_PIPELINE_JSON_SCHEMA_V1,
823
1561
  ActionBindingSchema,
1562
+ ActionPipelineSchema,
1563
+ ActionStepConditionSchema,
1564
+ ActionStepSchema,
1565
+ ActionStepTypeSchema,
1566
+ ActionTriggerSchema,
1567
+ ActionTriggerTypeSchema,
1568
+ AnimationConfigSchema,
1569
+ ApiRequestStepPayloadSchema,
824
1570
  AssetReferenceSchema,
825
1571
  CURRENT_SCHEMA_VERSION,
1572
+ CloseModalStepPayloadSchema,
1573
+ ConditionOperatorSchema,
1574
+ CopyClipboardStepPayloadSchema,
1575
+ CustomEventStepPayloadSchema,
1576
+ DEFAULT_ANIMATION_CONFIG,
826
1577
  DocumentMetadataSchema,
1578
+ FORM_CONFIG_JSON_SCHEMA_V1,
1579
+ FORM_FIELD_BINDING_JSON_SCHEMA_V1,
1580
+ FormConfigSchema,
1581
+ FormFieldBindingSchema,
827
1582
  MANIFEST_JSON_SCHEMA_V1,
828
1583
  ManifestAssetItemSchema,
829
1584
  ManifestSchema,
1585
+ NavigateStepPayloadSchema,
830
1586
  NodeSchema,
1587
+ OpenModalStepPayloadSchema,
831
1588
  PAGE_DOCUMENT_JSON_SCHEMA_V1,
832
1589
  PageDocumentSchema,
833
1590
  PseudoStateStylesSchema,
1591
+ ResetFormStepPayloadSchema,
834
1592
  ResponsiveStylesSchema,
835
1593
  RootPageNodeSchema,
836
1594
  SCHEMA_NAME,
837
1595
  SafeThumbnailObjectSchema,
838
1596
  SafeThumbnailSchema,
839
1597
  SafeThumbnailUrlSchema,
1598
+ SetStateStepPayloadSchema,
1599
+ ShowToastStepPayloadSchema,
1600
+ StepPayloadSchemas,
840
1601
  StyleDefinitionSchema,
841
1602
  StyleValueSchema,
842
1603
  TEMPLATE_RECORD_JSON_SCHEMA_V1,
843
1604
  TemplatePackageRefSchema,
844
1605
  TemplateRecordSchema,
845
1606
  TemplateRequirementsSchema,
1607
+ ValidateOnEventSchema,
1608
+ ValidationRuleSchema,
1609
+ ValidationRuleTypeSchema,
846
1610
  VariableBindingSchema,
847
1611
  collectNodeIds,
848
1612
  generateDeterministicNodeId,
1613
+ getActionPipelineJsonSchema,
1614
+ getFormConfigJsonSchema,
1615
+ getFormFieldBindingJsonSchema,
849
1616
  getManifestJsonSchema,
850
1617
  getPageDocumentJsonSchema,
851
1618
  getTemplateRecordJsonSchema,
852
1619
  isActionBinding,
1620
+ isActionPipeline,
1621
+ isActionStep,
1622
+ isActionStepCondition,
1623
+ isActionStepType,
1624
+ isActionTriggerType,
1625
+ isAnimationConfig,
853
1626
  isAssetReference,
1627
+ isConditionOperator,
1628
+ isFormConfig,
1629
+ isFormFieldBinding,
854
1630
  isManifest,
1631
+ isSafeActionUrl,
855
1632
  isSafeThumbnail,
856
1633
  isSafeThumbnailUrl,
857
1634
  isTemplateRecord,
1635
+ isValidateOnEvent,
1636
+ isValidationRule,
1637
+ isValidationRuleType,
858
1638
  isVariableBinding,
1639
+ sanitizeActionPayload,
1640
+ sanitizeActionPipeline,
1641
+ sanitizeActionStep,
1642
+ sanitizeActionString,
1643
+ sanitizeActionUrl,
1644
+ sanitizeActionValue,
859
1645
  starterPageFixture,
1646
+ validateActionStepPayload,
860
1647
  validateNodeIdUniqueness
861
1648
  };
862
1649
  //# sourceMappingURL=index.js.map