@kubuild/schema 0.1.0 → 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,56 +1,368 @@
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
351
  }).passthrough().default({});
40
- var AnimationConfigSchema = z.object({
41
- type: z.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
352
+ var AnimationConfigSchema = z3.object({
353
+ type: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
42
354
  message: "Animation type contains a disallowed or unsafe pattern"
43
355
  }).optional().default("none"),
44
- duration: z.number().min(0, "Duration must be non-negative").optional().default(600),
45
- delay: z.number().min(0, "Delay must be non-negative").optional().default(0),
46
- easing: z.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
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), {
47
359
  message: "Animation easing contains a disallowed or unsafe pattern"
48
360
  }).optional().default("ease-out"),
49
- once: z.boolean().optional().default(true),
50
- hoverEffect: z.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
361
+ once: z3.boolean().optional().default(true),
362
+ hoverEffect: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
51
363
  message: "Hover effect contains a disallowed or unsafe pattern"
52
364
  }).optional().default("none"),
53
- loopEffect: z.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
365
+ loopEffect: z3.string().refine((value) => !DANGEROUS_STYLE_VALUE_PATTERN.test(value), {
54
366
  message: "Loop effect contains a disallowed or unsafe pattern"
55
367
  }).optional().default("none")
56
368
  });
@@ -63,14 +375,16 @@ var DEFAULT_ANIMATION_CONFIG = {
63
375
  hoverEffect: "none",
64
376
  loopEffect: "none"
65
377
  };
66
- var NodeSchema = z.lazy(
67
- () => z.object({
68
- id: z.string().min(1, "Node ID must be a non-empty string"),
69
- type: z.string().min(1, "Node type must be a non-empty string"),
70
- props: z.record(z.string(), z.unknown()).optional().default({}),
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({}),
71
383
  styles: ResponsiveStylesSchema.optional().default({}),
72
384
  animation: AnimationConfigSchema.optional(),
73
- children: z.array(NodeSchema).optional().default([])
385
+ actions: z3.array(ActionPipelineSchema).optional(),
386
+ formConfig: FormConfigSchema.optional(),
387
+ children: z3.array(NodeSchema).optional().default([])
74
388
  })
75
389
  );
76
390
  var RootPageNodeSchema = NodeSchema.refine(
@@ -80,20 +394,20 @@ var RootPageNodeSchema = NodeSchema.refine(
80
394
  path: ["type"]
81
395
  }
82
396
  );
83
- var DocumentMetadataSchema = z.object({
84
- title: z.string().min(1, "Title is required").default("Untitled Page"),
85
- description: z.string().optional().default(""),
86
- author: z.string().optional().default(""),
87
- createdAt: z.string().optional(),
88
- updatedAt: z.string().optional(),
89
- tags: z.array(z.string()).optional().default([]),
90
- category: z.string().optional().default("general"),
91
- version: z.string().optional().default("1.0.0"),
92
- 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()
93
407
  });
94
- var PageDocumentSchema = z.object({
95
- schema: z.literal(SCHEMA_NAME),
96
- 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),
97
411
  metadata: DocumentMetadataSchema.optional(),
98
412
  document: RootPageNodeSchema
99
413
  });
@@ -140,30 +454,30 @@ function validateNodeIdUniqueness(node) {
140
454
  }
141
455
 
142
456
  // src/manifest.ts
143
- import { z as z2 } from "zod";
144
- var ManifestAssetItemSchema = z2.object({
145
- id: z2.string().min(1, "Asset ID cannot be empty"),
146
- path: z2.string().min(1, "Asset archive path cannot be empty"),
147
- mimeType: z2.string().min(1, "MIME type cannot be empty"),
148
- size: z2.number().nonnegative("Asset size must be non-negative"),
149
- 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()
150
464
  });
151
- var ManifestSchema = z2.object({
152
- schema: z2.literal(SCHEMA_NAME).default(SCHEMA_NAME),
153
- schemaVersion: z2.string().min(1, "Schema version cannot be empty").default("1.0.0"),
154
- packageVersion: z2.string().min(1, "Package version cannot be empty").default("1.0.0"),
155
- builderCompatibility: z2.string().default(">=0.1.0"),
156
- requiredComponents: z2.array(z2.string()).default([]),
157
- requiredCapabilities: z2.array(z2.string()).default([]),
158
- assets: z2.array(ManifestAssetItemSchema).default([]),
159
- 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()
160
474
  });
161
475
  function isManifest(value) {
162
476
  return ManifestSchema.safeParse(value).success;
163
477
  }
164
478
 
165
479
  // src/template.ts
166
- import { z as z3 } from "zod";
480
+ import { z as z5 } from "zod";
167
481
  var DANGEROUS_URI_PATTERN = /^(javascript:|vbscript:|data:(?!image\/))|<script/i;
168
482
  function isSafeThumbnailUrl(url) {
169
483
  if (!url || typeof url !== "string") return false;
@@ -172,49 +486,49 @@ function isSafeThumbnailUrl(url) {
172
486
  if (DANGEROUS_URI_PATTERN.test(trimmed)) return false;
173
487
  return true;
174
488
  }
175
- 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(
176
490
  (url) => isSafeThumbnailUrl(url),
177
491
  { message: "Thumbnail URL contains an unsafe protocol or payload" }
178
492
  );
179
- var SafeThumbnailObjectSchema = z3.object({
493
+ var SafeThumbnailObjectSchema = z5.object({
180
494
  url: SafeThumbnailUrlSchema,
181
- alt: z3.string().optional(),
182
- width: z3.number().positive().optional(),
183
- height: z3.number().positive().optional()
495
+ alt: z5.string().optional(),
496
+ width: z5.number().positive().optional(),
497
+ height: z5.number().positive().optional()
184
498
  });
185
- var SafeThumbnailSchema = z3.union([
499
+ var SafeThumbnailSchema = z5.union([
186
500
  AssetReferenceSchema,
187
501
  SafeThumbnailObjectSchema,
188
502
  SafeThumbnailUrlSchema
189
503
  ]);
190
- var TemplatePackageRefSchema = z3.object({
191
- path: z3.string().optional(),
504
+ var TemplatePackageRefSchema = z5.object({
505
+ path: z5.string().optional(),
192
506
  url: SafeThumbnailUrlSchema.optional(),
193
- checksum: z3.string().optional(),
194
- format: z3.enum(["stora", "json"]).default("stora")
507
+ checksum: z5.string().optional(),
508
+ format: z5.enum(["stora", "json"]).default("stora")
195
509
  });
196
- var TemplateRequirementsSchema = z3.object({
197
- requiredComponents: z3.array(z3.string()).default([]),
198
- 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([])
199
513
  });
200
- var TemplateRecordSchema = z3.object({
201
- id: z3.string().min(1, "Template ID must be a non-empty string"),
202
- name: z3.string().min(1, "Template name must be a non-empty string"),
203
- description: z3.string().optional().default(""),
204
- category: z3.string().optional().default("general"),
205
- 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([]),
206
520
  thumbnail: SafeThumbnailSchema.optional(),
207
- author: z3.string().optional().default(""),
208
- version: z3.string().optional().default("1.0.0"),
521
+ author: z5.string().optional().default(""),
522
+ version: z5.string().optional().default("1.0.0"),
209
523
  document: PageDocumentSchema.optional(),
210
524
  packageReference: TemplatePackageRefSchema.optional(),
211
525
  requirements: TemplateRequirementsSchema.default({
212
526
  requiredComponents: [],
213
527
  requiredCapabilities: []
214
528
  }),
215
- createdAt: z3.string().optional(),
216
- updatedAt: z3.string().optional(),
217
- 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()
218
532
  });
219
533
  function isTemplateRecord(value) {
220
534
  return TemplateRecordSchema.safeParse(value).success;
@@ -534,6 +848,111 @@ var PAGE_DOCUMENT_JSON_SCHEMA_V1 = {
534
848
  },
535
849
  additionalProperties: false
536
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
+ },
537
956
  node: {
538
957
  type: "object",
539
958
  required: ["id", "type"],
@@ -559,6 +978,17 @@ var PAGE_DOCUMENT_JSON_SCHEMA_V1 = {
559
978
  animation: {
560
979
  $ref: "#/definitions/animationConfig"
561
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
+ },
562
992
  children: {
563
993
  type: "array",
564
994
  items: {
@@ -895,47 +1325,325 @@ var TEMPLATE_RECORD_JSON_SCHEMA_V1 = {
895
1325
  function getTemplateRecordJsonSchema() {
896
1326
  return TEMPLATE_RECORD_JSON_SCHEMA_V1;
897
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
+ }
898
1559
  export {
1560
+ ACTION_PIPELINE_JSON_SCHEMA_V1,
899
1561
  ActionBindingSchema,
1562
+ ActionPipelineSchema,
1563
+ ActionStepConditionSchema,
1564
+ ActionStepSchema,
1565
+ ActionStepTypeSchema,
1566
+ ActionTriggerSchema,
1567
+ ActionTriggerTypeSchema,
900
1568
  AnimationConfigSchema,
1569
+ ApiRequestStepPayloadSchema,
901
1570
  AssetReferenceSchema,
902
1571
  CURRENT_SCHEMA_VERSION,
1572
+ CloseModalStepPayloadSchema,
1573
+ ConditionOperatorSchema,
1574
+ CopyClipboardStepPayloadSchema,
1575
+ CustomEventStepPayloadSchema,
903
1576
  DEFAULT_ANIMATION_CONFIG,
904
1577
  DocumentMetadataSchema,
1578
+ FORM_CONFIG_JSON_SCHEMA_V1,
1579
+ FORM_FIELD_BINDING_JSON_SCHEMA_V1,
1580
+ FormConfigSchema,
1581
+ FormFieldBindingSchema,
905
1582
  MANIFEST_JSON_SCHEMA_V1,
906
1583
  ManifestAssetItemSchema,
907
1584
  ManifestSchema,
1585
+ NavigateStepPayloadSchema,
908
1586
  NodeSchema,
1587
+ OpenModalStepPayloadSchema,
909
1588
  PAGE_DOCUMENT_JSON_SCHEMA_V1,
910
1589
  PageDocumentSchema,
911
1590
  PseudoStateStylesSchema,
1591
+ ResetFormStepPayloadSchema,
912
1592
  ResponsiveStylesSchema,
913
1593
  RootPageNodeSchema,
914
1594
  SCHEMA_NAME,
915
1595
  SafeThumbnailObjectSchema,
916
1596
  SafeThumbnailSchema,
917
1597
  SafeThumbnailUrlSchema,
1598
+ SetStateStepPayloadSchema,
1599
+ ShowToastStepPayloadSchema,
1600
+ StepPayloadSchemas,
918
1601
  StyleDefinitionSchema,
919
1602
  StyleValueSchema,
920
1603
  TEMPLATE_RECORD_JSON_SCHEMA_V1,
921
1604
  TemplatePackageRefSchema,
922
1605
  TemplateRecordSchema,
923
1606
  TemplateRequirementsSchema,
1607
+ ValidateOnEventSchema,
1608
+ ValidationRuleSchema,
1609
+ ValidationRuleTypeSchema,
924
1610
  VariableBindingSchema,
925
1611
  collectNodeIds,
926
1612
  generateDeterministicNodeId,
1613
+ getActionPipelineJsonSchema,
1614
+ getFormConfigJsonSchema,
1615
+ getFormFieldBindingJsonSchema,
927
1616
  getManifestJsonSchema,
928
1617
  getPageDocumentJsonSchema,
929
1618
  getTemplateRecordJsonSchema,
930
1619
  isActionBinding,
1620
+ isActionPipeline,
1621
+ isActionStep,
1622
+ isActionStepCondition,
1623
+ isActionStepType,
1624
+ isActionTriggerType,
931
1625
  isAnimationConfig,
932
1626
  isAssetReference,
1627
+ isConditionOperator,
1628
+ isFormConfig,
1629
+ isFormFieldBinding,
933
1630
  isManifest,
1631
+ isSafeActionUrl,
934
1632
  isSafeThumbnail,
935
1633
  isSafeThumbnailUrl,
936
1634
  isTemplateRecord,
1635
+ isValidateOnEvent,
1636
+ isValidationRule,
1637
+ isValidationRuleType,
937
1638
  isVariableBinding,
1639
+ sanitizeActionPayload,
1640
+ sanitizeActionPipeline,
1641
+ sanitizeActionStep,
1642
+ sanitizeActionString,
1643
+ sanitizeActionUrl,
1644
+ sanitizeActionValue,
938
1645
  starterPageFixture,
1646
+ validateActionStepPayload,
939
1647
  validateNodeIdUniqueness
940
1648
  };
941
1649
  //# sourceMappingURL=index.js.map