@getrheo/contracts 1.0.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.
Files changed (81) hide show
  1. package/dist/animations.d.ts +226 -0
  2. package/dist/animations.js +1160 -0
  3. package/dist/animations.js.map +1 -0
  4. package/dist/appIntegrations.d.ts +175 -0
  5. package/dist/appIntegrations.js +60 -0
  6. package/dist/appIntegrations.js.map +1 -0
  7. package/dist/billingPeriod.d.ts +26 -0
  8. package/dist/billingPeriod.js +39 -0
  9. package/dist/billingPeriod.js.map +1 -0
  10. package/dist/canvasEditorGates.d.ts +81 -0
  11. package/dist/canvasEditorGates.js +1460 -0
  12. package/dist/canvasEditorGates.js.map +1 -0
  13. package/dist/constants/index.d.ts +30 -0
  14. package/dist/constants/index.js +67 -0
  15. package/dist/constants/index.js.map +1 -0
  16. package/dist/dashboard.d.ts +181856 -0
  17. package/dist/dashboard.js +3348 -0
  18. package/dist/dashboard.js.map +1 -0
  19. package/dist/decisions.d.ts +575 -0
  20. package/dist/decisions.js +1209 -0
  21. package/dist/decisions.js.map +1 -0
  22. package/dist/events.d.ts +231 -0
  23. package/dist/events.js +63 -0
  24. package/dist/events.js.map +1 -0
  25. package/dist/experiments-DN8pQa_D.d.ts +530 -0
  26. package/dist/externalSurfaceIntegrations.d.ts +20 -0
  27. package/dist/externalSurfaceIntegrations.js +49 -0
  28. package/dist/externalSurfaceIntegrations.js.map +1 -0
  29. package/dist/externalSurfaces.d.ts +177 -0
  30. package/dist/externalSurfaces.js +1190 -0
  31. package/dist/externalSurfaces.js.map +1 -0
  32. package/dist/fields.d.ts +8 -0
  33. package/dist/fields.js +15 -0
  34. package/dist/fields.js.map +1 -0
  35. package/dist/flowManifestSchema-CtqygXCK.d.ts +50857 -0
  36. package/dist/flowTemplateComments.d.ts +23 -0
  37. package/dist/flowTemplateComments.js +14 -0
  38. package/dist/flowTemplateComments.js.map +1 -0
  39. package/dist/flowTemplates.d.ts +22 -0
  40. package/dist/flowTemplates.js +73 -0
  41. package/dist/flowTemplates.js.map +1 -0
  42. package/dist/identity.d.ts +35 -0
  43. package/dist/identity.js +18 -0
  44. package/dist/identity.js.map +1 -0
  45. package/dist/imageContentType.d.ts +11 -0
  46. package/dist/imageContentType.js +54 -0
  47. package/dist/imageContentType.js.map +1 -0
  48. package/dist/index.d.ts +224 -0
  49. package/dist/index.js +4557 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/layerUnion-BzXoAJLY.d.ts +34 -0
  52. package/dist/layers.d.ts +89844 -0
  53. package/dist/layers.js +1507 -0
  54. package/dist/layers.js.map +1 -0
  55. package/dist/layout-D0LpaKG-.d.ts +12896 -0
  56. package/dist/localized.d.ts +17 -0
  57. package/dist/localized.js +18 -0
  58. package/dist/localized.js.map +1 -0
  59. package/dist/manifest.d.ts +22192 -0
  60. package/dist/manifest.js +2163 -0
  61. package/dist/manifest.js.map +1 -0
  62. package/dist/media.d.ts +53 -0
  63. package/dist/media.js +55 -0
  64. package/dist/media.js.map +1 -0
  65. package/dist/planEntitlements.d.ts +65 -0
  66. package/dist/planEntitlements.js +117 -0
  67. package/dist/planEntitlements.js.map +1 -0
  68. package/dist/publish-exports.json +102 -0
  69. package/dist/screens.d.ts +33586 -0
  70. package/dist/screens.js +1439 -0
  71. package/dist/screens.js.map +1 -0
  72. package/dist/sdk.d.ts +145942 -0
  73. package/dist/sdk.js +3424 -0
  74. package/dist/sdk.js.map +1 -0
  75. package/dist/sdkAttributes.d.ts +11 -0
  76. package/dist/sdkAttributes.js +17 -0
  77. package/dist/sdkAttributes.js.map +1 -0
  78. package/dist/workspaceCapabilities.d.ts +15 -0
  79. package/dist/workspaceCapabilities.js +116 -0
  80. package/dist/workspaceCapabilities.js.map +1 -0
  81. package/package.json +162 -0
package/dist/index.js ADDED
@@ -0,0 +1,4557 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/localized.ts
4
+ var LocaleCode = z.string().regex(/^[a-z]{2}(-[A-Z]{2})?$/, 'locale must be like "en" or "en-US"');
5
+ var LocalizedTextSchema = z.object({
6
+ default: z.string().min(1, "default copy is required"),
7
+ translations: z.record(LocaleCode, z.string()).optional()
8
+ });
9
+ var resolveLocalizedText = (text, locale) => {
10
+ if (text.translations && text.translations[locale]) {
11
+ return text.translations[locale];
12
+ }
13
+ return text.default;
14
+ };
15
+
16
+ // src/hyperlinkHref.ts
17
+ var parseHyperlinkHref = (raw) => {
18
+ const t = raw.trim();
19
+ if (!t) return { ok: false };
20
+ let u;
21
+ try {
22
+ u = new URL(t);
23
+ } catch {
24
+ return { ok: false };
25
+ }
26
+ const scheme = u.protocol.replace(/:$/, "").toLowerCase();
27
+ if (scheme === "https") {
28
+ if (!u.hostname) return { ok: false };
29
+ return { ok: true, scheme: "https", host: u.hostname };
30
+ }
31
+ if (scheme === "mailto") {
32
+ return { ok: true, scheme: "mailto" };
33
+ }
34
+ return { ok: false };
35
+ };
36
+
37
+ // src/constants/index.ts
38
+ var ENVIRONMENTS = ["test", "live"];
39
+ var ROLES = ["owner", "editor"];
40
+ var STEP_TYPES = [
41
+ "carousel",
42
+ "single_choice",
43
+ "multiple_choice",
44
+ "text_input",
45
+ "scale_input",
46
+ "cta"
47
+ ];
48
+ var FIELD_CLASSIFICATIONS = ["safe", "sensitive"];
49
+ var MEDIA_TYPES = ["image", "font", "lottie", "video"];
50
+ var IMAGE_MIME_TYPES = [
51
+ "image/png",
52
+ "image/jpeg",
53
+ "image/webp",
54
+ "image/gif",
55
+ "image/svg+xml"
56
+ ];
57
+ var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
58
+ var LOTTIE_MIME_TYPES = ["application/json", "text/json"];
59
+ var MAX_LOTTIE_BYTES = 10 * 1024 * 1024;
60
+ var VIDEO_MIME_TYPES = ["video/mp4", "video/webm", "video/quicktime"];
61
+ var MAX_VIDEO_BYTES = 50 * 1024 * 1024;
62
+ var FONT_MIME_TYPES = [
63
+ "font/ttf",
64
+ "font/otf",
65
+ "font/woff",
66
+ "font/woff2",
67
+ "application/font-woff",
68
+ "application/font-woff2",
69
+ "application/x-font-ttf",
70
+ "application/x-font-otf",
71
+ "application/octet-stream"
72
+ ];
73
+ var FONT_FILE_EXTENSIONS = [".ttf", ".otf", ".woff", ".woff2"];
74
+ var MAX_FONT_BYTES = 10 * 1024 * 1024;
75
+ var EVENT_NAMES = [
76
+ "flow_started",
77
+ "step_viewed",
78
+ "step_completed",
79
+ "step_skipped",
80
+ "choice_selected",
81
+ "text_submitted",
82
+ "flow_completed",
83
+ "flow_abandoned",
84
+ "decision_evaluated",
85
+ "external_link_opened",
86
+ "surface_presented",
87
+ "surface_outcome",
88
+ "app_review_prompt_shown",
89
+ "app_review_prompt_dismissed",
90
+ /** Emitted once per provider id when merged SDK attributes first expose that attribution source (used for integration health checks). */
91
+ "attribution_context_observed",
92
+ /** Successful in-app purchase from an external surface (e.g. RevenueCat paywall); commerce fields live in `properties`. */
93
+ "iap_purchase"
94
+ ];
95
+ var PUBLISHABLE_KEY_PREFIX = "ob_pk_";
96
+ var API_VERSION = "v1";
97
+ var DEFAULT_LOCALE = "en";
98
+ var AUTOSAVE_DEBOUNCE_MS = 800;
99
+ var SDK_EVENT_FLUSH_MS = 5e3;
100
+
101
+ // src/mediaFileName.ts
102
+ var CONTENT_TYPE_EXTENSION = {
103
+ "image/png": ".png",
104
+ "image/jpeg": ".jpg",
105
+ "image/webp": ".webp",
106
+ "image/gif": ".gif",
107
+ "image/svg+xml": ".svg",
108
+ "application/json": ".json",
109
+ "text/json": ".json",
110
+ "video/mp4": ".mp4",
111
+ "video/webm": ".webm",
112
+ "video/quicktime": ".mov"
113
+ };
114
+ var splitMediaFileName = (name) => {
115
+ const raw = name?.trim() ?? "";
116
+ if (!raw) return { stem: "", extension: "" };
117
+ const dot = raw.lastIndexOf(".");
118
+ if (dot <= 0) return { stem: raw, extension: "" };
119
+ return { stem: raw.slice(0, dot), extension: raw.slice(dot) };
120
+ };
121
+ var mediaExtensionFromContentType = (contentType) => CONTENT_TYPE_EXTENSION[contentType] ?? "";
122
+ var mergeMediaFileNameStem = (stem, currentName, contentType) => {
123
+ const trimmed = stem.trim();
124
+ const { extension } = splitMediaFileName(currentName);
125
+ const ext = extension || mediaExtensionFromContentType(contentType);
126
+ return ext ? `${trimmed}${ext}` : trimmed;
127
+ };
128
+
129
+ // src/media.ts
130
+ var MediaTypeSchema = z.enum(MEDIA_TYPES);
131
+ var MediaReferenceSchema = z.object({
132
+ mediaAssetId: z.string().uuid()
133
+ });
134
+ var MediaAssetSchema = z.object({
135
+ id: z.string().uuid(),
136
+ orgId: z.string().uuid(),
137
+ type: MediaTypeSchema,
138
+ url: z.string().url(),
139
+ name: z.string().nullable().optional(),
140
+ contentType: z.string(),
141
+ sizeBytes: z.number().int().nonnegative(),
142
+ archivedAt: z.string().datetime().nullable().optional(),
143
+ createdAt: z.string().datetime()
144
+ });
145
+ var FIELD_KEY_RE = /^[a-z][a-z0-9_]*$/;
146
+ var FieldKeySchema = z.string().min(1).max(64).regex(FIELD_KEY_RE, "field key must be snake_case");
147
+ var FieldClassificationSchema = z.enum(FIELD_CLASSIFICATIONS);
148
+
149
+ // src/layers/layerSchemaRef.ts
150
+ var layerSchemaStore = {};
151
+ var LayerIdSchema = z.string().min(1).max(64).regex(/^lyr_[a-z0-9_]+$/i, "layer id must look like lyr_<id>");
152
+ var ScreenIdSchema = z.string().min(1).max(64).regex(/^scr_[a-z0-9_]+$/i, "screen id must look like scr_<id>");
153
+ var RESTING_MOTION_PRESETS = ["translate", "bounce", "scale", "pulse", "rotate"];
154
+ var RestingMotionPresetSchema = z.enum(RESTING_MOTION_PRESETS);
155
+ var RESTING_MOTION_SCALE_DIRECTIONS = ["up", "down"];
156
+ var RestingMotionScaleDirectionSchema = z.enum(RESTING_MOTION_SCALE_DIRECTIONS);
157
+ var RESTING_MOTION_ROTATE_DIRECTIONS = ["clockwise", "counterclockwise"];
158
+ var RestingMotionRotateDirectionSchema = z.enum(RESTING_MOTION_ROTATE_DIRECTIONS);
159
+ var RestingMotionSchema = z.object({
160
+ preset: RestingMotionPresetSchema,
161
+ /**
162
+ * Timeline segment length (ms): motion is active from start until
163
+ * start + durationMs. When {@link loop} is true, the preset pattern repeats
164
+ * every {@link cycleDurationMs} (or preset default) within this window.
165
+ */
166
+ durationMs: z.number().int().min(200).max(2e4).optional(),
167
+ /** When true, repeat the motion pattern within the timeline segment; default is one shot. */
168
+ loop: z.boolean().optional(),
169
+ /**
170
+ * Duration (ms) of one full pattern cycle when looping. Defaults per {@link RESTING_MOTION_DEFAULT_DURATION_MS}.
171
+ */
172
+ cycleDurationMs: z.number().int().min(200).max(2e4).optional(),
173
+ intensity: z.number().min(0).max(2).optional(),
174
+ /** Bounce preset only: vertical lift in px. When omitted, uses `14 * intensity` (default intensity 1 → 14). */
175
+ bounceAmplitudePx: z.number().min(1).max(80).optional(),
176
+ /** Scale preset: grow (+) or shrink (−) toward a peak, then return to 100%. */
177
+ scaleDirection: RestingMotionScaleDirectionSchema.optional(),
178
+ /**
179
+ * Scale preset: when true (default), each cycle goes rest → peak scale → rest.
180
+ * When false, ramps rest → peak and holds; with loop, the next cycle restarts from rest.
181
+ */
182
+ scaleSpringBack: z.boolean().optional(),
183
+ /**
184
+ * Scale preset: magnitude in % — growth above 100% (up to +400% = 5× at peak) or shrink toward
185
+ * 100%− (up to 90% so peak can be 10% size). See authoring caps in the layer editor.
186
+ */
187
+ scalePercent: z.number().min(0).max(400).optional(),
188
+ /**
189
+ * Scale preset: ms for one full out-and-back (rest → peak → rest). Timeline bar still sets
190
+ * {@link durationMs} (when the layer may animate); this controls how fast each cycle runs.
191
+ */
192
+ scalePatternDurationMs: z.number().int().min(200).max(2e4).optional(),
193
+ /** @deprecated Use {@link scalePercent} + {@link scaleDirection}. Kept for legacy manifests. */
194
+ scaleUpPercent: z.number().min(0).max(400).optional(),
195
+ /** @deprecated Use {@link scalePercent} + {@link scaleDirection}. Kept for legacy manifests. */
196
+ scaleDownPercent: z.number().min(0).max(90).optional(),
197
+ /**
198
+ * @deprecated Legacy vertical-only float (px). Prefer {@link translatePeakXPercent} / {@link translatePeakYPercent}.
199
+ */
200
+ translateRangePx: z.number().min(0).max(40).optional(),
201
+ /** @deprecated Legacy peak offsets in px. Prefer {@link translatePeakXPercent} / {@link translatePeakYPercent}. */
202
+ translatePeakXPx: z.number().min(-200).max(200).optional(),
203
+ /** @deprecated Legacy peak offsets in px. Prefer {@link translatePeakXPercent} / {@link translatePeakYPercent}. */
204
+ translatePeakYPx: z.number().min(-200).max(200).optional(),
205
+ /** Translate preset: peak X offset as % of the layer box (−200–200). Scaled by intensity. */
206
+ translatePeakXPercent: z.number().min(-200).max(200).optional(),
207
+ /** Translate preset: peak Y offset as % of the layer box (−200–200). Scaled by intensity. */
208
+ translatePeakYPercent: z.number().min(-200).max(200).optional(),
209
+ /**
210
+ * Translate preset: when true (default), each cycle goes rest → peak offset → rest. When false, ramp to
211
+ * peak and hold; with loop, the next cycle restarts from the origin.
212
+ */
213
+ translateSpringBack: z.boolean().optional(),
214
+ /** Rotate preset: target rotation in degrees (0–360), scaled by intensity. */
215
+ rotateMaxDeg: z.number().min(0).max(360).optional(),
216
+ /** Rotate preset: spin direction; omitted or `clockwise` → positive angles (default). */
217
+ rotateDirection: RestingMotionRotateDirectionSchema.optional(),
218
+ /**
219
+ * Rotate preset: when true (default), each cycle oscillates 0° → peak → 0°.
220
+ * When false, each cycle ramps 0° → peak and holds; with loop, the next cycle snaps to 0° and ramps again.
221
+ */
222
+ rotateSpringBack: z.boolean().optional(),
223
+ /** Pulse preset: minimum opacity at the dip (0–1). Omitted → `1 - 0.38 * intensity`. */
224
+ pulseMinOpacity: z.number().min(0).max(1).optional(),
225
+ /** Ms after the last mount/stagger clip ends before motion applies (authoring + scrub). */
226
+ delayMsAfterMountEnd: z.number().int().min(0).max(6e4).optional(),
227
+ /**
228
+ * Absolute start time (ms from screen mount). When set, overrides
229
+ * {@link delayMsAfterMountEnd} + mount-clip end so motion can sit between
230
+ * clips (e.g. after first entry, before exit) when multiple mounts exist.
231
+ */
232
+ timelineStartMs: z.number().int().min(0).max(36e5).optional()
233
+ }).strict();
234
+ var RestingMotionEntrySchema = RestingMotionSchema.extend({
235
+ id: z.string().min(1)
236
+ });
237
+
238
+ // src/layers/base.ts
239
+ var baseLayerShape = {
240
+ id: LayerIdSchema,
241
+ name: z.string().max(80).optional(),
242
+ restingMotion: RestingMotionSchema.optional(),
243
+ restingMotions: z.array(RestingMotionEntrySchema).optional()
244
+ };
245
+ var ThemedColorModesSchema = z.object({
246
+ light: z.string().min(1).optional(),
247
+ dark: z.string().min(1).optional()
248
+ }).strict().refine((o) => o.light !== void 0 || o.dark !== void 0, {
249
+ message: "at least one of light or dark is required"
250
+ });
251
+ var ThemedColorSchema = z.union([z.string().min(1), ThemedColorModesSchema]);
252
+ var DEFAULT_THEMED_FOREGROUND = {
253
+ light: "#000000",
254
+ dark: "#ffffff"
255
+ };
256
+ var PRIMARY_FILLED_LABEL = {
257
+ light: "#ffffff",
258
+ dark: "#000000"
259
+ };
260
+ var WIDTH_PRESETS = ["auto", "full", "1/2", "1/3", "2/3", "1/4", "3/4"];
261
+ var WidthValueSchema = z.union([z.enum(WIDTH_PRESETS), z.number().int().min(0).max(2e3)]);
262
+ var HEIGHT_PRESETS = ["auto", "full", "fill"];
263
+ var CommonLayoutHeightSchema = z.union([
264
+ z.enum(HEIGHT_PRESETS),
265
+ z.number().int().min(0).max(2e3)
266
+ ]);
267
+
268
+ // src/layers/styleCommon.ts
269
+ var NonNegativePxSchema = z.number().int().min(0);
270
+ var PaddingSchema = z.object({
271
+ t: NonNegativePxSchema.optional(),
272
+ r: NonNegativePxSchema.optional(),
273
+ b: NonNegativePxSchema.optional(),
274
+ l: NonNegativePxSchema.optional()
275
+ }).partial();
276
+ var BorderSchema = z.object({
277
+ width: z.number().int().min(0).max(20).optional(),
278
+ color: ThemedColorSchema.optional()
279
+ }).partial();
280
+ var DropShadowSchema = z.object({
281
+ offsetX: z.number().int().min(-100).max(100).optional(),
282
+ offsetY: z.number().int().min(-100).max(100).optional(),
283
+ blur: z.number().int().min(0).max(100).optional(),
284
+ spread: z.number().int().min(-50).max(50).optional(),
285
+ color: ThemedColorSchema.optional(),
286
+ opacity: z.number().min(0).max(1).optional()
287
+ }).partial();
288
+ var CommonStyleSchema = z.object({
289
+ padding: PaddingSchema.optional(),
290
+ margin: PaddingSchema.optional(),
291
+ radius: z.number().int().min(0).max(96).optional(),
292
+ background: ThemedColorSchema.optional(),
293
+ border: BorderSchema.optional(),
294
+ shadow: DropShadowSchema.optional(),
295
+ opacity: z.number().min(0).max(1).optional(),
296
+ width: WidthValueSchema.optional(),
297
+ /** Omit for normal flow; `'absolute'` removes the layer from flex flow (non-root only). */
298
+ position: z.literal("absolute").optional(),
299
+ /** Pixel insets when `position === 'absolute'` (same shape as padding). */
300
+ inset: PaddingSchema.optional(),
301
+ zIndex: z.number().int().min(-999).max(999).optional(),
302
+ /** Static rotation in degrees (CSS `rotate`); not timeline animation. */
303
+ rotate: z.number().min(-360).max(360).optional(),
304
+ /** Cross-axis size: `auto` (hug), `full`/`fill` (parent height), or fixed px. No fractions. */
305
+ height: CommonLayoutHeightSchema.optional(),
306
+ /** Stroke thickness in px for layers that render a stroke primitive (e.g. loader ring). */
307
+ strokeWidth: z.number().int().min(0).max(64).optional()
308
+ }).partial();
309
+ var TextStyleSchema = CommonStyleSchema.extend({
310
+ /**
311
+ * Logical font family: manifest `theme.fontFamily` when omitted, {@link TEXT_FONT_FAMILY_SYSTEM_UI}
312
+ * for the platform stack, or a custom name (matches `Branding.fontFamilies[].name` for uploaded fonts).
313
+ */
314
+ fontFamily: z.string().min(1).max(128).optional(),
315
+ fontSize: z.number().int().min(8).max(96).optional(),
316
+ fontWeight: z.number().int().min(100).max(900).optional(),
317
+ color: ThemedColorSchema.optional(),
318
+ align: z.enum(["left", "center", "right"]).optional(),
319
+ lineHeight: z.number().min(0.8).max(3).optional(),
320
+ /** Multiplier (0–1) applied to the resolved background color alpha only; text stays fully opaque unless `opacity` is set. */
321
+ backgroundOpacity: z.number().min(0).max(1).optional()
322
+ });
323
+ var ImageStyleSchema = CommonStyleSchema.extend({
324
+ fit: z.enum(["cover", "contain", "fill"]).optional(),
325
+ aspectRatio: z.number().positive().max(10).optional()
326
+ });
327
+ var IconStyleSchema = CommonStyleSchema.extend({
328
+ color: ThemedColorSchema.optional()
329
+ });
330
+ var ICON_FAMILIES = ["ionicons"];
331
+ var ButtonStyleSchema = CommonStyleSchema.extend({
332
+ fontSize: z.number().int().min(8).max(96).optional(),
333
+ fontWeight: z.number().int().min(100).max(900).optional(),
334
+ color: ThemedColorSchema.optional(),
335
+ align: z.enum(["left", "center", "right"]).optional()
336
+ });
337
+ var BUTTON_LAYER_VARIANTS = ["primary", "secondary", "ghost", "destructive"];
338
+ var ButtonLayerVariantSchema = z.enum(BUTTON_LAYER_VARIANTS);
339
+ var CommonStyleBreakpointsSchema = z.object({
340
+ sm: CommonStyleSchema.partial().optional(),
341
+ md: CommonStyleSchema.partial().optional(),
342
+ lg: CommonStyleSchema.partial().optional(),
343
+ xl: CommonStyleSchema.partial().optional(),
344
+ "2xl": CommonStyleSchema.partial().optional()
345
+ }).partial().optional();
346
+ var TextStyleBreakpointsSchema = z.object({
347
+ sm: TextStyleSchema.partial().optional(),
348
+ md: TextStyleSchema.partial().optional(),
349
+ lg: TextStyleSchema.partial().optional(),
350
+ xl: TextStyleSchema.partial().optional(),
351
+ "2xl": TextStyleSchema.partial().optional()
352
+ }).partial().optional();
353
+ var ImageStyleBreakpointsSchema = z.object({
354
+ sm: ImageStyleSchema.partial().optional(),
355
+ md: ImageStyleSchema.partial().optional(),
356
+ lg: ImageStyleSchema.partial().optional(),
357
+ xl: ImageStyleSchema.partial().optional(),
358
+ "2xl": ImageStyleSchema.partial().optional()
359
+ }).partial().optional();
360
+ var IconStyleBreakpointsSchema = z.object({
361
+ sm: IconStyleSchema.partial().optional(),
362
+ md: IconStyleSchema.partial().optional(),
363
+ lg: IconStyleSchema.partial().optional(),
364
+ xl: IconStyleSchema.partial().optional(),
365
+ "2xl": IconStyleSchema.partial().optional()
366
+ }).partial().optional();
367
+ var ButtonStyleBreakpointsSchema = z.object({
368
+ sm: ButtonStyleSchema.partial().optional(),
369
+ md: ButtonStyleSchema.partial().optional(),
370
+ lg: ButtonStyleSchema.partial().optional(),
371
+ xl: ButtonStyleSchema.partial().optional(),
372
+ "2xl": ButtonStyleSchema.partial().optional()
373
+ }).partial().optional();
374
+ var StackLayoutBreakpointPatchSchema = z.object({
375
+ gap: NonNegativePxSchema.optional(),
376
+ direction: z.enum(["vertical", "horizontal"]).optional()
377
+ }).partial();
378
+ var StackLayoutBreakpointsSchema = z.object({
379
+ sm: StackLayoutBreakpointPatchSchema.optional(),
380
+ md: StackLayoutBreakpointPatchSchema.optional(),
381
+ lg: StackLayoutBreakpointPatchSchema.optional(),
382
+ xl: StackLayoutBreakpointPatchSchema.optional(),
383
+ "2xl": StackLayoutBreakpointPatchSchema.optional()
384
+ }).partial().optional();
385
+ var ButtonLayoutBreakpointPatchSchema = z.object({
386
+ gap: NonNegativePxSchema.optional(),
387
+ direction: z.enum(["vertical", "horizontal"]).optional()
388
+ }).partial();
389
+ var ButtonLayoutBreakpointsSchema = z.object({
390
+ sm: ButtonLayoutBreakpointPatchSchema.optional(),
391
+ md: ButtonLayoutBreakpointPatchSchema.optional(),
392
+ lg: ButtonLayoutBreakpointPatchSchema.optional(),
393
+ xl: ButtonLayoutBreakpointPatchSchema.optional(),
394
+ "2xl": ButtonLayoutBreakpointPatchSchema.optional()
395
+ }).partial().optional();
396
+ var OS_PERMISSION_KEYS = [
397
+ "notifications",
398
+ "camera",
399
+ "microphone",
400
+ "photo_library",
401
+ "contacts",
402
+ "calendar",
403
+ "reminders",
404
+ "location_when_in_use",
405
+ "location_always",
406
+ "motion",
407
+ "bluetooth",
408
+ "app_tracking_transparency",
409
+ "speech_recognition",
410
+ "face_id",
411
+ "health_kit",
412
+ "media_library",
413
+ "local_network",
414
+ "nearby_interactions",
415
+ "nfc",
416
+ "full_screen_intent_android",
417
+ "sms_android",
418
+ "phone_android"
419
+ ];
420
+ var OsPermissionKeySchema = z.enum(OS_PERMISSION_KEYS);
421
+ var PERMISSION_CAPTURE_FIELD_KEY_PREFIX = "permission:";
422
+ var permissionCaptureFieldKey = (key) => `${PERMISSION_CAPTURE_FIELD_KEY_PREFIX}${key}`;
423
+ var oauthLoginResponseKey = (layerId) => `oauth:${layerId}`;
424
+ var emailPasswordAuthResponseKey = (layerId) => `email_pw:${layerId}`;
425
+ var PERMISSION_OUTCOME_VALUES = ["granted", "denied", "blocked"];
426
+ var PermissionOutcomeSchema = z.enum(PERMISSION_OUTCOME_VALUES);
427
+ var OS_PERMISSION_OUTCOME_CONTINUE = "continue";
428
+ var OS_PERMISSION_OUTCOME_END = "end";
429
+ var OsPermissionOutcomeBranchTargetSchema = z.union([
430
+ ScreenIdSchema,
431
+ z.literal(OS_PERMISSION_OUTCOME_CONTINUE),
432
+ z.literal(OS_PERMISSION_OUTCOME_END)
433
+ ]);
434
+ var OsPermissionOutcomesSchema = z.object({
435
+ granted: OsPermissionOutcomeBranchTargetSchema,
436
+ denied: OsPermissionOutcomeBranchTargetSchema,
437
+ blocked: OsPermissionOutcomeBranchTargetSchema
438
+ }).strict();
439
+ var APP_REVIEW_CAPTURE_FIELD_KEY_PREFIX = "app_review:";
440
+ var appReviewCaptureFieldKey = (layerId) => `${APP_REVIEW_CAPTURE_FIELD_KEY_PREFIX}${layerId}`;
441
+ var APP_REVIEW_OUTCOMES = ["not_shown", "dismissed"];
442
+ var AppReviewOutcomeSchema = z.enum(APP_REVIEW_OUTCOMES);
443
+ var ButtonActionSchema = z.discriminatedUnion("kind", [
444
+ z.object({ kind: z.literal("none") }),
445
+ z.object({ kind: z.literal("continue") }),
446
+ z.object({ kind: z.literal("skip") }),
447
+ z.object({ kind: z.literal("end_flow") }),
448
+ z.object({
449
+ kind: z.literal("go_back_one_screen"),
450
+ fallbackScreenId: ScreenIdSchema.optional()
451
+ }),
452
+ z.object({ kind: z.literal("go_to_step"), screenId: ScreenIdSchema }),
453
+ z.object({
454
+ kind: z.literal("request_os_permission"),
455
+ permissionKey: OsPermissionKeySchema,
456
+ outcomes: OsPermissionOutcomesSchema
457
+ }),
458
+ z.object({
459
+ kind: z.literal("play_media"),
460
+ targetLayerIds: z.array(z.string().min(1)).min(1)
461
+ }),
462
+ z.object({ kind: z.literal("request_app_review") })
463
+ ]);
464
+ var TEXT_INPUT_TYPES = ["plain", "email", "phone", "url", "multiline"];
465
+ var TextInputTypeSchema = z.enum(TEXT_INPUT_TYPES);
466
+ var COUNTER_DISPLAY_KINDS = ["number", "time"];
467
+ var COUNTER_TIME_FORMATS = ["mm_ss", "hh_mm_ss", "dd_hh_mm_ss"];
468
+ var CheckboxGlyphStyleSchema = z.object({
469
+ /** Square edge length in px. */
470
+ size: z.number().int().min(8).max(128).optional(),
471
+ radius: z.number().int().min(0).max(96).optional(),
472
+ background: ThemedColorSchema.optional(),
473
+ border: BorderSchema.optional(),
474
+ shadow: DropShadowSchema.optional(),
475
+ opacity: z.number().min(0).max(1).optional(),
476
+ /** Fill color for the check mark when checked. */
477
+ checkColor: ThemedColorSchema.optional()
478
+ }).partial();
479
+ var OAUTH_LOGIN_PRESETS = ["github", "google", "apple"];
480
+ var OAUTH_LOGIN_PRESET_DISPLAY = {
481
+ google: "Google",
482
+ github: "GitHub",
483
+ apple: "Apple"
484
+ };
485
+ var DEFAULT_OAUTH_PRESET_BUTTON_LABEL = {
486
+ google: "Sign in with Google",
487
+ github: "Continue with GitHub",
488
+ apple: "Sign in with Apple"
489
+ };
490
+ var defaultOAuthPresetButtonLabel = (provider) => DEFAULT_OAUTH_PRESET_BUTTON_LABEL[provider];
491
+ var oauthPresetEffectiveLabel = (provider, label2) => {
492
+ const base = DEFAULT_OAUTH_PRESET_BUTTON_LABEL[provider];
493
+ if (!label2) return { default: base };
494
+ const d = typeof label2.default === "string" && label2.default.trim().length > 0 ? label2.default : base;
495
+ return {
496
+ default: d,
497
+ ...label2.translations && Object.keys(label2.translations).length > 0 ? { translations: { ...label2.translations } } : {}
498
+ };
499
+ };
500
+ var OAuthPresetButtonChromeSchema = CommonStyleSchema.pick({
501
+ width: true,
502
+ padding: true,
503
+ margin: true,
504
+ radius: true
505
+ }).partial();
506
+ var OAuthPresetButtonChromeBreakpointsSchema = z.object({
507
+ sm: OAuthPresetButtonChromeSchema.partial().optional(),
508
+ md: OAuthPresetButtonChromeSchema.partial().optional(),
509
+ lg: OAuthPresetButtonChromeSchema.partial().optional(),
510
+ xl: OAuthPresetButtonChromeSchema.partial().optional(),
511
+ "2xl": OAuthPresetButtonChromeSchema.partial().optional()
512
+ }).partial().optional();
513
+ var EMAIL_PASSWORD_AUTH_MODES = ["sign_in", "sign_up"];
514
+ var EMAIL_PASSWORD_SLOTS = ["email", "password", "confirm"];
515
+
516
+ // src/layers/kinds/chrome.ts
517
+ var lazyLayer = () => layerSchemaStore.schema;
518
+ var ButtonLayerSchema = z.object({
519
+ ...baseLayerShape,
520
+ kind: z.literal("button"),
521
+ children: z.lazy(() => z.array(lazyLayer())),
522
+ action: ButtonActionSchema,
523
+ variant: ButtonLayerVariantSchema,
524
+ direction: z.enum(["vertical", "horizontal"]).optional(),
525
+ gap: z.number().int().min(0).optional(),
526
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
527
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
528
+ style: ButtonStyleSchema.optional(),
529
+ styleBreakpoints: ButtonStyleBreakpointsSchema,
530
+ buttonLayoutBreakpoints: ButtonLayoutBreakpointsSchema
531
+ });
532
+ var BackButtonLayerSchema = z.object({
533
+ ...baseLayerShape,
534
+ kind: z.literal("back_button"),
535
+ children: z.lazy(() => z.array(lazyLayer())),
536
+ variant: ButtonLayerVariantSchema,
537
+ direction: z.enum(["vertical", "horizontal"]).optional(),
538
+ gap: z.number().int().min(0).optional(),
539
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
540
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
541
+ style: ButtonStyleSchema.optional(),
542
+ styleBreakpoints: ButtonStyleBreakpointsSchema,
543
+ buttonLayoutBreakpoints: ButtonLayoutBreakpointsSchema,
544
+ fallbackScreenId: ScreenIdSchema.optional()
545
+ });
546
+ var ProgressLayerSchema = z.object({
547
+ ...baseLayerShape,
548
+ kind: z.literal("progress"),
549
+ trackColor: ThemedColorSchema.optional(),
550
+ fillColor: ThemedColorSchema.optional(),
551
+ style: CommonStyleSchema.optional()
552
+ });
553
+ var LoaderOnCompleteSchema = z.discriminatedUnion("mode", [
554
+ z.object({ mode: z.literal("none") }),
555
+ z.object({ mode: z.literal("next") }),
556
+ z.object({ mode: z.literal("screen"), screenId: ScreenIdSchema })
557
+ ]);
558
+ var LoaderLayerSchema = z.object({
559
+ ...baseLayerShape,
560
+ kind: z.literal("loader"),
561
+ variant: z.enum(["linear", "circular"]).optional(),
562
+ targetPercent: z.number().int().min(0).max(100).optional(),
563
+ fillDelayMs: z.number().int().min(0).max(1e4).optional(),
564
+ durationMs: z.number().int().min(0).max(36e5).optional(),
565
+ onComplete: LoaderOnCompleteSchema.optional(),
566
+ trackColor: ThemedColorSchema.optional(),
567
+ trackOpacity: z.number().min(0).max(1).optional(),
568
+ fillColor: ThemedColorSchema.optional(),
569
+ /** Horizontal alignment of the bar or ring within the layer box (default start). */
570
+ align: z.enum(["start", "center", "end"]).optional(),
571
+ style: CommonStyleSchema.optional()
572
+ }).superRefine((data, ctx) => {
573
+ if (data.variant !== "circular") return;
574
+ const w = data.style?.width;
575
+ const h = data.style?.height;
576
+ if (typeof w === "number" && typeof h === "number" && w !== h) {
577
+ ctx.addIssue({
578
+ code: z.ZodIssueCode.custom,
579
+ message: "circular loader requires style.width === style.height",
580
+ path: ["style", "height"]
581
+ });
582
+ }
583
+ });
584
+ var CounterLayerSchema = z.object({
585
+ ...baseLayerShape,
586
+ kind: z.literal("counter"),
587
+ startValue: z.number().finite(),
588
+ endValue: z.number().finite(),
589
+ durationMs: z.number().int().min(0).max(36e5).optional(),
590
+ delayMs: z.number().int().min(0).max(36e5).optional(),
591
+ decimalPlaces: z.number().int().min(0).max(10).optional(),
592
+ displayKind: z.enum(COUNTER_DISPLAY_KINDS).optional(),
593
+ timeFormat: z.enum(COUNTER_TIME_FORMATS).optional(),
594
+ style: TextStyleSchema.optional(),
595
+ styleBreakpoints: TextStyleBreakpointsSchema
596
+ });
597
+ var CheckboxLayerSchema = z.object({
598
+ ...baseLayerShape,
599
+ kind: z.literal("checkbox"),
600
+ fieldKey: z.string().min(1),
601
+ blocking: z.boolean().optional(),
602
+ uncheckedStyle: CheckboxGlyphStyleSchema.optional(),
603
+ checkedStyle: CheckboxGlyphStyleSchema.optional(),
604
+ style: CommonStyleSchema.optional(),
605
+ styleBreakpoints: CommonStyleBreakpointsSchema
606
+ });
607
+
608
+ // src/layers/kinds/layout.ts
609
+ var lazyLayer2 = () => layerSchemaStore.schema;
610
+ var StackLayerSchema = z.object({
611
+ ...baseLayerShape,
612
+ kind: z.literal("stack"),
613
+ style: CommonStyleSchema.optional(),
614
+ styleBreakpoints: CommonStyleBreakpointsSchema,
615
+ stackLayoutBreakpoints: StackLayoutBreakpointsSchema,
616
+ selectedStyle: CommonStyleSchema.optional(),
617
+ direction: z.enum(["vertical", "horizontal"]),
618
+ gap: z.number().int().min(0).optional(),
619
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
620
+ justify: z.enum(["start", "center", "end"]).optional(),
621
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
622
+ wrap: z.boolean().optional(),
623
+ children: z.lazy(() => z.array(lazyLayer2()))
624
+ });
625
+ var TextLayerSchema = z.object({
626
+ ...baseLayerShape,
627
+ kind: z.literal("text"),
628
+ text: LocalizedTextSchema,
629
+ style: TextStyleSchema.optional(),
630
+ styleBreakpoints: TextStyleBreakpointsSchema
631
+ });
632
+ var migrateLegacyHyperlinkForParse = (raw) => {
633
+ if (!raw || typeof raw !== "object") return raw;
634
+ const o = raw;
635
+ if (o.kind !== "hyperlink") return raw;
636
+ const existing = o.children;
637
+ if (Array.isArray(existing) && existing.length > 0) return raw;
638
+ const idSrc = typeof o.id === "string" ? o.id.replace(/[^a-zA-Z0-9_]/g, "_") : "lyr_hyperlink";
639
+ const textChildId = `${idSrc}_lnktxt`.slice(0, 64);
640
+ const children = [
641
+ {
642
+ id: textChildId,
643
+ kind: "text",
644
+ text: o.text ?? { default: "Link" },
645
+ ...typeof o.style === "object" && o.style !== null ? { style: o.style } : {},
646
+ ...typeof o.styleBreakpoints === "object" && o.styleBreakpoints !== null ? { styleBreakpoints: o.styleBreakpoints } : {}
647
+ }
648
+ ];
649
+ const next = {
650
+ ...o,
651
+ children
652
+ };
653
+ delete next.text;
654
+ delete next.style;
655
+ delete next.styleBreakpoints;
656
+ return next;
657
+ };
658
+ var HyperlinkLayerSchemaInner = z.object({
659
+ ...baseLayerShape,
660
+ kind: z.literal("hyperlink"),
661
+ href: z.string().min(1).max(2048),
662
+ children: z.lazy(() => z.array(lazyLayer2()).min(1)),
663
+ direction: z.enum(["vertical", "horizontal"]).optional(),
664
+ gap: z.number().int().min(0).optional(),
665
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
666
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
667
+ wrap: z.boolean().optional(),
668
+ style: CommonStyleSchema.optional(),
669
+ styleBreakpoints: CommonStyleBreakpointsSchema
670
+ }).superRefine((data, ctx) => {
671
+ const p = parseHyperlinkHref(data.href.trim());
672
+ if (!p.ok) {
673
+ ctx.addIssue({
674
+ code: z.ZodIssueCode.custom,
675
+ message: "hyperlink href must be a valid https: or mailto: URL",
676
+ path: ["href"]
677
+ });
678
+ }
679
+ });
680
+ var HyperlinkLayerSchema = z.preprocess(
681
+ migrateLegacyHyperlinkForParse,
682
+ HyperlinkLayerSchemaInner
683
+ );
684
+ var ImageLayerSchema = z.object({
685
+ ...baseLayerShape,
686
+ kind: z.literal("image"),
687
+ media: MediaReferenceSchema.optional(),
688
+ alt: z.string().max(280).optional(),
689
+ style: ImageStyleSchema.optional(),
690
+ styleBreakpoints: ImageStyleBreakpointsSchema
691
+ });
692
+ var LottieLayerSchema = z.object({
693
+ ...baseLayerShape,
694
+ kind: z.literal("lottie"),
695
+ media: MediaReferenceSchema.optional(),
696
+ loop: z.boolean().optional(),
697
+ autoPlay: z.boolean().optional(),
698
+ triggerLayerId: z.string().min(1).optional(),
699
+ onComplete: LoaderOnCompleteSchema.optional(),
700
+ style: ImageStyleSchema.optional(),
701
+ styleBreakpoints: ImageStyleBreakpointsSchema
702
+ });
703
+ var VideoLayerSchema = z.object({
704
+ ...baseLayerShape,
705
+ kind: z.literal("video"),
706
+ media: MediaReferenceSchema.optional(),
707
+ loop: z.boolean().optional(),
708
+ autoPlay: z.boolean().optional(),
709
+ triggerLayerId: z.string().min(1).optional(),
710
+ onComplete: LoaderOnCompleteSchema.optional(),
711
+ audioEnabled: z.boolean().optional(),
712
+ style: ImageStyleSchema.optional(),
713
+ styleBreakpoints: ImageStyleBreakpointsSchema
714
+ });
715
+ var IconLayerSchema = z.object({
716
+ ...baseLayerShape,
717
+ kind: z.literal("icon"),
718
+ family: z.enum(ICON_FAMILIES),
719
+ iconName: z.string().min(1).max(128),
720
+ style: IconStyleSchema.optional(),
721
+ styleBreakpoints: IconStyleBreakpointsSchema
722
+ });
723
+ var lazyLayer3 = () => layerSchemaStore.schema;
724
+ var oauthLoginManifestProviderFromLayer = (layer) => layer.variant === "preset" ? { type: "preset", provider: layer.provider } : oauthLoginCustomPayloadFromLayer(layer);
725
+ var oauthLoginCustomPayloadFromLayer = (layer) => {
726
+ const text = layer.children.find((c) => c.kind === "text");
727
+ const icon = layer.children.find((c) => c.kind === "icon");
728
+ return {
729
+ type: "custom",
730
+ rowId: layer.rowId,
731
+ label: text?.text ?? { default: "" },
732
+ family: icon?.family ?? "ionicons",
733
+ iconName: icon?.iconName ?? "help-circle-outline"
734
+ };
735
+ };
736
+ var OAuthProviderPresetLayerSchema = z.object({
737
+ ...baseLayerShape,
738
+ kind: z.literal("oauth_provider"),
739
+ variant: z.literal("preset"),
740
+ provider: z.enum(OAUTH_LOGIN_PRESETS),
741
+ label: LocalizedTextSchema.optional(),
742
+ style: OAuthPresetButtonChromeSchema.optional(),
743
+ styleBreakpoints: OAuthPresetButtonChromeBreakpointsSchema.optional()
744
+ });
745
+ var migrateOAuthProviderCustomIncoming = (raw) => {
746
+ if (!raw || typeof raw !== "object") return raw;
747
+ const o = raw;
748
+ if (o.kind !== "oauth_provider" || o.variant !== "custom") return raw;
749
+ const ch = o.children;
750
+ if (Array.isArray(ch) && ch.length > 0) {
751
+ const next2 = { ...o };
752
+ if (next2.buttonVariant === void 0) next2.buttonVariant = "secondary";
753
+ return next2;
754
+ }
755
+ const pid = typeof o.id === "string" ? o.id : "lyr_oauth_custom";
756
+ const slug = pid.replace(/[^a-z0-9_]/gi, "_").slice(0, 40) || "oauth";
757
+ const label2 = o.label ?? { default: "Custom" };
758
+ let family = o.family ?? "ionicons";
759
+ let iconName = o.iconName ?? "shield-outline";
760
+ if (family === "sf_symbol") {
761
+ family = "ionicons";
762
+ iconName = "star-outline";
763
+ }
764
+ const cid = slug;
765
+ const iconId = `lyr_${cid}_ico`.slice(0, 64);
766
+ const textId = `lyr_${cid}_txt`.slice(0, 64);
767
+ const next = { ...o };
768
+ delete next.label;
769
+ delete next.family;
770
+ delete next.iconName;
771
+ return {
772
+ ...next,
773
+ buttonVariant: o.buttonVariant ?? "secondary",
774
+ children: [
775
+ { id: iconId, kind: "icon", family, iconName },
776
+ { id: textId, kind: "text", text: label2 }
777
+ ]
778
+ };
779
+ };
780
+ var OAuthProviderCustomLayerSchemaValidated = z.object({
781
+ ...baseLayerShape,
782
+ kind: z.literal("oauth_provider"),
783
+ variant: z.literal("custom"),
784
+ rowId: z.string().uuid(),
785
+ buttonVariant: ButtonLayerVariantSchema,
786
+ direction: z.enum(["vertical", "horizontal"]).optional(),
787
+ gap: z.number().int().min(0).optional(),
788
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
789
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
790
+ children: z.lazy(() => z.array(lazyLayer3()).min(1)),
791
+ style: ButtonStyleSchema.optional(),
792
+ styleBreakpoints: ButtonStyleBreakpointsSchema,
793
+ buttonLayoutBreakpoints: ButtonLayoutBreakpointsSchema
794
+ });
795
+ var OAuthProviderCustomLayerSchema = z.preprocess(
796
+ migrateOAuthProviderCustomIncoming,
797
+ OAuthProviderCustomLayerSchemaValidated
798
+ );
799
+ var OAuthProviderLayerSchema = z.union([
800
+ OAuthProviderPresetLayerSchema,
801
+ OAuthProviderCustomLayerSchema
802
+ ]);
803
+ var OAuthLoginPresetProviderSchema = z.object({
804
+ type: z.literal("preset"),
805
+ provider: z.enum(OAUTH_LOGIN_PRESETS)
806
+ });
807
+ var OAuthLoginCustomProviderSchema = z.object({
808
+ type: z.literal("custom"),
809
+ rowId: z.string().uuid(),
810
+ label: LocalizedTextSchema,
811
+ family: z.enum(ICON_FAMILIES),
812
+ iconName: z.string().min(1).max(128)
813
+ });
814
+ var OAuthLoginProviderSchema = z.discriminatedUnion("type", [
815
+ OAuthLoginPresetProviderSchema,
816
+ OAuthLoginCustomProviderSchema
817
+ ]);
818
+ var oauthLoginChildrenUniquePresets = (children, ctx) => {
819
+ const seen = /* @__PURE__ */ new Set();
820
+ for (let i = 0; i < children.length; i++) {
821
+ const c = children[i];
822
+ if (!c || c.kind !== "oauth_provider" || c.variant !== "preset") continue;
823
+ const preset = c.provider;
824
+ if (seen.has(preset)) {
825
+ ctx.addIssue({
826
+ code: z.ZodIssueCode.custom,
827
+ message: `duplicate OAuth preset "${preset}"`,
828
+ path: ["children", i, "provider"]
829
+ });
830
+ return;
831
+ }
832
+ seen.add(preset);
833
+ }
834
+ };
835
+ var migrateOAuthLoginIncoming = (raw) => {
836
+ if (!raw || typeof raw !== "object") return raw;
837
+ const o = raw;
838
+ if (o.kind !== "oauth_login") return raw;
839
+ if (Array.isArray(o.children) && o.children.length > 0) return raw;
840
+ const provs = o.providers;
841
+ if (!Array.isArray(provs) || provs.length === 0) return raw;
842
+ const pid = typeof o.id === "string" ? o.id : "lyr_oauth_legacy";
843
+ const slug = pid.replace(/^lyr_/i, "").replace(/[^a-z0-9_]/gi, "_").replace(/^_+/, "").slice(0, 48) || "oauth";
844
+ const children = provs.map((p, idx) => {
845
+ const prov = p ?? {};
846
+ const cid = `lyr_${slug}_opr_${idx}`.slice(0, 64);
847
+ if (prov.type === "preset") {
848
+ return {
849
+ id: cid,
850
+ kind: "oauth_provider",
851
+ variant: "preset",
852
+ provider: prov.provider
853
+ };
854
+ }
855
+ return {
856
+ id: cid,
857
+ kind: "oauth_provider",
858
+ variant: "custom",
859
+ rowId: String(prov.rowId),
860
+ buttonVariant: "secondary",
861
+ children: [
862
+ {
863
+ id: `${cid}_ico`.slice(0, 64),
864
+ kind: "icon",
865
+ family: prov.family ?? "ionicons",
866
+ iconName: String(prov.iconName ?? "shield")
867
+ },
868
+ {
869
+ id: `${cid}_txt`.slice(0, 64),
870
+ kind: "text",
871
+ text: prov.label ?? { default: "Custom" }
872
+ }
873
+ ]
874
+ };
875
+ });
876
+ const { providers: _omit, ...rest } = o;
877
+ return { ...rest, children };
878
+ };
879
+ var OAuthLoginLayerSchemaValidated = z.object({
880
+ ...baseLayerShape,
881
+ kind: z.literal("oauth_login"),
882
+ children: z.lazy(
883
+ () => z.array(OAuthProviderLayerSchema).min(1).superRefine(oauthLoginChildrenUniquePresets)
884
+ ),
885
+ gap: z.number().int().min(0).optional(),
886
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
887
+ style: CommonStyleSchema.optional(),
888
+ styleBreakpoints: CommonStyleBreakpointsSchema
889
+ });
890
+ var OAuthLoginLayerSchema = z.preprocess(
891
+ migrateOAuthLoginIncoming,
892
+ OAuthLoginLayerSchemaValidated
893
+ );
894
+ var OAuthLoginProvidersArraySchema = z.array(OAuthLoginProviderSchema).min(1).superRefine((providers, ctx) => {
895
+ const seen = /* @__PURE__ */ new Set();
896
+ for (let i = 0; i < providers.length; i++) {
897
+ const p = providers[i];
898
+ if (!p || p.type !== "preset") continue;
899
+ const preset = p.provider;
900
+ if (seen.has(preset)) {
901
+ ctx.addIssue({
902
+ code: z.ZodIssueCode.custom,
903
+ message: `duplicate OAuth preset "${preset}"`,
904
+ path: [i, "provider"]
905
+ });
906
+ return;
907
+ }
908
+ seen.add(preset);
909
+ }
910
+ });
911
+ var lazyLayer4 = () => layerSchemaStore.schema;
912
+ var EmailPasswordAuthModeSchema = z.enum(EMAIL_PASSWORD_AUTH_MODES);
913
+ var migrateEmailPasswordAuthIncoming = (raw) => {
914
+ if (!raw || typeof raw !== "object") return raw;
915
+ const o = raw;
916
+ if (o.kind !== "email_password_auth") return raw;
917
+ if (Array.isArray(o.children) && o.children.length > 0) return raw;
918
+ const idBase = typeof o.id === "string" ? o.id : "lyr_email_password_auth";
919
+ const slugRaw = idBase.replace(/^lyr_/i, "").replace(/[^a-z0-9_]/gi, "_");
920
+ const slug = slugRaw.length > 0 ? slugRaw.slice(0, 40) : "ep_auth";
921
+ const mode = o.mode === "sign_up" ? "sign_up" : "sign_in";
922
+ const pickLt = (v, fallback) => v && typeof v === "object" && v !== null && "default" in v ? v : { default: fallback };
923
+ const mkField = (suf, slot, labelSource, fallbackPlaceholder) => ({
924
+ id: `lyr_${slug}_fld_${suf}`.slice(0, 64),
925
+ kind: "email_password_field",
926
+ slot,
927
+ ...labelSource ? { placeholder: pickLt(labelSource, fallbackPlaceholder) } : { placeholder: { default: fallbackPlaceholder } },
928
+ children: []
929
+ });
930
+ const children = [];
931
+ children.push(mkField("email", "email", o.emailLabel, "Email"));
932
+ children.push(mkField("pw", "password", o.passwordLabel, "Password"));
933
+ if (mode === "sign_up") {
934
+ children.push(mkField("cf", "confirm", o.confirmPasswordLabel, "Confirm password"));
935
+ }
936
+ const submitLbl = o.submitLabel ?? { default: mode === "sign_in" ? "Sign in" : "Create account" };
937
+ children.push({
938
+ id: `lyr_${slug}_submit`.slice(0, 64),
939
+ kind: "email_password_submit",
940
+ buttonVariant: "primary",
941
+ direction: "horizontal",
942
+ align: "center",
943
+ distribution: "center",
944
+ gap: 8,
945
+ children: [
946
+ {
947
+ id: `lyr_${slug}_submit_txt`.slice(0, 64),
948
+ kind: "text",
949
+ text: submitLbl
950
+ }
951
+ ]
952
+ });
953
+ const {
954
+ emailLabel: _e,
955
+ passwordLabel: _p,
956
+ confirmPasswordLabel: _c,
957
+ submitLabel: _s,
958
+ ...rest
959
+ } = o;
960
+ return { ...rest, mode, children };
961
+ };
962
+ var refineEmailPasswordAuthChildren = (data, ctx) => {
963
+ const fields = data.children.filter((c) => c.kind === "email_password_field");
964
+ const submits = data.children.filter((c) => c.kind === "email_password_submit");
965
+ const slotSeen = /* @__PURE__ */ new Set();
966
+ for (const f of fields) {
967
+ if (slotSeen.has(f.slot)) {
968
+ ctx.addIssue({
969
+ code: z.ZodIssueCode.custom,
970
+ message: `duplicate email_password_field slot "${f.slot}"`,
971
+ path: ["children"]
972
+ });
973
+ }
974
+ slotSeen.add(f.slot);
975
+ }
976
+ const slotHas = new Set(fields.map((f) => f.slot));
977
+ const requiredSlots = data.mode === "sign_up" ? ["email", "password", "confirm"] : ["email", "password"];
978
+ for (const s of requiredSlots) {
979
+ if (!slotHas.has(s)) {
980
+ ctx.addIssue({
981
+ code: z.ZodIssueCode.custom,
982
+ message: data.mode === "sign_up" ? `sign_up requires an email_password_field with slot "${s}"` : `sign_in requires an email_password_field with slot "${s}"`,
983
+ path: ["children"]
984
+ });
985
+ }
986
+ }
987
+ if (data.mode === "sign_in" && slotHas.has("confirm")) {
988
+ ctx.addIssue({
989
+ code: z.ZodIssueCode.custom,
990
+ message: 'sign_in must not include email_password_field with slot "confirm"',
991
+ path: ["children"]
992
+ });
993
+ }
994
+ if (submits.length !== 1) {
995
+ ctx.addIssue({
996
+ code: z.ZodIssueCode.custom,
997
+ message: `email_password_auth must have exactly one email_password_submit (found ${submits.length})`,
998
+ path: ["children"]
999
+ });
1000
+ }
1001
+ };
1002
+ var EmailPasswordFieldLayerSchema = z.object({
1003
+ ...baseLayerShape,
1004
+ kind: z.literal("email_password_field"),
1005
+ slot: z.enum(EMAIL_PASSWORD_SLOTS),
1006
+ placeholder: LocalizedTextSchema.optional(),
1007
+ children: z.lazy(() => z.array(lazyLayer4())).optional(),
1008
+ style: CommonStyleSchema.optional(),
1009
+ styleBreakpoints: CommonStyleBreakpointsSchema
1010
+ });
1011
+ var EmailPasswordSubmitLayerSchema = z.object({
1012
+ ...baseLayerShape,
1013
+ kind: z.literal("email_password_submit"),
1014
+ buttonVariant: ButtonLayerVariantSchema,
1015
+ direction: z.enum(["vertical", "horizontal"]).optional(),
1016
+ gap: z.number().int().min(0).optional(),
1017
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
1018
+ distribution: z.enum(["start", "center", "end", "between", "around"]).optional(),
1019
+ children: z.lazy(() => z.array(lazyLayer4()).min(1)),
1020
+ style: ButtonStyleSchema.optional(),
1021
+ styleBreakpoints: ButtonStyleBreakpointsSchema,
1022
+ buttonLayoutBreakpoints: ButtonLayoutBreakpointsSchema
1023
+ });
1024
+ var EmailPasswordAuthLayerSchemaValidated = z.object({
1025
+ ...baseLayerShape,
1026
+ kind: z.literal("email_password_auth"),
1027
+ mode: EmailPasswordAuthModeSchema,
1028
+ fieldKey: FieldKeySchema,
1029
+ minPasswordLength: z.number().int().min(4).max(128).optional(),
1030
+ children: z.lazy(
1031
+ () => z.array(z.union([EmailPasswordFieldLayerSchema, EmailPasswordSubmitLayerSchema])).min(1)
1032
+ ),
1033
+ gap: z.number().int().min(0).optional(),
1034
+ align: z.enum(["start", "center", "end", "stretch"]).optional(),
1035
+ style: CommonStyleSchema.optional(),
1036
+ styleBreakpoints: CommonStyleBreakpointsSchema
1037
+ }).superRefine(refineEmailPasswordAuthChildren);
1038
+ var EmailPasswordAuthLayerSchema = z.preprocess(
1039
+ migrateEmailPasswordAuthIncoming,
1040
+ EmailPasswordAuthLayerSchemaValidated
1041
+ );
1042
+ var ChoiceOptionBindingSchema = z.object({
1043
+ optionId: z.string().min(1).max(64),
1044
+ rootLayerId: LayerIdSchema
1045
+ });
1046
+ var BranchConditionSchema = z.object({
1047
+ choiceId: z.string().min(1),
1048
+ goTo: ScreenIdSchema
1049
+ });
1050
+ var ChoiceBranchingSchema = z.object({
1051
+ enabled: z.boolean(),
1052
+ conditions: z.array(BranchConditionSchema)
1053
+ });
1054
+
1055
+ // src/layers/kinds/input.ts
1056
+ var lazyLayer5 = () => layerSchemaStore.schema;
1057
+ var ChoiceChildrenAndBindingsRefinement = (data, ctx) => {
1058
+ const childIds = /* @__PURE__ */ new Set();
1059
+ for (const c of data.children) {
1060
+ if (childIds.has(c.id)) {
1061
+ ctx.addIssue({
1062
+ code: z.ZodIssueCode.custom,
1063
+ message: `duplicate option child id "${c.id}"`,
1064
+ path: ["children"]
1065
+ });
1066
+ }
1067
+ childIds.add(c.id);
1068
+ }
1069
+ const seenOptionIds = /* @__PURE__ */ new Set();
1070
+ const seenRootIds = /* @__PURE__ */ new Set();
1071
+ for (const b of data.optionBindings) {
1072
+ if (seenOptionIds.has(b.optionId)) {
1073
+ ctx.addIssue({
1074
+ code: z.ZodIssueCode.custom,
1075
+ message: `duplicate optionId "${b.optionId}" in optionBindings`,
1076
+ path: ["optionBindings"]
1077
+ });
1078
+ }
1079
+ seenOptionIds.add(b.optionId);
1080
+ if (seenRootIds.has(b.rootLayerId)) {
1081
+ ctx.addIssue({
1082
+ code: z.ZodIssueCode.custom,
1083
+ message: `duplicate rootLayerId "${b.rootLayerId}" in optionBindings`,
1084
+ path: ["optionBindings"]
1085
+ });
1086
+ }
1087
+ seenRootIds.add(b.rootLayerId);
1088
+ if (!childIds.has(b.rootLayerId)) {
1089
+ ctx.addIssue({
1090
+ code: z.ZodIssueCode.custom,
1091
+ message: `optionBindings rootLayerId "${b.rootLayerId}" does not match any direct child stack`,
1092
+ path: ["optionBindings"]
1093
+ });
1094
+ }
1095
+ }
1096
+ if (data.optionBindings.length !== data.children.length) {
1097
+ ctx.addIssue({
1098
+ code: z.ZodIssueCode.custom,
1099
+ message: "optionBindings length must equal children length",
1100
+ path: ["optionBindings"]
1101
+ });
1102
+ }
1103
+ };
1104
+ var SingleChoiceLayerSchema = z.object({
1105
+ ...baseLayerShape,
1106
+ kind: z.literal("single_choice"),
1107
+ fieldKey: FieldKeySchema,
1108
+ children: z.lazy(
1109
+ () => z.array(StackLayerSchema).min(2)
1110
+ ),
1111
+ optionBindings: z.array(ChoiceOptionBindingSchema).min(2),
1112
+ branching: ChoiceBranchingSchema,
1113
+ direction: z.enum(["vertical", "horizontal", "grid"]).optional(),
1114
+ gap: z.number().int().min(0).optional(),
1115
+ columns: z.number().int().min(1).max(12).optional(),
1116
+ style: CommonStyleSchema.optional(),
1117
+ styleBreakpoints: CommonStyleBreakpointsSchema
1118
+ });
1119
+ var MultipleChoiceLayerSchema = z.object({
1120
+ ...baseLayerShape,
1121
+ kind: z.literal("multiple_choice"),
1122
+ fieldKey: FieldKeySchema,
1123
+ children: z.lazy(
1124
+ () => z.array(StackLayerSchema).min(2)
1125
+ ),
1126
+ optionBindings: z.array(ChoiceOptionBindingSchema).min(2),
1127
+ minSelections: z.number().int().nonnegative().optional(),
1128
+ maxSelections: z.number().int().positive().optional(),
1129
+ branching: ChoiceBranchingSchema,
1130
+ direction: z.enum(["vertical", "horizontal", "grid"]).optional(),
1131
+ gap: z.number().int().min(0).optional(),
1132
+ columns: z.number().int().min(1).max(12).optional(),
1133
+ style: CommonStyleSchema.optional(),
1134
+ styleBreakpoints: CommonStyleBreakpointsSchema
1135
+ });
1136
+ var validateChoiceChildrenAndBindings = ChoiceChildrenAndBindingsRefinement;
1137
+ var TextInputLayerSchema = z.object({
1138
+ ...baseLayerShape,
1139
+ kind: z.literal("text_input"),
1140
+ fieldKey: FieldKeySchema,
1141
+ placeholder: LocalizedTextSchema.optional(),
1142
+ inputType: TextInputTypeSchema.optional(),
1143
+ required: z.boolean().optional(),
1144
+ minLength: z.number().int().min(0).max(2e3).optional(),
1145
+ maxLength: z.number().int().positive().max(2e3).optional(),
1146
+ classification: FieldClassificationSchema,
1147
+ children: z.lazy(() => z.array(lazyLayer5())).optional(),
1148
+ style: CommonStyleSchema.optional()
1149
+ });
1150
+ var ScaleInputLabelStyleSchema = z.object({
1151
+ fontFamily: z.string().min(1).max(128).optional(),
1152
+ fontSize: z.number().int().min(8).max(96).optional(),
1153
+ fontWeight: z.number().int().min(100).max(900).optional(),
1154
+ color: ThemedColorSchema.optional(),
1155
+ align: z.enum(["left", "center", "right"]).optional(),
1156
+ lineHeight: z.number().min(0.8).max(3).optional(),
1157
+ opacity: z.number().min(0).max(1).optional()
1158
+ }).partial();
1159
+ var ScaleInputLayerSchema = z.object({
1160
+ ...baseLayerShape,
1161
+ kind: z.literal("scale_input"),
1162
+ fieldKey: FieldKeySchema,
1163
+ min: z.number(),
1164
+ max: z.number(),
1165
+ step: z.number().positive().optional(),
1166
+ defaultValue: z.number().optional(),
1167
+ minLabel: LocalizedTextSchema.optional(),
1168
+ maxLabel: LocalizedTextSchema.optional(),
1169
+ labelStyle: ScaleInputLabelStyleSchema.optional(),
1170
+ valueStyle: ScaleInputLabelStyleSchema.optional(),
1171
+ showLabels: z.boolean().optional(),
1172
+ showValue: z.boolean().optional(),
1173
+ trackHeight: z.number().int().min(2).max(32).optional(),
1174
+ trackColor: ThemedColorSchema.optional(),
1175
+ fillColor: ThemedColorSchema.optional(),
1176
+ thumbSize: z.number().int().min(8).max(48).optional(),
1177
+ thumbColor: ThemedColorSchema.optional(),
1178
+ children: z.lazy(() => z.array(lazyLayer5())).optional(),
1179
+ style: CommonStyleSchema.optional()
1180
+ });
1181
+ var CarouselIndicatorsStyleSchema = z.object({
1182
+ width: z.number().int().min(1).max(64).optional(),
1183
+ height: z.number().int().min(1).max(64).optional(),
1184
+ defaultColor: ThemedColorSchema.optional(),
1185
+ defaultOpacity: z.number().min(0).max(1).optional(),
1186
+ activeColor: ThemedColorSchema.optional(),
1187
+ activeOpacity: z.number().min(0).max(1).optional(),
1188
+ activeWidth: z.number().int().min(1).max(64).optional(),
1189
+ activeHeight: z.number().int().min(1).max(64).optional(),
1190
+ border: BorderSchema.optional(),
1191
+ activeBorder: BorderSchema.optional()
1192
+ }).partial();
1193
+ var CarouselPageControlSchema = z.object({
1194
+ position: z.enum(["top", "bottom"]),
1195
+ spacing: z.number().int().min(0).optional(),
1196
+ padding: PaddingSchema.optional(),
1197
+ margin: PaddingSchema.optional(),
1198
+ indicators: CarouselIndicatorsStyleSchema.optional(),
1199
+ border: BorderSchema.optional(),
1200
+ shadow: DropShadowSchema.optional()
1201
+ });
1202
+ var CarouselLayerSchema = z.object({
1203
+ ...baseLayerShape,
1204
+ kind: z.literal("carousel"),
1205
+ slides: z.lazy(() => z.array(StackLayerSchema).min(1)),
1206
+ pageAlignment: z.enum(["top", "center", "bottom"]).optional(),
1207
+ pageSpacing: z.number().int().min(0).optional(),
1208
+ pagePeek: z.number().int().min(0).max(400).optional(),
1209
+ openOn: z.number().int().min(0).optional(),
1210
+ loop: z.boolean().optional(),
1211
+ autoAdvance: z.boolean().optional(),
1212
+ autoAdvanceMs: z.number().int().min(500).max(6e4).optional(),
1213
+ pageControl: CarouselPageControlSchema.optional(),
1214
+ style: CommonStyleSchema.optional(),
1215
+ styleBreakpoints: CommonStyleBreakpointsSchema
1216
+ });
1217
+
1218
+ // src/layers/initLayerSchema.ts
1219
+ layerSchemaStore.schema = z.lazy(
1220
+ () => z.union([
1221
+ StackLayerSchema,
1222
+ TextLayerSchema,
1223
+ HyperlinkLayerSchema,
1224
+ ImageLayerSchema,
1225
+ LottieLayerSchema,
1226
+ VideoLayerSchema,
1227
+ IconLayerSchema,
1228
+ ButtonLayerSchema,
1229
+ BackButtonLayerSchema,
1230
+ ProgressLayerSchema,
1231
+ LoaderLayerSchema,
1232
+ CounterLayerSchema,
1233
+ CheckboxLayerSchema,
1234
+ SingleChoiceLayerSchema,
1235
+ MultipleChoiceLayerSchema,
1236
+ TextInputLayerSchema,
1237
+ ScaleInputLayerSchema,
1238
+ OAuthLoginLayerSchema,
1239
+ OAuthProviderPresetLayerSchema,
1240
+ OAuthProviderCustomLayerSchema,
1241
+ EmailPasswordAuthLayerSchema,
1242
+ EmailPasswordFieldLayerSchema,
1243
+ EmailPasswordSubmitLayerSchema,
1244
+ CarouselLayerSchema
1245
+ ])
1246
+ );
1247
+ var LayerSchema = layerSchemaStore.schema;
1248
+
1249
+ // src/layers/layerKinds.ts
1250
+ var LAYER_KINDS = [
1251
+ "stack",
1252
+ "text",
1253
+ "image",
1254
+ "lottie",
1255
+ "video",
1256
+ "icon",
1257
+ "button",
1258
+ "back_button",
1259
+ "progress",
1260
+ "loader",
1261
+ "counter",
1262
+ "single_choice",
1263
+ "multiple_choice",
1264
+ "text_input",
1265
+ "scale_input",
1266
+ "oauth_provider",
1267
+ "oauth_login",
1268
+ "email_password_auth",
1269
+ "email_password_field",
1270
+ "email_password_submit",
1271
+ "carousel",
1272
+ "hyperlink",
1273
+ "checkbox"
1274
+ ];
1275
+ var INPUT_LAYER_KINDS = [
1276
+ "single_choice",
1277
+ "multiple_choice",
1278
+ "text_input",
1279
+ "scale_input"
1280
+ ];
1281
+
1282
+ // src/layers/tree.ts
1283
+ var STYLE_BREAKPOINT_KEYS = ["sm", "md", "lg", "xl", "2xl"];
1284
+ var commonStyleHasAbsolutePosition = (style, breakpoints) => {
1285
+ if (style?.position === "absolute") return true;
1286
+ if (!breakpoints) return false;
1287
+ for (const k of STYLE_BREAKPOINT_KEYS) {
1288
+ if (breakpoints[k]?.position === "absolute") return true;
1289
+ }
1290
+ return false;
1291
+ };
1292
+ var layerHasAbsolutePositionAuthored = (layer) => {
1293
+ switch (layer.kind) {
1294
+ case "stack":
1295
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints) || layer.selectedStyle?.position === "absolute";
1296
+ case "text":
1297
+ case "counter":
1298
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1299
+ case "image":
1300
+ case "lottie":
1301
+ case "video":
1302
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1303
+ case "icon":
1304
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1305
+ case "button":
1306
+ case "back_button":
1307
+ case "hyperlink":
1308
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1309
+ case "progress":
1310
+ case "loader":
1311
+ return commonStyleHasAbsolutePosition(layer.style, void 0);
1312
+ case "text_input":
1313
+ case "scale_input":
1314
+ return commonStyleHasAbsolutePosition(layer.style, void 0);
1315
+ case "oauth_provider":
1316
+ if (layer.variant === "preset") {
1317
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1318
+ }
1319
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1320
+ case "oauth_login":
1321
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1322
+ case "email_password_auth":
1323
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1324
+ case "email_password_field":
1325
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1326
+ case "email_password_submit":
1327
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1328
+ case "carousel":
1329
+ return commonStyleHasAbsolutePosition(layer.style, void 0);
1330
+ case "checkbox":
1331
+ case "single_choice":
1332
+ case "multiple_choice":
1333
+ return commonStyleHasAbsolutePosition(layer.style, layer.styleBreakpoints);
1334
+ default:
1335
+ return false;
1336
+ }
1337
+ };
1338
+ var layerSubtreeContainsAbsolutePosition = (layer) => {
1339
+ if (layerHasAbsolutePositionAuthored(layer)) return true;
1340
+ if (layer.kind === "stack") {
1341
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1342
+ }
1343
+ if (layer.kind === "carousel") {
1344
+ return layer.slides.some(layerSubtreeContainsAbsolutePosition);
1345
+ }
1346
+ if (layer.kind === "button" || layer.kind === "back_button" || layer.kind === "hyperlink") {
1347
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1348
+ }
1349
+ if (layer.kind === "single_choice" || layer.kind === "multiple_choice") {
1350
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1351
+ }
1352
+ if (layer.kind === "text_input" || layer.kind === "scale_input") {
1353
+ return layer.children?.some(layerSubtreeContainsAbsolutePosition) ?? false;
1354
+ }
1355
+ if (layer.kind === "oauth_login") {
1356
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1357
+ }
1358
+ if (layer.kind === "oauth_provider" && layer.variant === "custom") {
1359
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1360
+ }
1361
+ if (layer.kind === "email_password_auth") {
1362
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1363
+ }
1364
+ if (layer.kind === "email_password_field") {
1365
+ return layer.children?.some(layerSubtreeContainsAbsolutePosition) ?? false;
1366
+ }
1367
+ if (layer.kind === "email_password_submit") {
1368
+ return layer.children.some(layerSubtreeContainsAbsolutePosition);
1369
+ }
1370
+ return false;
1371
+ };
1372
+
1373
+ // src/layers/layerUnion.ts
1374
+ var isInputLayer = (l) => l.kind === "single_choice" || l.kind === "multiple_choice" || l.kind === "text_input" || l.kind === "scale_input";
1375
+ var isParentLayer = (l) => l.kind === "stack" || l.kind === "carousel" || l.kind === "button" || l.kind === "back_button" || l.kind === "hyperlink" || l.kind === "single_choice" || l.kind === "multiple_choice" || l.kind === "text_input" || l.kind === "scale_input" || l.kind === "oauth_login" || l.kind === "oauth_provider" && l.variant === "custom" || l.kind === "email_password_auth" || l.kind === "email_password_field" || l.kind === "email_password_submit";
1376
+
1377
+ // src/layers/minimalLayerExamples.ts
1378
+ var label = (id, copy) => ({
1379
+ id,
1380
+ kind: "text",
1381
+ text: { default: copy },
1382
+ style: { color: PRIMARY_FILLED_LABEL }
1383
+ });
1384
+ var choiceOptions = (prefix) => {
1385
+ const a = {
1386
+ id: `${prefix}_opt_a`,
1387
+ kind: "stack",
1388
+ direction: "horizontal",
1389
+ align: "center",
1390
+ gap: 8,
1391
+ children: [
1392
+ {
1393
+ id: `${prefix}_opt_a_t`,
1394
+ kind: "text",
1395
+ text: { default: "A" },
1396
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1397
+ }
1398
+ ]
1399
+ };
1400
+ const b = {
1401
+ id: `${prefix}_opt_b`,
1402
+ kind: "stack",
1403
+ direction: "horizontal",
1404
+ align: "center",
1405
+ gap: 8,
1406
+ children: [
1407
+ {
1408
+ id: `${prefix}_opt_b_t`,
1409
+ kind: "text",
1410
+ text: { default: "B" },
1411
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1412
+ }
1413
+ ]
1414
+ };
1415
+ return {
1416
+ children: [a, b],
1417
+ optionBindings: [
1418
+ { optionId: "a", rootLayerId: `${prefix}_opt_a` },
1419
+ { optionId: "b", rootLayerId: `${prefix}_opt_b` }
1420
+ ]
1421
+ };
1422
+ };
1423
+ var minimalLayerExamples = () => ({
1424
+ stack: {
1425
+ id: "lyr_stack",
1426
+ kind: "stack",
1427
+ direction: "vertical",
1428
+ gap: 8,
1429
+ children: [
1430
+ {
1431
+ id: "lyr_stack_txt",
1432
+ kind: "text",
1433
+ text: { default: "Nested" },
1434
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1435
+ }
1436
+ ]
1437
+ },
1438
+ text: {
1439
+ id: "lyr_text",
1440
+ kind: "text",
1441
+ text: { default: "Hello" },
1442
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1443
+ },
1444
+ image: { id: "lyr_image", kind: "image", alt: "x" },
1445
+ lottie: { id: "lyr_lottie", kind: "lottie", loop: true },
1446
+ video: { id: "lyr_video", kind: "video", loop: true },
1447
+ icon: { id: "lyr_icon", kind: "icon", family: "ionicons", iconName: "star-outline" },
1448
+ button: {
1449
+ id: "lyr_btn",
1450
+ kind: "button",
1451
+ variant: "primary",
1452
+ action: { kind: "continue" },
1453
+ children: [label("lyr_btn_t", "Go")]
1454
+ },
1455
+ back_button: {
1456
+ id: "lyr_back",
1457
+ kind: "back_button",
1458
+ variant: "secondary",
1459
+ children: [label("lyr_back_t", "Back")]
1460
+ },
1461
+ progress: { id: "lyr_prog", kind: "progress", style: { height: 6 } },
1462
+ loader: { id: "lyr_load", kind: "loader", variant: "linear" },
1463
+ counter: {
1464
+ id: "lyr_ctr",
1465
+ kind: "counter",
1466
+ startValue: 0,
1467
+ endValue: 10,
1468
+ durationMs: 500
1469
+ },
1470
+ single_choice: {
1471
+ id: "lyr_sc",
1472
+ kind: "single_choice",
1473
+ fieldKey: "pick",
1474
+ branching: { enabled: false, conditions: [] },
1475
+ ...choiceOptions("lyr_sc")
1476
+ },
1477
+ multiple_choice: {
1478
+ id: "lyr_mc",
1479
+ kind: "multiple_choice",
1480
+ fieldKey: "tags",
1481
+ branching: { enabled: false, conditions: [] },
1482
+ ...choiceOptions("lyr_mc")
1483
+ },
1484
+ text_input: {
1485
+ id: "lyr_ti",
1486
+ kind: "text_input",
1487
+ fieldKey: "name",
1488
+ classification: "safe"
1489
+ },
1490
+ scale_input: {
1491
+ id: "lyr_scale",
1492
+ kind: "scale_input",
1493
+ fieldKey: "level",
1494
+ min: 1,
1495
+ max: 5,
1496
+ defaultValue: 3
1497
+ },
1498
+ oauth_provider: {
1499
+ id: "lyr_oauth_gh",
1500
+ kind: "oauth_provider",
1501
+ variant: "preset",
1502
+ provider: "github"
1503
+ },
1504
+ oauth_login: {
1505
+ id: "lyr_oauth",
1506
+ kind: "oauth_login",
1507
+ gap: 8,
1508
+ children: [
1509
+ {
1510
+ id: "lyr_oauth_gh_inner",
1511
+ kind: "oauth_provider",
1512
+ variant: "preset",
1513
+ provider: "google"
1514
+ }
1515
+ ]
1516
+ },
1517
+ email_password_auth: {
1518
+ id: "lyr_epa",
1519
+ kind: "email_password_auth",
1520
+ mode: "sign_in",
1521
+ fieldKey: "credentials",
1522
+ children: [
1523
+ {
1524
+ id: "lyr_epf_email",
1525
+ kind: "email_password_field",
1526
+ slot: "email",
1527
+ placeholder: { default: "Email" }
1528
+ },
1529
+ {
1530
+ id: "lyr_epf_pass",
1531
+ kind: "email_password_field",
1532
+ slot: "password",
1533
+ placeholder: { default: "Password" }
1534
+ },
1535
+ {
1536
+ id: "lyr_eps",
1537
+ kind: "email_password_submit",
1538
+ buttonVariant: "primary",
1539
+ children: [label("lyr_eps_t", "Sign in")]
1540
+ }
1541
+ ]
1542
+ },
1543
+ email_password_field: {
1544
+ id: "lyr_epf_only",
1545
+ kind: "email_password_field",
1546
+ slot: "email"
1547
+ },
1548
+ email_password_submit: {
1549
+ id: "lyr_eps_only",
1550
+ kind: "email_password_submit",
1551
+ buttonVariant: "primary",
1552
+ children: [label("lyr_eps_only_t", "Submit")]
1553
+ },
1554
+ carousel: {
1555
+ id: "lyr_car",
1556
+ kind: "carousel",
1557
+ slides: [
1558
+ {
1559
+ id: "lyr_slide",
1560
+ kind: "stack",
1561
+ direction: "vertical",
1562
+ gap: 8,
1563
+ children: [
1564
+ {
1565
+ id: "lyr_slide_t",
1566
+ kind: "text",
1567
+ text: { default: "Slide" },
1568
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1569
+ }
1570
+ ]
1571
+ }
1572
+ ]
1573
+ },
1574
+ hyperlink: {
1575
+ id: "lyr_link",
1576
+ kind: "hyperlink",
1577
+ href: "https://example.com",
1578
+ children: [
1579
+ {
1580
+ id: "lyr_link_t",
1581
+ kind: "text",
1582
+ text: { default: "Link" },
1583
+ style: { color: DEFAULT_THEMED_FOREGROUND }
1584
+ }
1585
+ ]
1586
+ },
1587
+ checkbox: {
1588
+ id: "lyr_chk",
1589
+ kind: "checkbox",
1590
+ fieldKey: "agree"
1591
+ }
1592
+ });
1593
+ var manifestScreenLayerKinds = () => LAYER_KINDS.filter(
1594
+ (k) => k !== "oauth_provider" && k !== "email_password_field" && k !== "email_password_submit"
1595
+ );
1596
+ var ANIMATABLE_PROPERTIES = [
1597
+ "opacity",
1598
+ "translateX",
1599
+ "translateY",
1600
+ "scale"
1601
+ ];
1602
+ var AnimatablePropertySchema = z.enum(ANIMATABLE_PROPERTIES);
1603
+ var EASING_TOKENS = [
1604
+ "linear",
1605
+ "ease-in",
1606
+ "ease-out",
1607
+ "ease-in-out",
1608
+ "standard",
1609
+ "emphasized"
1610
+ ];
1611
+ var EasingTokenSchema = z.enum(EASING_TOKENS);
1612
+ var KeyframeSchema = z.object({
1613
+ t: z.number().min(0).max(1),
1614
+ value: z.number(),
1615
+ /** Easing applied from this keyframe to the next; defaults to linear. */
1616
+ easing: EasingTokenSchema.optional()
1617
+ }).strict();
1618
+ var KeyframeTrackSchema = z.object({
1619
+ property: AnimatablePropertySchema,
1620
+ keyframes: z.array(KeyframeSchema).min(2)
1621
+ }).strict().superRefine((track, ctx) => {
1622
+ let last = -Infinity;
1623
+ for (const k of track.keyframes) {
1624
+ if (k.t < last) {
1625
+ ctx.addIssue({
1626
+ code: z.ZodIssueCode.custom,
1627
+ message: `keyframe times must be monotonically non-decreasing on track "${track.property}"`
1628
+ });
1629
+ return;
1630
+ }
1631
+ last = k.t;
1632
+ }
1633
+ if (track.keyframes[0].t !== 0) {
1634
+ ctx.addIssue({
1635
+ code: z.ZodIssueCode.custom,
1636
+ message: `track "${track.property}" first keyframe must start at t=0`
1637
+ });
1638
+ }
1639
+ if (track.keyframes[track.keyframes.length - 1].t !== 1) {
1640
+ ctx.addIssue({
1641
+ code: z.ZodIssueCode.custom,
1642
+ message: `track "${track.property}" last keyframe must end at t=1`
1643
+ });
1644
+ }
1645
+ });
1646
+ var ANIMATION_TRIGGERS = ["mount", "stagger", "unmount"];
1647
+ var AnimationTriggerSchema = z.enum(ANIMATION_TRIGGERS);
1648
+ var AnimationClipSchema = z.object({
1649
+ id: z.string().min(1).max(64),
1650
+ targetLayerId: LayerIdSchema,
1651
+ trigger: AnimationTriggerSchema,
1652
+ /** Position in the screen's stagger order. Required when trigger is `stagger`. */
1653
+ staggerIndex: z.number().int().min(0).max(64).optional(),
1654
+ /** Total clip duration in milliseconds (renderer scales 0..1 keyframes by this). */
1655
+ durationMs: z.number().int().min(0).max(36e5),
1656
+ /** Pre-roll delay before the clip begins, in ms. Stagger adds on top of this. */
1657
+ delayMs: z.number().int().min(0).max(36e5).optional(),
1658
+ tracks: z.array(KeyframeTrackSchema).min(1)
1659
+ }).strict().superRefine((clip, ctx) => {
1660
+ if (clip.trigger === "unmount" && clip.staggerIndex !== void 0) {
1661
+ ctx.addIssue({
1662
+ code: z.ZodIssueCode.custom,
1663
+ message: `clip "${clip.id}" with trigger "unmount" must not set staggerIndex`,
1664
+ path: ["staggerIndex"]
1665
+ });
1666
+ }
1667
+ if (clip.trigger === "stagger" && clip.staggerIndex === void 0) {
1668
+ ctx.addIssue({
1669
+ code: z.ZodIssueCode.custom,
1670
+ message: `clip "${clip.id}" with trigger "stagger" must define staggerIndex`,
1671
+ path: ["staggerIndex"]
1672
+ });
1673
+ }
1674
+ const seenProps = /* @__PURE__ */ new Set();
1675
+ for (const track of clip.tracks) {
1676
+ if (seenProps.has(track.property)) {
1677
+ ctx.addIssue({
1678
+ code: z.ZodIssueCode.custom,
1679
+ message: `clip "${clip.id}" has duplicate track for property "${track.property}"`
1680
+ });
1681
+ }
1682
+ seenProps.add(track.property);
1683
+ }
1684
+ });
1685
+ var DEFAULT_ANIMATION_CLIP_DURATION_MS = 500;
1686
+ var ScreenStaggerSchema = z.object({
1687
+ /** Per-index delay multiplier in ms. */
1688
+ stepMs: z.number().int().min(0).max(2e3)
1689
+ }).strict();
1690
+ var SCREEN_BACKGROUND_PLAYBACK_PREFIX = "__screen_bg__:";
1691
+ var screenBackgroundPlaybackId = (screenId) => `${SCREEN_BACKGROUND_PLAYBACK_PREFIX}${screenId}`;
1692
+ var isScreenBackgroundPlaybackId = (id) => id.startsWith(SCREEN_BACKGROUND_PLAYBACK_PREFIX);
1693
+ var ScreenBackgroundFitSchema = z.enum(["cover", "contain", "fill"]);
1694
+ var ScreenBackgroundScrimSchema = z.object({
1695
+ color: ThemedColorSchema.optional(),
1696
+ opacity: z.number().min(0).max(1).optional()
1697
+ }).partial();
1698
+ var screenBackgroundMediaShape = {
1699
+ media: MediaReferenceSchema.optional(),
1700
+ fit: ScreenBackgroundFitSchema.optional(),
1701
+ opacity: z.number().min(0).max(1).optional(),
1702
+ scrim: ScreenBackgroundScrimSchema.optional()
1703
+ };
1704
+ var ScreenBackgroundColorFillSchema = z.object({
1705
+ kind: z.literal("color"),
1706
+ color: ThemedColorSchema.optional(),
1707
+ opacity: z.number().min(0).max(1).optional()
1708
+ });
1709
+ var ScreenBackgroundImageFillSchema = z.object({
1710
+ kind: z.literal("image"),
1711
+ ...screenBackgroundMediaShape
1712
+ });
1713
+ var ScreenBackgroundVideoFillSchema = z.object({
1714
+ kind: z.literal("video"),
1715
+ ...screenBackgroundMediaShape,
1716
+ loop: z.boolean().optional(),
1717
+ autoPlay: z.boolean().optional(),
1718
+ triggerLayerId: z.string().min(1).optional(),
1719
+ onComplete: LoaderOnCompleteSchema.optional(),
1720
+ audioEnabled: z.boolean().optional()
1721
+ });
1722
+ var ScreenBackgroundFillSchema = z.discriminatedUnion("kind", [
1723
+ ScreenBackgroundColorFillSchema,
1724
+ ScreenBackgroundImageFillSchema,
1725
+ ScreenBackgroundVideoFillSchema
1726
+ ]);
1727
+ var ScreenBackgroundFillPatchSchema = z.object({
1728
+ color: ThemedColorSchema.optional(),
1729
+ fit: ScreenBackgroundFitSchema.optional(),
1730
+ opacity: z.number().min(0).max(1).optional(),
1731
+ scrim: ScreenBackgroundScrimSchema.optional(),
1732
+ loop: z.boolean().optional(),
1733
+ autoPlay: z.boolean().optional(),
1734
+ triggerLayerId: z.string().min(1).optional(),
1735
+ onComplete: LoaderOnCompleteSchema.optional(),
1736
+ audioEnabled: z.boolean().optional()
1737
+ }).partial();
1738
+ var defaultScreenBackgroundColorFill = () => ({
1739
+ kind: "color"
1740
+ });
1741
+ var defaultScreenBackgroundImageFill = (mediaAssetId) => ({
1742
+ kind: "image",
1743
+ media: { mediaAssetId },
1744
+ fit: "cover"
1745
+ });
1746
+ var defaultScreenBackgroundVideoFill = (mediaAssetId) => ({
1747
+ kind: "video",
1748
+ media: { mediaAssetId },
1749
+ fit: "cover",
1750
+ loop: true,
1751
+ autoPlay: true,
1752
+ audioEnabled: false
1753
+ });
1754
+ var ScreenContainerBreakpointPatchSchema = z.object({
1755
+ padding: PaddingSchema.optional(),
1756
+ margin: PaddingSchema.optional(),
1757
+ insetSafeArea: z.boolean().optional(),
1758
+ backgroundFillPatch: ScreenBackgroundFillPatchSchema.optional()
1759
+ }).partial();
1760
+ var ScreenContainerStyleBreakpointsSchema = z.object({
1761
+ sm: ScreenContainerBreakpointPatchSchema.optional(),
1762
+ md: ScreenContainerBreakpointPatchSchema.optional(),
1763
+ lg: ScreenContainerBreakpointPatchSchema.optional(),
1764
+ xl: ScreenContainerBreakpointPatchSchema.optional(),
1765
+ "2xl": ScreenContainerBreakpointPatchSchema.optional()
1766
+ }).partial().optional();
1767
+ var DecisionNodeIdSchema = z.string().min(1).max(64).regex(/^dec_[a-z0-9_]+$/i, "decision node id must look like dec_<id>");
1768
+ var ExternalSurfaceJumpIdSchema = z.string().min(1).max(64).regex(/^surf_[a-z0-9_]+$/i, "external surface node id must look like surf_<id>");
1769
+ var EXTERNAL_SURFACE_NO_NEXT = "__onb_surface_no_next__";
1770
+ var DECISION_ELSE_SOURCE_HANDLE = "__dec_else__";
1771
+ var ExternalSurfaceTerminalTargetSchema = z.literal(EXTERNAL_SURFACE_NO_NEXT);
1772
+ var FlowJumpTargetSchema = ScreenIdSchema.or(DecisionNodeIdSchema).or(ExternalSurfaceJumpIdSchema).or(ExternalSurfaceTerminalTargetSchema).nullable();
1773
+ var DecisionBuiltinNameSchema = z.enum(["locale", "platform"]);
1774
+ var DecisionVariableRefSchema = z.discriminatedUnion("kind", [
1775
+ z.object({ kind: z.literal("builtin"), name: DecisionBuiltinNameSchema }),
1776
+ z.object({ kind: z.literal("sdk"), key: z.string().min(1).max(128) }),
1777
+ z.object({ kind: z.literal("field"), fieldKey: z.string().min(1).max(128) })
1778
+ ]);
1779
+ var DecisionStringPredicateSchema = z.discriminatedUnion("op", [
1780
+ z.object({ op: z.literal("eq"), value: z.string() }),
1781
+ z.object({ op: z.literal("neq"), value: z.string() }),
1782
+ z.object({ op: z.literal("contains"), value: z.string() })
1783
+ ]);
1784
+ var DecisionNumberPredicateSchema = z.discriminatedUnion("op", [
1785
+ z.object({ op: z.literal("eq"), value: z.number() }),
1786
+ z.object({ op: z.literal("neq"), value: z.number() }),
1787
+ z.object({ op: z.literal("lt"), value: z.number() }),
1788
+ z.object({ op: z.literal("lte"), value: z.number() }),
1789
+ z.object({ op: z.literal("gt"), value: z.number() }),
1790
+ z.object({ op: z.literal("gte"), value: z.number() })
1791
+ ]);
1792
+ var DecisionChoicePredicateSchema = z.discriminatedUnion("op", [
1793
+ z.object({ op: z.literal("eq"), optionId: z.string().min(1) }),
1794
+ z.object({ op: z.literal("one_of"), optionIds: z.array(z.string().min(1)).min(1) })
1795
+ ]);
1796
+ var DecisionMultiPredicateSchema = z.discriminatedUnion("op", [
1797
+ z.object({
1798
+ op: z.literal("intersects"),
1799
+ optionIds: z.array(z.string().min(1)).min(1)
1800
+ }),
1801
+ z.object({
1802
+ op: z.literal("contains_all"),
1803
+ optionIds: z.array(z.string().min(1)).min(1)
1804
+ }),
1805
+ z.object({
1806
+ op: z.literal("subset_of"),
1807
+ optionIds: z.array(z.string().min(1)).min(1)
1808
+ })
1809
+ ]);
1810
+ var DecisionBooleanPredicateSchema = z.discriminatedUnion("op", [
1811
+ z.object({ op: z.literal("eq"), value: z.boolean() }),
1812
+ z.object({ op: z.literal("neq"), value: z.boolean() })
1813
+ ]);
1814
+ var DecisionPredicatePayloadSchema = z.discriminatedUnion("type", [
1815
+ z.object({ type: z.literal("string"), pred: DecisionStringPredicateSchema }),
1816
+ z.object({ type: z.literal("number"), pred: DecisionNumberPredicateSchema }),
1817
+ z.object({ type: z.literal("boolean"), pred: DecisionBooleanPredicateSchema }),
1818
+ z.object({ type: z.literal("choice"), pred: DecisionChoicePredicateSchema }),
1819
+ z.object({ type: z.literal("multi"), pred: DecisionMultiPredicateSchema })
1820
+ ]);
1821
+ var DecisionExprSchema = z.lazy(
1822
+ () => z.discriminatedUnion("kind", [
1823
+ z.object({ kind: z.literal("empty") }),
1824
+ z.object({
1825
+ kind: z.literal("group"),
1826
+ op: z.enum(["and", "or"]),
1827
+ children: z.array(DecisionExprSchema).min(1)
1828
+ }),
1829
+ z.object({
1830
+ kind: z.literal("predicate"),
1831
+ variable: DecisionVariableRefSchema,
1832
+ predicate: DecisionPredicatePayloadSchema
1833
+ })
1834
+ ])
1835
+ );
1836
+ var DecisionCaseSchema = z.object({
1837
+ id: z.string().min(1).max(80),
1838
+ /** Display label in the editor (e.g. “Engaged users”). */
1839
+ name: z.string().min(1).max(80).optional(),
1840
+ expression: DecisionExprSchema,
1841
+ next: FlowJumpTargetSchema
1842
+ });
1843
+ var DecisionNodeSchema = z.object({
1844
+ id: DecisionNodeIdSchema,
1845
+ name: z.string().min(1).max(80).optional(),
1846
+ cases: z.array(DecisionCaseSchema).min(1).max(16),
1847
+ elseNext: FlowJumpTargetSchema
1848
+ });
1849
+ var migrateLegacyDecisionNodeInPlace = (node) => {
1850
+ if (!node || typeof node !== "object") return;
1851
+ if (Array.isArray(node.cases)) return;
1852
+ if (!("expression" in node)) return;
1853
+ const id = typeof node.id === "string" ? node.id : "dec_unknown";
1854
+ const expression = node.expression;
1855
+ const onTrue = "onTrue" in node ? node.onTrue ?? null : null;
1856
+ const onFalse = "onFalse" in node ? node.onFalse ?? null : null;
1857
+ delete node.expression;
1858
+ delete node.onTrue;
1859
+ delete node.onFalse;
1860
+ node.cases = [
1861
+ {
1862
+ id: `${id}_case_0`,
1863
+ name: "Group 1",
1864
+ expression,
1865
+ next: onTrue
1866
+ }
1867
+ ];
1868
+ node.elseNext = onFalse;
1869
+ };
1870
+ var collectDecisionSdkKeys = (expr) => {
1871
+ const out = [];
1872
+ const walk = (e) => {
1873
+ if (e.kind === "empty") return;
1874
+ if (e.kind === "predicate") {
1875
+ if (e.variable.kind === "sdk") out.push(e.variable.key);
1876
+ return;
1877
+ }
1878
+ for (const c of e.children) walk(c);
1879
+ };
1880
+ walk(expr);
1881
+ return out;
1882
+ };
1883
+ var collectDecisionFieldKeys = (expr) => {
1884
+ const out = [];
1885
+ const walk = (e) => {
1886
+ if (e.kind === "empty") return;
1887
+ if (e.kind === "predicate") {
1888
+ if (e.variable.kind === "field") out.push(e.variable.fieldKey);
1889
+ return;
1890
+ }
1891
+ for (const c of e.children) walk(c);
1892
+ };
1893
+ walk(expr);
1894
+ return out;
1895
+ };
1896
+ var collectDecisionSdkKeysFromNode = (node) => {
1897
+ const seen = /* @__PURE__ */ new Set();
1898
+ for (const c of node.cases) {
1899
+ for (const k of collectDecisionSdkKeys(c.expression)) seen.add(k);
1900
+ }
1901
+ return [...seen];
1902
+ };
1903
+ var collectDecisionFieldKeysFromNode = (node) => {
1904
+ const seen = /* @__PURE__ */ new Set();
1905
+ for (const c of node.cases) {
1906
+ for (const k of collectDecisionFieldKeys(c.expression)) seen.add(k);
1907
+ }
1908
+ return [...seen];
1909
+ };
1910
+
1911
+ // src/screens.ts
1912
+ var ScreenNextSchema = z.object({
1913
+ default: FlowJumpTargetSchema
1914
+ });
1915
+ var ScreenRegionsSchema = z.object({
1916
+ header: StackLayerSchema.optional(),
1917
+ body: StackLayerSchema,
1918
+ footer: StackLayerSchema.optional()
1919
+ });
1920
+ var ScreenContainerStyleSchema = z.object({
1921
+ padding: PaddingSchema.optional(),
1922
+ margin: PaddingSchema.optional(),
1923
+ /** When true, runtimes add device safe-area insets to shell padding (in addition to manual padding). */
1924
+ insetSafeArea: z.boolean().optional(),
1925
+ backgroundFill: ScreenBackgroundFillSchema.optional()
1926
+ }).partial();
1927
+ var ScreenSchema = z.object({
1928
+ id: ScreenIdSchema,
1929
+ name: z.string().min(1).max(80),
1930
+ regions: ScreenRegionsSchema,
1931
+ next: ScreenNextSchema,
1932
+ /** Ordered animation clips bound to layers on this screen. */
1933
+ animations: z.array(AnimationClipSchema).optional(),
1934
+ /** Defaults for clips with `trigger: stagger`. */
1935
+ stagger: ScreenStaggerSchema.optional(),
1936
+ /** Chrome on the outer screen container (wraps all regions). */
1937
+ containerStyle: ScreenContainerStyleSchema.optional(),
1938
+ containerStyleBreakpoints: ScreenContainerStyleBreakpointsSchema
1939
+ });
1940
+ var walkScreenLayersWithLayoutContext = (screen, fn) => {
1941
+ const visit = (l, ctx) => {
1942
+ fn(l, ctx);
1943
+ const childCtx = (opts = {}) => ({
1944
+ region: ctx.region,
1945
+ isRegionRoot: false,
1946
+ insideChoiceOption: opts.insideChoiceOption ?? ctx.insideChoiceOption,
1947
+ parentKind: l.kind
1948
+ });
1949
+ if (l.kind === "stack") {
1950
+ for (const c of l.children) visit(c, childCtx());
1951
+ } else if (l.kind === "carousel") {
1952
+ for (const s of l.slides) visit(s, childCtx());
1953
+ } else if (l.kind === "button" || l.kind === "back_button") {
1954
+ for (const c of l.children) visit(c, childCtx());
1955
+ } else if (l.kind === "hyperlink") {
1956
+ for (const c of l.children) visit(c, childCtx());
1957
+ } else if (l.kind === "single_choice" || l.kind === "multiple_choice") {
1958
+ for (const c of l.children) {
1959
+ visit(c, childCtx({ insideChoiceOption: true }));
1960
+ }
1961
+ } else if (l.kind === "text_input" || l.kind === "scale_input") {
1962
+ for (const c of l.children ?? []) visit(c, childCtx());
1963
+ } else if (l.kind === "oauth_login") {
1964
+ for (const c of l.children) visit(c, childCtx());
1965
+ } else if (l.kind === "oauth_provider" && l.variant === "custom") {
1966
+ for (const c of l.children) visit(c, childCtx());
1967
+ } else if (l.kind === "email_password_auth") {
1968
+ for (const c of l.children) visit(c, childCtx());
1969
+ } else if (l.kind === "email_password_field") {
1970
+ for (const c of l.children ?? []) visit(c, childCtx());
1971
+ } else if (l.kind === "email_password_submit") {
1972
+ for (const c of l.children) visit(c, childCtx());
1973
+ }
1974
+ };
1975
+ const regionCtx = (region) => ({
1976
+ region,
1977
+ isRegionRoot: true,
1978
+ insideChoiceOption: false,
1979
+ parentKind: null
1980
+ });
1981
+ if (screen.regions.header) visit(screen.regions.header, regionCtx("header"));
1982
+ visit(screen.regions.body, regionCtx("body"));
1983
+ if (screen.regions.footer) visit(screen.regions.footer, regionCtx("footer"));
1984
+ };
1985
+ var walkScreenLayers = (screen, fn) => {
1986
+ const visit = (l) => {
1987
+ fn(l);
1988
+ if (l.kind === "stack") l.children.forEach(visit);
1989
+ else if (l.kind === "carousel") l.slides.forEach(visit);
1990
+ else if (l.kind === "button") l.children.forEach(visit);
1991
+ else if (l.kind === "back_button") l.children.forEach(visit);
1992
+ else if (l.kind === "hyperlink") l.children.forEach(visit);
1993
+ else if (l.kind === "single_choice" || l.kind === "multiple_choice") {
1994
+ l.children.forEach(visit);
1995
+ } else if (l.kind === "text_input" || l.kind === "scale_input") {
1996
+ l.children?.forEach(visit);
1997
+ } else if (l.kind === "oauth_login") {
1998
+ l.children.forEach(visit);
1999
+ } else if (l.kind === "oauth_provider" && l.variant === "custom") {
2000
+ l.children.forEach(visit);
2001
+ } else if (l.kind === "email_password_auth") {
2002
+ l.children.forEach(visit);
2003
+ } else if (l.kind === "email_password_field") {
2004
+ l.children?.forEach(visit);
2005
+ } else if (l.kind === "email_password_submit") {
2006
+ l.children.forEach(visit);
2007
+ }
2008
+ };
2009
+ if (screen.regions.header) visit(screen.regions.header);
2010
+ visit(screen.regions.body);
2011
+ if (screen.regions.footer) visit(screen.regions.footer);
2012
+ };
2013
+ var collectAnswerCaptureFieldKeysFromScreen = (screen) => {
2014
+ const keys = [];
2015
+ walkScreenLayers(screen, (l) => {
2016
+ if (isInputLayer(l)) keys.push(l.fieldKey);
2017
+ if (l.kind === "checkbox") keys.push(l.fieldKey);
2018
+ if (l.kind === "button" && l.action.kind === "request_os_permission") {
2019
+ keys.push(permissionCaptureFieldKey(l.action.permissionKey));
2020
+ }
2021
+ if (l.kind === "button" && l.action.kind === "request_app_review") {
2022
+ keys.push(appReviewCaptureFieldKey(l.id));
2023
+ }
2024
+ });
2025
+ return keys;
2026
+ };
2027
+ var ExternalSurfaceNodeIdSchema = z.string().min(1).max(64).regex(/^surf_[a-z0-9_]+$/i, "external surface node id must look like surf_<id>");
2028
+ var NORMALIZED_SURFACE_OUTCOMES = [
2029
+ "purchase_completed",
2030
+ "purchase_cancelled",
2031
+ "dismissed",
2032
+ "failed",
2033
+ "restore_completed"
2034
+ ];
2035
+ var NormalizedSurfaceOutcomeSchema = z.enum(NORMALIZED_SURFACE_OUTCOMES);
2036
+ var SurfaceProviderSchema = z.enum(["unspecified", "revenuecat"]);
2037
+ var UnspecifiedExternalSurfaceConfigSchema = z.object({
2038
+ provider: z.literal("unspecified")
2039
+ });
2040
+ var RevenueCatSurfacePresentationSchema = z.enum(["paywall", "paywall_if_needed"]);
2041
+ var RevenueCatSurfaceConfigSchema = z.object({
2042
+ provider: z.literal("revenuecat"),
2043
+ offeringId: z.string().min(1).max(128).optional(),
2044
+ placementId: z.string().min(1).max(128).optional(),
2045
+ presentation: RevenueCatSurfacePresentationSchema.optional()
2046
+ });
2047
+ var ExternalSurfaceConfigSchema = z.discriminatedUnion("provider", [
2048
+ UnspecifiedExternalSurfaceConfigSchema,
2049
+ RevenueCatSurfaceConfigSchema
2050
+ ]);
2051
+ var ExternalSurfaceOutcomesMapSchema = z.object({
2052
+ purchase_completed: FlowJumpTargetSchema.optional(),
2053
+ purchase_cancelled: FlowJumpTargetSchema.optional(),
2054
+ dismissed: FlowJumpTargetSchema.optional(),
2055
+ failed: FlowJumpTargetSchema.optional(),
2056
+ restore_completed: FlowJumpTargetSchema.optional()
2057
+ }).strict();
2058
+ var ExternalSurfaceNodeSchema = z.object({
2059
+ id: ExternalSurfaceNodeIdSchema,
2060
+ name: z.string().min(1).max(80).optional(),
2061
+ config: ExternalSurfaceConfigSchema,
2062
+ /** Per-outcome jump targets. Outcomes not listed here fall through to `fallback`. */
2063
+ outcomes: ExternalSurfaceOutcomesMapSchema,
2064
+ /** Required: used for any outcome not in `outcomes` (e.g. provider quirks, unmapped events). */
2065
+ fallback: FlowJumpTargetSchema
2066
+ });
2067
+ var resolveExternalSurfaceTarget = (node, outcome) => node.outcomes[outcome] ?? node.fallback;
2068
+
2069
+ // src/sdkAttributes.ts
2070
+ var RESERVED_RC_SDK_KEYS = [
2071
+ /** Last RC event observed by the SDK (e.g. `purchase_completed`, `purchase_cancelled`). */
2072
+ "onb_rc_last_event",
2073
+ /** Product identifier from the most recent successful purchase. */
2074
+ "onb_rc_last_product_id",
2075
+ /** Period type (`normal`, `intro`, `trial`) from the most recent purchase. */
2076
+ "onb_rc_last_period_type",
2077
+ /** RevenueCat offering id surfaced by the most recent paywall presentation. */
2078
+ "onb_rc_last_offering_id"
2079
+ ];
2080
+ var RESERVED_SDK_KEYS_SET = new Set(RESERVED_RC_SDK_KEYS);
2081
+ var isReservedSdkKey = (key) => RESERVED_SDK_KEYS_SET.has(key);
2082
+
2083
+ // src/manifest/version.ts
2084
+ var MANIFEST_SCHEMA_VERSION = 7;
2085
+ var ThemeSchema = z.object({
2086
+ primary: z.string().optional(),
2087
+ primaryForeground: z.string().optional(),
2088
+ background: z.string().optional(),
2089
+ foreground: z.string().optional(),
2090
+ accent: z.string().optional(),
2091
+ borderRadius: z.number().optional(),
2092
+ fontFamily: z.string().optional()
2093
+ });
2094
+ var BuilderMetaSchema = z.object({
2095
+ layout: z.object({
2096
+ nodes: z.array(
2097
+ z.object({
2098
+ id: z.string(),
2099
+ kind: z.enum(["screen", "decision"]).optional(),
2100
+ x: z.number(),
2101
+ y: z.number()
2102
+ })
2103
+ ).optional(),
2104
+ canvas: z.object({
2105
+ zoom: z.number().optional(),
2106
+ x: z.number().optional(),
2107
+ y: z.number().optional()
2108
+ }).optional()
2109
+ }).optional()
2110
+ }).passthrough().optional();
2111
+
2112
+ // src/manifest/migrate.ts
2113
+ var migrateLayerInPlace = (layer) => {
2114
+ if (!layer || typeof layer !== "object") return;
2115
+ const l = layer;
2116
+ if (l.kind === "progress_bar") {
2117
+ l.kind = "progress";
2118
+ }
2119
+ if (l.kind === "icon" && l.family === "sf_symbol") {
2120
+ l.family = "ionicons";
2121
+ l.iconName = "star-outline";
2122
+ }
2123
+ if (l.kind === "button") {
2124
+ const hasChildren = Array.isArray(l.children);
2125
+ const hasLegacyLabel = !!l.label && typeof l.label === "object";
2126
+ if (!hasChildren && hasLegacyLabel) {
2127
+ const id = typeof l.id === "string" ? `${l.id}_text` : "lyr_btn_text";
2128
+ l.children = [
2129
+ {
2130
+ id,
2131
+ kind: "text",
2132
+ text: l.label
2133
+ }
2134
+ ];
2135
+ delete l.label;
2136
+ } else if (!hasChildren) {
2137
+ l.children = [];
2138
+ }
2139
+ }
2140
+ if (l.kind === "hyperlink") {
2141
+ const hasKids = Array.isArray(l.children) && l.children.length > 0;
2142
+ const hasLegacyText = l.text !== void 0 && l.text !== null;
2143
+ if (!hasKids && hasLegacyText) {
2144
+ const baseId = typeof l.id === "string" ? `${l.id}_lnktxt` : "lyr_hyperlink_lnktxt";
2145
+ const row = {
2146
+ id: String(baseId).slice(0, 64),
2147
+ kind: "text",
2148
+ text: l.text
2149
+ };
2150
+ if (l.style !== void 0) row.style = l.style;
2151
+ if (l.styleBreakpoints !== void 0) row.styleBreakpoints = l.styleBreakpoints;
2152
+ l.children = [row];
2153
+ delete l.text;
2154
+ delete l.style;
2155
+ delete l.styleBreakpoints;
2156
+ } else if (!Array.isArray(l.children)) {
2157
+ l.children = [];
2158
+ }
2159
+ }
2160
+ if (l.kind === "stack" && Array.isArray(l.children)) {
2161
+ for (const c of l.children) migrateLayerInPlace(c);
2162
+ } else if (l.kind === "carousel" && Array.isArray(l.slides)) {
2163
+ for (const s of l.slides) migrateLayerInPlace(s);
2164
+ } else if (l.kind === "button" && Array.isArray(l.children)) {
2165
+ for (const c of l.children) migrateLayerInPlace(c);
2166
+ } else if (l.kind === "back_button" && Array.isArray(l.children)) {
2167
+ for (const c of l.children) migrateLayerInPlace(c);
2168
+ } else if (l.kind === "hyperlink" && Array.isArray(l.children)) {
2169
+ for (const c of l.children) migrateLayerInPlace(c);
2170
+ } else if (l.kind === "oauth_login" && Array.isArray(l.children)) {
2171
+ for (const c of l.children) migrateLayerInPlace(c);
2172
+ } else if (l.kind === "oauth_provider" && l.variant === "custom" && Array.isArray(l.children)) {
2173
+ for (const c of l.children) migrateLayerInPlace(c);
2174
+ } else if (l.kind === "email_password_auth" && Array.isArray(l.children)) {
2175
+ for (const c of l.children) migrateLayerInPlace(c);
2176
+ } else if (l.kind === "email_password_field" && Array.isArray(l.children)) {
2177
+ for (const c of l.children) migrateLayerInPlace(c);
2178
+ } else if (l.kind === "email_password_submit" && Array.isArray(l.children)) {
2179
+ for (const c of l.children) migrateLayerInPlace(c);
2180
+ }
2181
+ };
2182
+ var migrateScreenInPlace = (screen) => {
2183
+ if (!screen || typeof screen !== "object") return;
2184
+ const s = screen;
2185
+ if (s.regions) {
2186
+ if (s.regions.header) migrateLayerInPlace(s.regions.header);
2187
+ if (s.regions.body) migrateLayerInPlace(s.regions.body);
2188
+ if (s.regions.footer) migrateLayerInPlace(s.regions.footer);
2189
+ }
2190
+ if (s.animations === void 0) {
2191
+ delete s.animations;
2192
+ }
2193
+ };
2194
+ var migrateManifestInPlace = (data) => {
2195
+ if (!data || typeof data !== "object") return data;
2196
+ const d = data;
2197
+ if (Array.isArray(d.screens)) {
2198
+ for (const s of d.screens) migrateScreenInPlace(s);
2199
+ }
2200
+ if (!Array.isArray(d.decisionNodes)) d.decisionNodes = [];
2201
+ if (Array.isArray(d.decisionNodes)) {
2202
+ for (const node of d.decisionNodes) {
2203
+ if (node && typeof node === "object") {
2204
+ migrateLegacyDecisionNodeInPlace(node);
2205
+ }
2206
+ }
2207
+ }
2208
+ if (!Array.isArray(d.externalSurfaceNodes)) d.externalSurfaceNodes = [];
2209
+ if (!Array.isArray(d.sdkAttributeKeys)) d.sdkAttributeKeys = [];
2210
+ if (d.schemaVersion === 6) d.schemaVersion = MANIFEST_SCHEMA_VERSION;
2211
+ if (d.schemaVersion === 5) d.schemaVersion = MANIFEST_SCHEMA_VERSION;
2212
+ if (d.schemaVersion === 4) d.schemaVersion = MANIFEST_SCHEMA_VERSION;
2213
+ return data;
2214
+ };
2215
+ var migrateLegacyManifest = (raw) => {
2216
+ if (!raw || typeof raw !== "object") return raw;
2217
+ const clone = JSON.parse(JSON.stringify(raw));
2218
+ return migrateManifestInPlace(clone);
2219
+ };
2220
+ var FlowManifestObjectBaseSchema = z.object({
2221
+ flowId: z.string().uuid(),
2222
+ /** Manifest schema version — see {@link MANIFEST_SCHEMA_VERSION}. */
2223
+ schemaVersion: z.literal(MANIFEST_SCHEMA_VERSION).optional(),
2224
+ version: z.number().int().positive(),
2225
+ defaultLocale: LocaleCode,
2226
+ locales: z.array(LocaleCode),
2227
+ /** When null, the draft has no wired entry target (builder connects the canvas entry node). */
2228
+ entryScreenId: z.union([z.string().min(1), z.null()]),
2229
+ screens: z.array(ScreenSchema),
2230
+ decisionNodes: z.union([z.array(DecisionNodeSchema), z.undefined()]).transform((x) => x ?? []),
2231
+ externalSurfaceNodes: z.union([z.array(ExternalSurfaceNodeSchema), z.undefined()]).transform((x) => x ?? []),
2232
+ sdkAttributeKeys: z.union([z.array(z.string().min(1).max(128)), z.undefined()]).transform((x) => x ?? []),
2233
+ theme: ThemeSchema.optional(),
2234
+ builderMeta: BuilderMetaSchema
2235
+ });
2236
+ var buildManifestJumpTargets = (manifest) => {
2237
+ const screenIds = new Set(manifest.screens.map((s) => s.id));
2238
+ const decisionIds = new Set(manifest.decisionNodes.map((d) => d.id));
2239
+ const surfaceIds = new Set(manifest.externalSurfaceNodes.map((s) => s.id));
2240
+ return /* @__PURE__ */ new Set([
2241
+ ...screenIds,
2242
+ ...decisionIds,
2243
+ ...surfaceIds,
2244
+ EXTERNAL_SURFACE_NO_NEXT
2245
+ ]);
2246
+ };
2247
+ var refineManifestGraph = (manifest, ctx, jumpTargets) => {
2248
+ const screenIds = /* @__PURE__ */ new Set();
2249
+ for (const s of manifest.screens) {
2250
+ if (screenIds.has(s.id)) {
2251
+ ctx.addIssue({
2252
+ code: z.ZodIssueCode.custom,
2253
+ message: `duplicate screen id "${s.id}"`,
2254
+ path: ["screens"]
2255
+ });
2256
+ }
2257
+ screenIds.add(s.id);
2258
+ }
2259
+ const decisionIds = new Set(manifest.decisionNodes.map((d) => d.id));
2260
+ const surfaceIds = new Set(manifest.externalSurfaceNodes.map((s) => s.id));
2261
+ if (manifest.entryScreenId != null && !jumpTargets.has(manifest.entryScreenId)) {
2262
+ ctx.addIssue({
2263
+ code: z.ZodIssueCode.custom,
2264
+ message: `entryScreenId "${manifest.entryScreenId}" not found in screens, decisionNodes, or externalSurfaceNodes`,
2265
+ path: ["entryScreenId"]
2266
+ });
2267
+ }
2268
+ const seenDecisionId = /* @__PURE__ */ new Set();
2269
+ const sdkAllow = new Set(manifest.sdkAttributeKeys);
2270
+ manifest.decisionNodes.forEach((dn, di) => {
2271
+ if (seenDecisionId.has(dn.id)) {
2272
+ ctx.addIssue({
2273
+ code: z.ZodIssueCode.custom,
2274
+ message: `duplicate decision node id "${dn.id}"`,
2275
+ path: ["decisionNodes", di]
2276
+ });
2277
+ }
2278
+ seenDecisionId.add(dn.id);
2279
+ if (screenIds.has(dn.id)) {
2280
+ ctx.addIssue({
2281
+ code: z.ZodIssueCode.custom,
2282
+ message: `decision node id "${dn.id}" collides with a screen id`,
2283
+ path: ["decisionNodes", di]
2284
+ });
2285
+ }
2286
+ if (surfaceIds.has(dn.id)) {
2287
+ ctx.addIssue({
2288
+ code: z.ZodIssueCode.custom,
2289
+ message: `decision node id "${dn.id}" collides with an external surface id`,
2290
+ path: ["decisionNodes", di]
2291
+ });
2292
+ }
2293
+ dn.cases.forEach((c, ci) => {
2294
+ if (c.next != null && !jumpTargets.has(c.next)) {
2295
+ ctx.addIssue({
2296
+ code: z.ZodIssueCode.custom,
2297
+ message: `decision "${dn.id}" case "${c.id}" next "${c.next}" not found`,
2298
+ path: ["decisionNodes", di, "cases", ci, "next"]
2299
+ });
2300
+ }
2301
+ for (const sk of collectDecisionSdkKeys(c.expression)) {
2302
+ if (isReservedSdkKey(sk)) continue;
2303
+ if (!sdkAllow.has(sk)) {
2304
+ ctx.addIssue({
2305
+ code: z.ZodIssueCode.custom,
2306
+ message: `decision "${dn.id}" case "${c.id}" references sdk key "${sk}" not in sdkAttributeKeys`,
2307
+ path: ["decisionNodes", di, "cases", ci, "expression"]
2308
+ });
2309
+ }
2310
+ }
2311
+ });
2312
+ if (dn.elseNext != null && !jumpTargets.has(dn.elseNext)) {
2313
+ ctx.addIssue({
2314
+ code: z.ZodIssueCode.custom,
2315
+ message: `decision "${dn.id}" elseNext "${dn.elseNext}" not found`,
2316
+ path: ["decisionNodes", di, "elseNext"]
2317
+ });
2318
+ }
2319
+ });
2320
+ const seenSurfaceId = /* @__PURE__ */ new Set();
2321
+ manifest.externalSurfaceNodes.forEach((sn, si) => {
2322
+ if (seenSurfaceId.has(sn.id)) {
2323
+ ctx.addIssue({
2324
+ code: z.ZodIssueCode.custom,
2325
+ message: `duplicate external surface id "${sn.id}"`,
2326
+ path: ["externalSurfaceNodes", si]
2327
+ });
2328
+ }
2329
+ seenSurfaceId.add(sn.id);
2330
+ if (screenIds.has(sn.id)) {
2331
+ ctx.addIssue({
2332
+ code: z.ZodIssueCode.custom,
2333
+ message: `external surface id "${sn.id}" collides with a screen id`,
2334
+ path: ["externalSurfaceNodes", si]
2335
+ });
2336
+ }
2337
+ if (decisionIds.has(sn.id)) {
2338
+ ctx.addIssue({
2339
+ code: z.ZodIssueCode.custom,
2340
+ message: `external surface id "${sn.id}" collides with a decision node id`,
2341
+ path: ["externalSurfaceNodes", si]
2342
+ });
2343
+ }
2344
+ for (const [outcome, target] of Object.entries(sn.outcomes)) {
2345
+ if (target != null && !jumpTargets.has(target)) {
2346
+ ctx.addIssue({
2347
+ code: z.ZodIssueCode.custom,
2348
+ message: `external surface "${sn.id}" outcome "${outcome}" target "${target}" not found`,
2349
+ path: ["externalSurfaceNodes", si, "outcomes", outcome]
2350
+ });
2351
+ }
2352
+ }
2353
+ if (sn.fallback != null && !jumpTargets.has(sn.fallback)) {
2354
+ ctx.addIssue({
2355
+ code: z.ZodIssueCode.custom,
2356
+ message: `external surface "${sn.id}" fallback "${sn.fallback}" not found`,
2357
+ path: ["externalSurfaceNodes", si, "fallback"]
2358
+ });
2359
+ }
2360
+ });
2361
+ return { screenIds, decisionIds, surfaceIds };
2362
+ };
2363
+ var refineManifestScreens = (manifest, ctx, jumpTargets, screenIds, allFieldKeys) => {
2364
+ const layerIds = /* @__PURE__ */ new Set();
2365
+ manifest.screens.forEach((screen, screenIdx) => {
2366
+ let inputCount = 0;
2367
+ const layerIdsForScreen = /* @__PURE__ */ new Set();
2368
+ walkScreenLayers(screen, (l) => {
2369
+ layerIdsForScreen.add(l.id);
2370
+ });
2371
+ walkScreenLayers(screen, (l) => {
2372
+ if (layerIds.has(l.id)) {
2373
+ ctx.addIssue({
2374
+ code: z.ZodIssueCode.custom,
2375
+ message: `duplicate layer id "${l.id}"`,
2376
+ path: ["screens", screenIdx, "regions"]
2377
+ });
2378
+ }
2379
+ layerIds.add(l.id);
2380
+ if (isInputLayer(l)) {
2381
+ inputCount += 1;
2382
+ if (allFieldKeys.has(l.fieldKey)) {
2383
+ ctx.addIssue({
2384
+ code: z.ZodIssueCode.custom,
2385
+ message: `duplicate fieldKey "${l.fieldKey}" across screens or on the same screen`,
2386
+ path: ["screens", screenIdx]
2387
+ });
2388
+ }
2389
+ allFieldKeys.set(l.fieldKey, screen.id);
2390
+ }
2391
+ if (l.kind === "checkbox") {
2392
+ if (allFieldKeys.has(l.fieldKey)) {
2393
+ ctx.addIssue({
2394
+ code: z.ZodIssueCode.custom,
2395
+ message: `duplicate fieldKey "${l.fieldKey}" across screens or on the same screen`,
2396
+ path: ["screens", screenIdx]
2397
+ });
2398
+ }
2399
+ allFieldKeys.set(l.fieldKey, screen.id);
2400
+ }
2401
+ if (l.kind === "button" && l.action.kind === "request_os_permission") {
2402
+ const fk = permissionCaptureFieldKey(l.action.permissionKey);
2403
+ if (!allFieldKeys.has(fk)) allFieldKeys.set(fk, screen.id);
2404
+ }
2405
+ });
2406
+ if (inputCount > 1) {
2407
+ ctx.addIssue({
2408
+ code: z.ZodIssueCode.custom,
2409
+ message: `screen "${screen.id}" has ${inputCount} input layers (max 1 allowed)`,
2410
+ path: ["screens", screenIdx, "regions"]
2411
+ });
2412
+ }
2413
+ walkScreenLayersWithLayoutContext(screen, (l, layoutCtx) => {
2414
+ if (!layerHasAbsolutePositionAuthored(l)) return;
2415
+ if (layoutCtx.isRegionRoot) {
2416
+ ctx.addIssue({
2417
+ code: z.ZodIssueCode.custom,
2418
+ message: `layer "${l.id}" cannot use absolute positioning on a screen region root`,
2419
+ path: ["screens", screenIdx, "regions"]
2420
+ });
2421
+ }
2422
+ if (layoutCtx.insideChoiceOption) {
2423
+ ctx.addIssue({
2424
+ code: z.ZodIssueCode.custom,
2425
+ message: `layer "${l.id}" cannot use absolute positioning inside a choice option`,
2426
+ path: ["screens", screenIdx, "regions"]
2427
+ });
2428
+ }
2429
+ });
2430
+ walkScreenLayersWithLayoutContext(screen, (l, layoutCtx) => {
2431
+ if (l.kind === "oauth_provider" && layoutCtx.parentKind !== "oauth_login") {
2432
+ ctx.addIssue({
2433
+ code: z.ZodIssueCode.custom,
2434
+ message: `OAuth button "${l.id}" must be nested under an OAuth login layer`,
2435
+ path: ["screens", screenIdx, "regions"]
2436
+ });
2437
+ }
2438
+ if ((l.kind === "email_password_field" || l.kind === "email_password_submit") && layoutCtx.parentKind !== "email_password_auth") {
2439
+ ctx.addIssue({
2440
+ code: z.ZodIssueCode.custom,
2441
+ message: `Layer "${l.id}" (${l.kind}) must be nested under an Email / password login layer`,
2442
+ path: ["screens", screenIdx, "regions"]
2443
+ });
2444
+ }
2445
+ });
2446
+ const nextDefault = screen.next.default;
2447
+ if (nextDefault && !jumpTargets.has(nextDefault)) {
2448
+ ctx.addIssue({
2449
+ code: z.ZodIssueCode.custom,
2450
+ message: `screen "${screen.id}" next.default "${nextDefault}" not found`,
2451
+ path: ["screens", screenIdx, "next", "default"]
2452
+ });
2453
+ }
2454
+ walkScreenLayers(screen, (l) => {
2455
+ if (l.kind === "single_choice" || l.kind === "multiple_choice") {
2456
+ validateChoiceChildrenAndBindings(
2457
+ { children: l.children, optionBindings: l.optionBindings },
2458
+ ctx
2459
+ );
2460
+ const knownOptionIds = new Set(l.optionBindings.map((b) => b.optionId));
2461
+ for (const cond of l.branching.conditions) {
2462
+ if (!screenIds.has(cond.goTo)) {
2463
+ ctx.addIssue({
2464
+ code: z.ZodIssueCode.custom,
2465
+ message: `screen "${screen.id}" branch condition "${cond.choiceId}" -> "${cond.goTo}" not found`,
2466
+ path: ["screens", screenIdx]
2467
+ });
2468
+ }
2469
+ if (!knownOptionIds.has(cond.choiceId)) {
2470
+ ctx.addIssue({
2471
+ code: z.ZodIssueCode.custom,
2472
+ message: `screen "${screen.id}" branch condition references unknown choice "${cond.choiceId}"`,
2473
+ path: ["screens", screenIdx]
2474
+ });
2475
+ }
2476
+ }
2477
+ }
2478
+ if (l.kind === "button" && l.action.kind === "go_to_step") {
2479
+ if (!screenIds.has(l.action.screenId)) {
2480
+ ctx.addIssue({
2481
+ code: z.ZodIssueCode.custom,
2482
+ message: `screen "${screen.id}" button action go_to_step "${l.action.screenId}" not found`,
2483
+ path: ["screens", screenIdx]
2484
+ });
2485
+ }
2486
+ }
2487
+ if (l.kind === "button" && l.action.kind === "go_back_one_screen" && manifest.entryScreenId != null && screen.id === manifest.entryScreenId) {
2488
+ ctx.addIssue({
2489
+ code: z.ZodIssueCode.custom,
2490
+ message: `screen "${screen.id}" is the flow entry screen; buttons cannot use go_back_one_screen`,
2491
+ path: ["screens", screenIdx]
2492
+ });
2493
+ }
2494
+ if (l.kind === "button" && l.action.kind === "request_os_permission") {
2495
+ for (const [label2, sid] of [
2496
+ ["granted", l.action.outcomes.granted],
2497
+ ["denied", l.action.outcomes.denied],
2498
+ ["blocked", l.action.outcomes.blocked]
2499
+ ]) {
2500
+ if (sid === OS_PERMISSION_OUTCOME_END) ; else if (sid === OS_PERMISSION_OUTCOME_CONTINUE) {
2501
+ const def = screen.next.default;
2502
+ if (def != null && !jumpTargets.has(def)) {
2503
+ ctx.addIssue({
2504
+ code: z.ZodIssueCode.custom,
2505
+ message: `screen "${screen.id}" request_os_permission outcomes.${label2} uses default next (continue) but screen.next.default "${def}" is not a valid target`,
2506
+ path: ["screens", screenIdx]
2507
+ });
2508
+ }
2509
+ } else if (!jumpTargets.has(sid)) {
2510
+ ctx.addIssue({
2511
+ code: z.ZodIssueCode.custom,
2512
+ message: `screen "${screen.id}" request_os_permission outcomes.${label2} "${sid}" not found`,
2513
+ path: ["screens", screenIdx]
2514
+ });
2515
+ }
2516
+ }
2517
+ }
2518
+ if (l.kind === "back_button" && l.fallbackScreenId && !screenIds.has(l.fallbackScreenId)) {
2519
+ ctx.addIssue({
2520
+ code: z.ZodIssueCode.custom,
2521
+ message: `screen "${screen.id}" back_button fallback "${l.fallbackScreenId}" not found`,
2522
+ path: ["screens", screenIdx]
2523
+ });
2524
+ }
2525
+ if (l.kind === "button" && l.action.kind === "go_back_one_screen" && l.action.fallbackScreenId && !screenIds.has(l.action.fallbackScreenId)) {
2526
+ ctx.addIssue({
2527
+ code: z.ZodIssueCode.custom,
2528
+ message: `screen "${screen.id}" button go_back_one_screen fallback "${l.action.fallbackScreenId}" not found`,
2529
+ path: ["screens", screenIdx]
2530
+ });
2531
+ }
2532
+ if (l.kind === "text_input") {
2533
+ const minL = l.minLength;
2534
+ const maxL = l.maxLength;
2535
+ if (minL !== void 0 && maxL !== void 0 && minL > maxL) {
2536
+ ctx.addIssue({
2537
+ code: z.ZodIssueCode.custom,
2538
+ message: `text_input "${l.id}" minLength cannot exceed maxLength`,
2539
+ path: ["screens", screenIdx]
2540
+ });
2541
+ }
2542
+ }
2543
+ if (l.kind === "scale_input") {
2544
+ if (l.min >= l.max) {
2545
+ ctx.addIssue({
2546
+ code: z.ZodIssueCode.custom,
2547
+ message: `scale_input "${l.id}" max must be greater than min`,
2548
+ path: ["screens", screenIdx]
2549
+ });
2550
+ }
2551
+ const step = l.step ?? 1;
2552
+ if (l.defaultValue !== void 0) {
2553
+ if (l.defaultValue < l.min || l.defaultValue > l.max) {
2554
+ ctx.addIssue({
2555
+ code: z.ZodIssueCode.custom,
2556
+ message: `scale_input "${l.id}" defaultValue must be between min and max`,
2557
+ path: ["screens", screenIdx]
2558
+ });
2559
+ } else {
2560
+ const rem = (l.defaultValue - l.min) / step;
2561
+ if (Math.abs(rem - Math.round(rem)) > 1e-6) {
2562
+ ctx.addIssue({
2563
+ code: z.ZodIssueCode.custom,
2564
+ message: `scale_input "${l.id}" defaultValue must align with min and step`,
2565
+ path: ["screens", screenIdx]
2566
+ });
2567
+ }
2568
+ }
2569
+ }
2570
+ }
2571
+ });
2572
+ if (screen.animations) {
2573
+ const clipIds = /* @__PURE__ */ new Set();
2574
+ for (const clip of screen.animations) {
2575
+ if (clipIds.has(clip.id)) {
2576
+ ctx.addIssue({
2577
+ code: z.ZodIssueCode.custom,
2578
+ message: `screen "${screen.id}" has duplicate clip id "${clip.id}"`,
2579
+ path: ["screens", screenIdx, "animations"]
2580
+ });
2581
+ }
2582
+ clipIds.add(clip.id);
2583
+ if (!layerIdsForScreen.has(clip.targetLayerId)) {
2584
+ ctx.addIssue({
2585
+ code: z.ZodIssueCode.custom,
2586
+ message: `clip "${clip.id}" targets layer "${clip.targetLayerId}" not on screen "${screen.id}"`,
2587
+ path: ["screens", screenIdx, "animations"]
2588
+ });
2589
+ }
2590
+ }
2591
+ }
2592
+ });
2593
+ };
2594
+
2595
+ // src/manifest/refineFlowManifest.ts
2596
+ var refineFlowManifest = (manifest, ctx) => {
2597
+ const jumpTargets = buildManifestJumpTargets(manifest);
2598
+ const { screenIds } = refineManifestGraph(manifest, ctx, jumpTargets);
2599
+ const allFieldKeys = /* @__PURE__ */ new Map();
2600
+ refineManifestScreens(manifest, ctx, jumpTargets, screenIds, allFieldKeys);
2601
+ manifest.decisionNodes.forEach((dn, di) => {
2602
+ for (const fk of collectDecisionFieldKeysFromNode(dn)) {
2603
+ if (!allFieldKeys.has(fk)) {
2604
+ ctx.addIssue({
2605
+ code: z.ZodIssueCode.custom,
2606
+ message: `decision "${dn.id}" references unknown fieldKey "${fk}"`,
2607
+ path: ["decisionNodes", di, "cases"]
2608
+ });
2609
+ }
2610
+ }
2611
+ });
2612
+ if (manifest.locales.length > 0 && !manifest.locales.includes(manifest.defaultLocale)) {
2613
+ ctx.addIssue({
2614
+ code: z.ZodIssueCode.custom,
2615
+ message: `defaultLocale "${manifest.defaultLocale}" must be in locales`,
2616
+ path: ["defaultLocale"]
2617
+ });
2618
+ }
2619
+ };
2620
+
2621
+ // src/manifest/flowManifestSchema.ts
2622
+ var FlowManifestObjectSchema = FlowManifestObjectBaseSchema.superRefine(refineFlowManifest);
2623
+ var FlowManifestSchema = FlowManifestObjectSchema;
2624
+ var SdkIdentitySchema = z.object({
2625
+ appUserId: z.string().min(1),
2626
+ customUserId: z.string().min(1).optional(),
2627
+ sessionId: z.string().min(1).optional()
2628
+ });
2629
+ var SdkContextSchema = z.object({
2630
+ platform: z.enum(["ios", "android", "web"]).optional(),
2631
+ appVersion: z.string().optional(),
2632
+ locale: z.string().optional(),
2633
+ customProperties: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional()
2634
+ });
2635
+ var DEFAULT_REVENUECAT = {
2636
+ enabled: false,
2637
+ defaultOfferingId: "",
2638
+ defaultPlacementId: ""
2639
+ };
2640
+ var DEFAULT_APPSFLYER = {
2641
+ enabled: false
2642
+ };
2643
+ var DEFAULT_INTEGRATIONS = {
2644
+ revenuecat: DEFAULT_REVENUECAT,
2645
+ appsflyer: DEFAULT_APPSFLYER
2646
+ };
2647
+ var parseAppIntegrations = (raw) => {
2648
+ const parsed = AppIntegrationsSchema.safeParse(raw);
2649
+ if (!parsed.success) return DEFAULT_INTEGRATIONS;
2650
+ return {
2651
+ revenuecat: { ...DEFAULT_REVENUECAT, ...parsed.data.revenuecat },
2652
+ appsflyer: { ...DEFAULT_APPSFLYER, ...parsed.data.appsflyer }
2653
+ };
2654
+ };
2655
+ var APP_INTEGRATIONS_DEFAULTS = DEFAULT_INTEGRATIONS;
2656
+ var RevenueCatIntegrationSchema = z.object({
2657
+ enabled: z.boolean(),
2658
+ defaultOfferingId: z.string(),
2659
+ defaultPlacementId: z.string()
2660
+ });
2661
+ var AppsFlyerIntegrationSchema = z.object({
2662
+ enabled: z.boolean()
2663
+ });
2664
+ var ResolvedAppIntegrationsSchema = z.object({
2665
+ revenuecat: RevenueCatIntegrationSchema,
2666
+ appsflyer: AppsFlyerIntegrationSchema
2667
+ });
2668
+ var AppIntegrationsSchema = z.object({
2669
+ revenuecat: RevenueCatIntegrationSchema.partial().optional(),
2670
+ appsflyer: AppsFlyerIntegrationSchema.partial().optional()
2671
+ }).passthrough();
2672
+ var DASHBOARD_ATTRIBUTION_INTEGRATION_PROVIDER_IDS = ["appsflyer"];
2673
+ var DashboardAttributionIntegrationProviderIdSchema = z.enum(
2674
+ DASHBOARD_ATTRIBUTION_INTEGRATION_PROVIDER_IDS
2675
+ );
2676
+ var AttributionProviderSignalQuerySchema = z.object({
2677
+ provider: DashboardAttributionIntegrationProviderIdSchema
2678
+ });
2679
+ var AttributionProviderSignalResponseSchema = z.object({
2680
+ provider: z.string(),
2681
+ signalDetected: z.boolean(),
2682
+ /** `false` when ClickHouse was unavailable or the query failed — treat as inconclusive. */
2683
+ checked: z.boolean(),
2684
+ matchCount: z.number().int().nonnegative(),
2685
+ /** ISO-8601 from ClickHouse `max(timestamp)`, or null when there are no matches. */
2686
+ lastSeenAt: z.string().nullable()
2687
+ });
2688
+ var CANVAS_EDITOR_GATE_KEYS = [
2689
+ "lottie",
2690
+ "oauthLogin",
2691
+ "oauthProviderPreset",
2692
+ "oauthProviderCustom",
2693
+ "emailPasswordAuth",
2694
+ "emailPasswordField",
2695
+ "emailPasswordSubmit",
2696
+ "requestOsPermission"
2697
+ ];
2698
+ var CanvasEditorGatesResolvedSchema = z.object({
2699
+ lottie: z.boolean(),
2700
+ oauthLogin: z.boolean(),
2701
+ oauthProviderPreset: z.boolean(),
2702
+ oauthProviderCustom: z.boolean(),
2703
+ emailPasswordAuth: z.boolean(),
2704
+ emailPasswordField: z.boolean(),
2705
+ emailPasswordSubmit: z.boolean(),
2706
+ requestOsPermission: z.boolean()
2707
+ });
2708
+ var ALL_TRUE = {
2709
+ lottie: true,
2710
+ oauthLogin: true,
2711
+ oauthProviderPreset: true,
2712
+ oauthProviderCustom: true,
2713
+ emailPasswordAuth: true,
2714
+ emailPasswordField: true,
2715
+ emailPasswordSubmit: true,
2716
+ requestOsPermission: true
2717
+ };
2718
+ var CanvasEditorGatesPatchSchema = z.object({
2719
+ lottie: z.boolean().optional(),
2720
+ oauthLogin: z.boolean().optional(),
2721
+ oauthProviderPreset: z.boolean().optional(),
2722
+ oauthProviderCustom: z.boolean().optional(),
2723
+ emailPasswordAuth: z.boolean().optional(),
2724
+ emailPasswordField: z.boolean().optional(),
2725
+ emailPasswordSubmit: z.boolean().optional(),
2726
+ requestOsPermission: z.boolean().optional()
2727
+ }).strict();
2728
+ var parseCanvasEditorGates = (raw) => {
2729
+ if (raw == null) return { ...ALL_TRUE };
2730
+ const parsed = CanvasEditorGatesPatchSchema.safeParse(raw);
2731
+ if (!parsed.success) return { ...ALL_TRUE };
2732
+ return { ...ALL_TRUE, ...parsed.data };
2733
+ };
2734
+ var layerViolationMessage = (screenId, layerId, label2) => `Screen "${screenId}": ${label2} (layer "${layerId}") is disabled for this app in canvas editor settings.`;
2735
+ var buttonOsPermissionMessage = (screenId, layerId) => `Screen "${screenId}": request OS permission button actions are disabled for this app (layer "${layerId}").`;
2736
+ var collectCanvasGateViolations = (manifest, gates) => {
2737
+ const issues = [];
2738
+ for (const screen of manifest.screens) {
2739
+ walkScreenLayers(screen, (l) => {
2740
+ if ((l.kind === "lottie" || l.kind === "video") && !gates.lottie) {
2741
+ issues.push(
2742
+ layerViolationMessage(
2743
+ screen.id,
2744
+ l.id,
2745
+ l.kind === "video" ? "Video layers" : "Lottie layers"
2746
+ )
2747
+ );
2748
+ }
2749
+ if (l.kind === "oauth_login" && !gates.oauthLogin) {
2750
+ issues.push(layerViolationMessage(screen.id, l.id, "OAuth login layers"));
2751
+ }
2752
+ if (l.kind === "oauth_provider") {
2753
+ if (l.variant === "preset" && !gates.oauthProviderPreset) {
2754
+ issues.push(layerViolationMessage(screen.id, l.id, "OAuth provider (preset) layers"));
2755
+ }
2756
+ if (l.variant === "custom" && !gates.oauthProviderCustom) {
2757
+ issues.push(layerViolationMessage(screen.id, l.id, "OAuth provider (custom) layers"));
2758
+ }
2759
+ }
2760
+ if (l.kind === "email_password_auth" && !gates.emailPasswordAuth) {
2761
+ issues.push(layerViolationMessage(screen.id, l.id, "Email/password auth layers"));
2762
+ }
2763
+ if (l.kind === "email_password_field" && !gates.emailPasswordField) {
2764
+ issues.push(layerViolationMessage(screen.id, l.id, "Email/password field layers"));
2765
+ }
2766
+ if (l.kind === "email_password_submit" && !gates.emailPasswordSubmit) {
2767
+ issues.push(layerViolationMessage(screen.id, l.id, "Email/password submit layers"));
2768
+ }
2769
+ if (l.kind === "button" && l.action.kind === "request_os_permission" && !gates.requestOsPermission) {
2770
+ issues.push(buttonOsPermissionMessage(screen.id, l.id));
2771
+ }
2772
+ });
2773
+ }
2774
+ return issues;
2775
+ };
2776
+ var manifestPassesCanvasGates = (manifest, gates) => collectCanvasGateViolations(manifest, gates).length === 0;
2777
+ var describeCanvasGatesForAi = (gates) => {
2778
+ const disabled = [];
2779
+ if (!gates.lottie) disabled.push("do not use lottie or video layers");
2780
+ if (!gates.oauthLogin) disabled.push("do not use oauth_login layers");
2781
+ if (!gates.oauthProviderPreset) disabled.push("do not use oauth_provider with variant preset");
2782
+ if (!gates.oauthProviderCustom) disabled.push("do not use oauth_provider with variant custom");
2783
+ if (!gates.emailPasswordAuth) disabled.push("do not use email_password_auth layers");
2784
+ if (!gates.emailPasswordField) disabled.push("do not use email_password_field layers");
2785
+ if (!gates.emailPasswordSubmit) disabled.push("do not use email_password_submit layers");
2786
+ if (!gates.requestOsPermission) disabled.push("do not use button actions with kind request_os_permission");
2787
+ if (disabled.length === 0) {
2788
+ return "Canvas editor: all advanced layer types and OS permission button actions are allowed.";
2789
+ }
2790
+ return `Canvas editor restrictions for this app \u2014 ${disabled.join("; ")}.`;
2791
+ };
2792
+
2793
+ // src/dashboard/appBranding.ts
2794
+ var HEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
2795
+ var BrandColorSchema = z.object({
2796
+ id: z.string().uuid(),
2797
+ name: z.string().min(1).max(50),
2798
+ /** Hex color, e.g. `#0F172A`. Alpha (8 chars) supported. */
2799
+ value: z.string().regex(HEX, "must be a hex color (#RRGGBB or #RRGGBBAA)")
2800
+ });
2801
+ var BrandGradientStopSchema = z.object({
2802
+ /** 0..1 position along the gradient. */
2803
+ offset: z.number().min(0).max(1),
2804
+ color: z.string().regex(HEX)
2805
+ });
2806
+ var BrandGradientSchema = z.object({
2807
+ id: z.string().uuid(),
2808
+ name: z.string().min(1).max(50),
2809
+ type: z.enum(["linear", "radial"]),
2810
+ /** Degrees, used when type === 'linear'. 0 = top → bottom (CSS convention). */
2811
+ angle: z.number().min(0).max(360).optional(),
2812
+ stops: z.array(BrandGradientStopSchema).min(2)
2813
+ });
2814
+ var FontStyleSchema = z.object({
2815
+ id: z.string().uuid(),
2816
+ /** Numeric CSS font-weight, e.g. 100..900. */
2817
+ weight: z.number().int().min(100).max(900),
2818
+ italic: z.boolean(),
2819
+ /** Optional human label (e.g. "Bold Italic"). */
2820
+ label: z.string().max(40).optional(),
2821
+ /** MediaAsset id of the uploaded font file. */
2822
+ mediaAssetId: z.string().uuid().optional(),
2823
+ /** Public URL of the uploaded font file (denormalized for SDK consumption). */
2824
+ url: z.string().url().optional(),
2825
+ /** Original filename — useful for display. */
2826
+ filename: z.string().max(200).optional()
2827
+ });
2828
+ var FontFamilySchema = z.object({
2829
+ id: z.string().uuid(),
2830
+ name: z.string().min(1).max(60),
2831
+ styles: z.array(FontStyleSchema)
2832
+ });
2833
+ var AppIconSchema = z.object({
2834
+ url: z.string().url(),
2835
+ source: z.enum(["app_store", "play_store", "upload"])
2836
+ });
2837
+ var BrandingSchema = z.object({
2838
+ /** Optional store / marketing icon for this app (shown in dashboard). */
2839
+ appIcon: AppIconSchema.optional(),
2840
+ colorPresets: z.array(BrandColorSchema),
2841
+ gradientPresets: z.array(BrandGradientSchema),
2842
+ fontFamilies: z.array(FontFamilySchema)
2843
+ });
2844
+ var EMPTY_BRANDING = {
2845
+ colorPresets: [],
2846
+ gradientPresets: [],
2847
+ fontFamilies: []
2848
+ };
2849
+ var StoreListingInputSchema = z.object({
2850
+ platform: z.enum(["ios", "android"]),
2851
+ applicationId: z.string().trim().min(1).max(200)
2852
+ });
2853
+ var StoreListingLookupResponseSchema = z.object({
2854
+ found: z.boolean(),
2855
+ platform: z.enum(["ios", "android"]),
2856
+ applicationId: z.string(),
2857
+ name: z.string().optional(),
2858
+ iconUrl: z.string().url().optional()
2859
+ });
2860
+ var AppSchema = z.object({
2861
+ id: z.string().uuid(),
2862
+ orgId: z.string().uuid(),
2863
+ name: z.string().min(1).max(100),
2864
+ branding: BrandingSchema.optional(),
2865
+ /** Resolved flags; all true when unset in storage. */
2866
+ canvasEditorGates: CanvasEditorGatesResolvedSchema,
2867
+ /** Resolved per-provider integration toggles + settings. */
2868
+ integrations: ResolvedAppIntegrationsSchema,
2869
+ archivedAt: z.string().datetime().nullable().optional(),
2870
+ createdAt: z.string().datetime()
2871
+ });
2872
+ var CreateAppRequestSchema = z.object({
2873
+ name: z.string().min(1).max(100),
2874
+ /** When set, the server resolves artwork from the store after the app row exists. */
2875
+ storeListing: StoreListingInputSchema.optional()
2876
+ });
2877
+ var UpdateAppRequestSchema = z.object({
2878
+ name: z.string().min(1).max(100).optional(),
2879
+ /** Full replace for the JSON column when set; omit to leave unchanged. */
2880
+ canvasEditorGates: CanvasEditorGatesResolvedSchema.optional(),
2881
+ /** Per-provider integration toggles + settings. Full replace semantics when set. */
2882
+ integrations: AppIntegrationsSchema.optional()
2883
+ });
2884
+ var UpdateAppBrandingRequestSchema = z.object({
2885
+ branding: BrandingSchema
2886
+ });
2887
+ var DeleteAppRequestSchema = z.object({
2888
+ /** User must type the app's exact name to confirm destructive deletion. */
2889
+ confirmName: z.string().min(1)
2890
+ });
2891
+ var DeleteAppResponseSchema = z.object({
2892
+ mode: z.enum(["hard", "soft"]),
2893
+ reason: z.enum(["has_events", "clickhouse_unavailable"]).optional()
2894
+ });
2895
+ var PublishableKeySchema = z.object({
2896
+ id: z.string().uuid(),
2897
+ environment: z.enum(ENVIRONMENTS),
2898
+ /**
2899
+ * Full publishable key. Always returned to dashboard users since publishable
2900
+ * keys are non-secret and meant to ship in mobile clients.
2901
+ */
2902
+ plaintext: z.string(),
2903
+ prefix: z.string(),
2904
+ lastFour: z.string(),
2905
+ revokedAt: z.string().datetime().nullable().optional(),
2906
+ createdAt: z.string().datetime()
2907
+ });
2908
+ var CreateAppResponseSchema = z.object({
2909
+ app: AppSchema,
2910
+ keys: z.array(PublishableKeySchema)
2911
+ });
2912
+ var DASHBOARD_MAX_TAGS = 20;
2913
+ var DASHBOARD_MAX_TAG_LEN = 64;
2914
+ var normalizeDashboardTags = (raw) => {
2915
+ const out = [];
2916
+ const seen = /* @__PURE__ */ new Set();
2917
+ for (const s of raw) {
2918
+ const t = s.trim().toLowerCase();
2919
+ if (t.length === 0 || t.length > DASHBOARD_MAX_TAG_LEN) continue;
2920
+ if (seen.has(t)) continue;
2921
+ seen.add(t);
2922
+ out.push(t);
2923
+ if (out.length >= DASHBOARD_MAX_TAGS) break;
2924
+ }
2925
+ return out;
2926
+ };
2927
+ var TagsSchema = z.array(z.string()).max(DASHBOARD_MAX_TAGS).superRefine((arr, ctx) => {
2928
+ arr.forEach((s, i) => {
2929
+ const t = s.trim().toLowerCase();
2930
+ if (t.length > DASHBOARD_MAX_TAG_LEN) {
2931
+ ctx.addIssue({
2932
+ code: z.ZodIssueCode.custom,
2933
+ message: `Tag exceeds ${DASHBOARD_MAX_TAG_LEN} characters`,
2934
+ path: [i]
2935
+ });
2936
+ }
2937
+ });
2938
+ }).transform((arr) => normalizeDashboardTags(arr));
2939
+ var TagsSchemaOptional = TagsSchema.optional();
2940
+ var FLOW_TEMPLATE_IDS = [
2941
+ "stories",
2942
+ "language_learning",
2943
+ "fitness",
2944
+ "win_back",
2945
+ "feedback",
2946
+ "word_learning",
2947
+ "journal_onboarding"
2948
+ ];
2949
+ var FlowTemplateIdSchema = z.enum(FLOW_TEMPLATE_IDS);
2950
+ var FLOW_TEMPLATE_CATEGORIES = ["engagement", "onboarding"];
2951
+ var FLOW_TEMPLATE_CATEGORY_LABELS = {
2952
+ engagement: "Engagement",
2953
+ onboarding: "Onboarding"
2954
+ };
2955
+ var FLOW_TEMPLATE_CATALOG = [
2956
+ {
2957
+ id: "stories",
2958
+ title: "Stories",
2959
+ description: "Full-screen video segments with progress bars and tap-to-advance.",
2960
+ icon: "circle-play",
2961
+ category: "engagement"
2962
+ },
2963
+ {
2964
+ id: "language_learning",
2965
+ title: "Language learning",
2966
+ description: "Duolingo-style onboarding: language pick, daily goal, name, and profile setup with progress bars.",
2967
+ icon: "languages",
2968
+ category: "onboarding"
2969
+ },
2970
+ {
2971
+ id: "fitness",
2972
+ title: "Fitness & health",
2973
+ description: "Fitness & health onboarding: Apple Health connect, strain/recovery/sleep education, and personalization quiz.",
2974
+ icon: "activity",
2975
+ category: "onboarding"
2976
+ },
2977
+ {
2978
+ id: "win_back",
2979
+ title: "Win-back",
2980
+ description: "Churn flow: retention, cancel survey, discount offer, and confirmation (5 screens).",
2981
+ icon: "gift",
2982
+ category: "engagement"
2983
+ },
2984
+ {
2985
+ id: "feedback",
2986
+ title: "Feedback",
2987
+ description: "In-app survey: satisfaction scale, topic picker, open feedback, and NPS \u2014 inspired by Craft and TextNow.",
2988
+ icon: "message-square",
2989
+ category: "engagement"
2990
+ },
2991
+ {
2992
+ id: "word_learning",
2993
+ title: "Word learning",
2994
+ description: "Word-learning onboarding: personalization quiz, notifications, themes, goals, and topics (15 screens).",
2995
+ icon: "book-open",
2996
+ category: "onboarding"
2997
+ },
2998
+ {
2999
+ id: "journal_onboarding",
3000
+ title: "Journal onboarding",
3001
+ description: "Journaly onboarding: self-discovery, name quiz, goals, privacy, journey cards, and attribution (8 screens).",
3002
+ icon: "notebook-pen",
3003
+ category: "onboarding"
3004
+ }
3005
+ ];
3006
+
3007
+ // src/dashboard/flows.ts
3008
+ var FlowStatusSchema = z.enum(["draft", "published_test", "published_live"]);
3009
+ var FlowPreviewSchema = z.object({
3010
+ nodes: z.array(
3011
+ z.object({
3012
+ id: z.string(),
3013
+ x: z.number(),
3014
+ y: z.number(),
3015
+ isEntry: z.boolean().optional()
3016
+ })
3017
+ ),
3018
+ edges: z.array(
3019
+ z.object({
3020
+ source: z.string(),
3021
+ target: z.string(),
3022
+ branching: z.boolean().optional()
3023
+ })
3024
+ )
3025
+ });
3026
+ var FlowSummarySchema = z.object({
3027
+ id: z.string().uuid(),
3028
+ appId: z.string().uuid(),
3029
+ name: z.string().min(1),
3030
+ status: FlowStatusSchema,
3031
+ archivedAt: z.string().datetime().nullable().optional(),
3032
+ updatedAt: z.string().datetime(),
3033
+ createdAt: z.string().datetime(),
3034
+ /** Dashboard user who created the flow (null for legacy rows). */
3035
+ createdByUserId: z.string().uuid().nullable().optional(),
3036
+ /** Number of published immutable versions (each publish appends one). */
3037
+ versionCount: z.number().int().nonnegative(),
3038
+ screenCount: z.number().int().nonnegative().optional(),
3039
+ preview: FlowPreviewSchema.optional(),
3040
+ tags: z.array(z.string())
3041
+ });
3042
+ var CREATE_FLOW_AI_PROMPT_MAX = 8e3;
3043
+ var AiFlowPromptSchema = z.string().trim().min(1).max(CREATE_FLOW_AI_PROMPT_MAX);
3044
+ var CreateFlowRequestSchema = z.object({
3045
+ name: z.string().min(1).max(100),
3046
+ tags: TagsSchemaOptional,
3047
+ /** When set, seeds the draft with a multi-screen onboarding manifest. Omit for a blank flow. */
3048
+ flowTemplateId: FlowTemplateIdSchema.optional(),
3049
+ /** When set, starts multi-step AI expansion after seeding a blank manifest. Mutually exclusive with `flowTemplateId`. */
3050
+ aiPrompt: AiFlowPromptSchema.optional(),
3051
+ /** Imported manifest JSON from the rheo skill flow-import workflow. Mutually exclusive with template and AI generation. */
3052
+ importManifest: z.unknown().optional()
3053
+ }).superRefine((data, ctx) => {
3054
+ const selected = [data.flowTemplateId, data.aiPrompt, data.importManifest].filter(
3055
+ (v) => v !== void 0
3056
+ );
3057
+ if (selected.length > 1) {
3058
+ ctx.addIssue({
3059
+ code: z.ZodIssueCode.custom,
3060
+ message: "Pick only one start mode: catalog template, Generate with AI, or Import manifest.",
3061
+ path: ["importManifest"]
3062
+ });
3063
+ }
3064
+ });
3065
+ var FlowAiGenerationRunStatusSchema = z.enum([
3066
+ "queued",
3067
+ "running",
3068
+ "completed",
3069
+ "failed"
3070
+ ]);
3071
+ var FlowAiGenerationRunStatusResponseSchema = z.object({
3072
+ id: z.string().uuid(),
3073
+ flowId: z.string().uuid(),
3074
+ status: FlowAiGenerationRunStatusSchema,
3075
+ stepIndex: z.number().int().nonnegative(),
3076
+ lastError: z.string().nullable().optional()
3077
+ });
3078
+ var StartAiFlowGenerationRequestSchema = z.object({
3079
+ aiPrompt: AiFlowPromptSchema
3080
+ });
3081
+ var RHEO_AGENT_IMAGE_MIME_TYPES = ["image/png", "image/jpeg", "image/webp"];
3082
+ var RHEO_AGENT_MAX_IMAGE_ATTACHMENTS = 4;
3083
+ var estimateBase64DecodedBytes = (dataBase64) => {
3084
+ const len = dataBase64.length;
3085
+ const padding = dataBase64.endsWith("==") ? 2 : dataBase64.endsWith("=") ? 1 : 0;
3086
+ return Math.max(0, Math.floor(len * 3 / 4) - padding);
3087
+ };
3088
+ var RheoAgentImageAttachmentSchema = z.object({
3089
+ mimeType: z.enum(RHEO_AGENT_IMAGE_MIME_TYPES),
3090
+ dataBase64: z.string().min(1)
3091
+ }).superRefine((attachment, ctx) => {
3092
+ const bytes = estimateBase64DecodedBytes(attachment.dataBase64);
3093
+ if (bytes > MAX_IMAGE_BYTES) {
3094
+ ctx.addIssue({
3095
+ code: z.ZodIssueCode.custom,
3096
+ message: "Image exceeds 5 MB limit"
3097
+ });
3098
+ }
3099
+ });
3100
+ var RheoAgentMessageSchema = z.object({
3101
+ role: z.enum(["user", "assistant"]),
3102
+ content: z.string(),
3103
+ attachments: z.array(RheoAgentImageAttachmentSchema).max(RHEO_AGENT_MAX_IMAGE_ATTACHMENTS).optional()
3104
+ }).superRefine((message, ctx) => {
3105
+ if (message.role === "assistant" && message.attachments?.length) {
3106
+ ctx.addIssue({
3107
+ code: z.ZodIssueCode.custom,
3108
+ message: "Assistant messages cannot include attachments"
3109
+ });
3110
+ }
3111
+ if (message.role === "user" && !message.content.trim() && !(message.attachments && message.attachments.length > 0)) {
3112
+ ctx.addIssue({
3113
+ code: z.ZodIssueCode.custom,
3114
+ message: "User message must include text or at least one image"
3115
+ });
3116
+ }
3117
+ });
3118
+ var RheoAgentSelectionSchema = z.object({
3119
+ screenId: z.string().optional(),
3120
+ screenIds: z.array(z.string()).min(1).optional(),
3121
+ layerId: z.string().optional(),
3122
+ decisionId: z.string().optional(),
3123
+ decisionIds: z.array(z.string()).min(1).optional(),
3124
+ externalSurfaceId: z.string().optional()
3125
+ }).optional();
3126
+ var RheoAgentChatRequestSchema = z.object({
3127
+ messages: z.array(RheoAgentMessageSchema).min(1),
3128
+ selection: RheoAgentSelectionSchema
3129
+ });
3130
+ var RheoAgentTextDeltaEventSchema = z.object({
3131
+ type: z.literal("text-delta"),
3132
+ delta: z.string()
3133
+ });
3134
+ var RheoAgentApplyingManifestEventSchema = z.object({
3135
+ type: z.literal("applying-manifest")
3136
+ });
3137
+ var RheoAgentManifestEventSchema = z.object({
3138
+ type: z.literal("manifest"),
3139
+ manifest: FlowManifestSchema
3140
+ });
3141
+ var RheoAgentErrorEventSchema = z.object({
3142
+ type: z.literal("error"),
3143
+ message: z.string()
3144
+ });
3145
+ var RheoAgentDoneEventSchema = z.object({
3146
+ type: z.literal("done"),
3147
+ ok: z.boolean()
3148
+ });
3149
+ var RheoAgentAttemptEventSchema = z.object({
3150
+ type: z.literal("attempt"),
3151
+ /** 1-based attempt index shown in the builder debug UI. */
3152
+ attempt: z.number().int().min(1),
3153
+ maxAttempts: z.number().int().min(1),
3154
+ phase: z.enum(["stream", "repair"])
3155
+ });
3156
+ var RheoAgentStreamEventSchema = z.discriminatedUnion("type", [
3157
+ RheoAgentTextDeltaEventSchema,
3158
+ RheoAgentApplyingManifestEventSchema,
3159
+ RheoAgentManifestEventSchema,
3160
+ RheoAgentErrorEventSchema,
3161
+ RheoAgentDoneEventSchema,
3162
+ RheoAgentAttemptEventSchema
3163
+ ]);
3164
+ var CreateFlowResponseSchema = z.object({
3165
+ flow: FlowSummarySchema,
3166
+ /** Present when `CreateFlowRequest` included `aiPrompt`. */
3167
+ generationRunId: z.string().uuid().optional()
3168
+ });
3169
+ var UpdateFlowRequestSchema = z.object({
3170
+ name: z.string().min(1).max(100).optional(),
3171
+ tags: TagsSchema.optional()
3172
+ }).refine((o) => o.name !== void 0 || o.tags !== void 0, {
3173
+ message: "Provide at least one of name or tags"
3174
+ });
3175
+ var DuplicateFlowRequestSchema = z.object({
3176
+ name: z.string().min(1).max(100).optional(),
3177
+ targetAppId: z.string().uuid().optional()
3178
+ });
3179
+ var FlowDraftSchema = z.object({
3180
+ flowId: z.string().uuid(),
3181
+ name: z.string().min(1),
3182
+ tags: z.array(z.string()),
3183
+ manifest: FlowManifestSchema,
3184
+ autosaveVersion: z.number().int().nonnegative(),
3185
+ updatedAt: z.string().datetime()
3186
+ });
3187
+ var AutosaveDraftRequestSchema = z.object({
3188
+ manifest: FlowManifestSchema,
3189
+ autosaveVersion: z.number().int().nonnegative()
3190
+ });
3191
+ var AutosaveDraftResponseSchema = z.object({
3192
+ flowId: z.string().uuid(),
3193
+ autosaveVersion: z.number().int().nonnegative(),
3194
+ updatedAt: z.string().datetime()
3195
+ });
3196
+ var PublishRequestSchema = z.object({
3197
+ label: z.string().trim().max(120).optional()
3198
+ });
3199
+ var PublishValidationErrorSchema = z.object({
3200
+ stepId: z.string().nullable().optional(),
3201
+ path: z.array(z.union([z.string(), z.number()])).optional(),
3202
+ message: z.string(),
3203
+ code: z.string()
3204
+ });
3205
+ var FlowVersionSchema = z.object({
3206
+ id: z.string().uuid(),
3207
+ flowId: z.string().uuid(),
3208
+ versionNumber: z.number().int().positive(),
3209
+ label: z.string().nullable().optional(),
3210
+ createdAt: z.string().datetime(),
3211
+ publishedByUserId: z.string().uuid().nullable().optional()
3212
+ });
3213
+ var FlowVersionWithManifestSchema = FlowVersionSchema.extend({
3214
+ manifest: FlowManifestSchema
3215
+ });
3216
+ var PublishResponseSchema = z.object({
3217
+ version: FlowVersionSchema
3218
+ });
3219
+ var ListVersionsResponseSchema = z.object({
3220
+ items: z.array(FlowVersionSchema)
3221
+ });
3222
+ var ChannelAssignmentKindSchema = z.enum(["direct", "experiment"]);
3223
+ var ChannelDirectAssignmentSchema = z.object({
3224
+ kind: z.literal("direct"),
3225
+ flowId: z.string().uuid(),
3226
+ versionId: z.string().uuid()
3227
+ });
3228
+ var ChannelExperimentAssignmentSchema = z.object({
3229
+ kind: z.literal("experiment"),
3230
+ experimentId: z.string().uuid()
3231
+ });
3232
+ var ChannelAssignmentRequestSchema = z.discriminatedUnion("kind", [
3233
+ ChannelDirectAssignmentSchema,
3234
+ ChannelExperimentAssignmentSchema
3235
+ ]);
3236
+ var ChannelSchema = z.object({
3237
+ id: z.string().uuid(),
3238
+ publicId: z.string(),
3239
+ appId: z.string().uuid(),
3240
+ environment: z.enum(ENVIRONMENTS),
3241
+ name: z.string(),
3242
+ archivedAt: z.string().datetime().nullable(),
3243
+ createdAt: z.string().datetime(),
3244
+ assignmentKind: ChannelAssignmentKindSchema.nullable(),
3245
+ assignmentVersion: z.number().int().nonnegative(),
3246
+ assignmentUpdatedAt: z.string().datetime().nullable(),
3247
+ pinned: z.object({
3248
+ flowId: z.string().uuid(),
3249
+ flowName: z.string(),
3250
+ versionId: z.string().uuid(),
3251
+ versionNumber: z.number().int().positive(),
3252
+ versionLabel: z.string().nullable().optional()
3253
+ }).nullable(),
3254
+ experimentId: z.string().uuid().nullable()
3255
+ });
3256
+ var ListChannelsResponseSchema = z.object({
3257
+ items: z.array(ChannelSchema)
3258
+ });
3259
+ var CreateChannelRequestSchema = z.object({
3260
+ name: z.string().min(1).max(64),
3261
+ environment: z.enum(ENVIRONMENTS)
3262
+ });
3263
+ var RenameChannelRequestSchema = z.object({
3264
+ name: z.string().min(1).max(64)
3265
+ });
3266
+ var ArchiveChannelRequestSchema = z.object({
3267
+ confirmName: z.string().min(1)
3268
+ });
3269
+ var UnarchiveChannelResponseSchema = z.object({
3270
+ channel: ChannelSchema,
3271
+ restored: z.boolean(),
3272
+ restoreWarning: z.string().nullable()
3273
+ });
3274
+ var ChannelEventTypeSchema = z.enum([
3275
+ "channel_created",
3276
+ "channel_renamed",
3277
+ "channel_archived",
3278
+ "channel_unarchived",
3279
+ "direct_pinned",
3280
+ "experiment_assigned",
3281
+ "assignment_cleared",
3282
+ "experiment_stopped_repinned",
3283
+ "experiment_winner_promoted",
3284
+ "rollout_requested",
3285
+ "rollout_rejected",
3286
+ "rollout_cancelled"
3287
+ ]);
3288
+ var ChannelHistoryFlowVersionSnapshotSchema = z.object({
3289
+ flowId: z.string().uuid(),
3290
+ flowName: z.string(),
3291
+ versionId: z.string().uuid(),
3292
+ versionNumber: z.number().int().positive(),
3293
+ versionLabel: z.string().nullable().optional()
3294
+ });
3295
+ var ChannelHistoryExperimentSnapshotSchema = z.object({
3296
+ experimentId: z.string().uuid(),
3297
+ experimentName: z.string(),
3298
+ variantCount: z.number().int().nonnegative().optional()
3299
+ });
3300
+ var ChannelHistoryPreviousAssignmentSchema = z.object({
3301
+ kind: z.enum(["direct", "experiment"]).nullable(),
3302
+ pinned: ChannelHistoryFlowVersionSnapshotSchema.nullable().optional(),
3303
+ experiment: ChannelHistoryExperimentSnapshotSchema.nullable().optional()
3304
+ });
3305
+ var ChannelCreatedPayloadSchema = z.object({
3306
+ type: z.literal("channel_created"),
3307
+ environment: z.enum(ENVIRONMENTS),
3308
+ name: z.string()
3309
+ });
3310
+ var ChannelRenamedPayloadSchema = z.object({
3311
+ type: z.literal("channel_renamed"),
3312
+ previousName: z.string(),
3313
+ newName: z.string()
3314
+ });
3315
+ var ChannelArchivedPayloadSchema = z.object({
3316
+ type: z.literal("channel_archived"),
3317
+ name: z.string()
3318
+ });
3319
+ var ChannelUnarchivedPayloadSchema = z.object({
3320
+ type: z.literal("channel_unarchived"),
3321
+ assignmentRestored: z.boolean(),
3322
+ restoreWarning: z.string().nullable(),
3323
+ assignmentCleared: z.boolean().optional()
3324
+ });
3325
+ var DirectPinnedPayloadSchema = z.object({
3326
+ type: z.literal("direct_pinned"),
3327
+ flowId: z.string().uuid(),
3328
+ flowName: z.string(),
3329
+ versionId: z.string().uuid(),
3330
+ versionNumber: z.number().int().positive(),
3331
+ versionLabel: z.string().nullable().optional(),
3332
+ source: z.enum(["direct", "rollout"]),
3333
+ rolloutRequestId: z.string().uuid().optional(),
3334
+ previous: ChannelHistoryPreviousAssignmentSchema.optional()
3335
+ });
3336
+ var ExperimentAssignedPayloadSchema = z.object({
3337
+ type: z.literal("experiment_assigned"),
3338
+ experimentId: z.string().uuid(),
3339
+ experimentName: z.string(),
3340
+ variantCount: z.number().int().nonnegative(),
3341
+ previous: ChannelHistoryPreviousAssignmentSchema.optional()
3342
+ });
3343
+ var AssignmentClearedPayloadSchema = z.object({
3344
+ type: z.literal("assignment_cleared"),
3345
+ previous: ChannelHistoryPreviousAssignmentSchema,
3346
+ reason: z.enum(["manual", "unarchive_restore_failed"]).optional()
3347
+ });
3348
+ var ExperimentStoppedRepinnedPayloadSchema = z.object({
3349
+ type: z.literal("experiment_stopped_repinned"),
3350
+ experimentId: z.string().uuid(),
3351
+ experimentName: z.string(),
3352
+ pinned: ChannelHistoryFlowVersionSnapshotSchema
3353
+ });
3354
+ var ExperimentWinnerPromotedPayloadSchema = z.object({
3355
+ type: z.literal("experiment_winner_promoted"),
3356
+ experimentId: z.string().uuid(),
3357
+ experimentName: z.string(),
3358
+ pinned: ChannelHistoryFlowVersionSnapshotSchema,
3359
+ wasPendingDecision: z.boolean()
3360
+ });
3361
+ var RolloutFlowPayloadSchema = z.object({
3362
+ type: z.enum(["rollout_requested", "rollout_rejected", "rollout_cancelled"]),
3363
+ rolloutRequestId: z.string().uuid(),
3364
+ flow: ChannelHistoryFlowVersionSnapshotSchema
3365
+ });
3366
+ var ChannelEventPayloadSchema = z.discriminatedUnion("type", [
3367
+ ChannelCreatedPayloadSchema,
3368
+ ChannelRenamedPayloadSchema,
3369
+ ChannelArchivedPayloadSchema,
3370
+ ChannelUnarchivedPayloadSchema,
3371
+ DirectPinnedPayloadSchema,
3372
+ ExperimentAssignedPayloadSchema,
3373
+ AssignmentClearedPayloadSchema,
3374
+ ExperimentStoppedRepinnedPayloadSchema,
3375
+ ExperimentWinnerPromotedPayloadSchema,
3376
+ RolloutFlowPayloadSchema
3377
+ ]);
3378
+ var ChannelEventSchema = z.object({
3379
+ id: z.string().uuid(),
3380
+ type: ChannelEventTypeSchema,
3381
+ actorUserId: z.string().uuid().nullable(),
3382
+ actorLabel: z.string().nullable(),
3383
+ occurredAt: z.string().datetime(),
3384
+ payload: z.record(z.unknown())
3385
+ });
3386
+ var ListChannelHistoryResponseSchema = z.object({
3387
+ items: z.array(ChannelEventSchema),
3388
+ total: z.number().int().nonnegative()
3389
+ });
3390
+ var RolloutRequestStatusSchema = z.enum([
3391
+ "pending",
3392
+ "approved",
3393
+ "rejected",
3394
+ "cancelled"
3395
+ ]);
3396
+ var RolloutCommentKindSchema = z.enum(["comment", "system"]);
3397
+ var CreateRolloutRequestsBodySchema = z.object({
3398
+ appId: z.string().uuid(),
3399
+ versionId: z.string().uuid(),
3400
+ channelIds: z.array(z.string().uuid()).min(1),
3401
+ /** PR-style summary: what changed, why, risk notes (first activity comment). */
3402
+ description: z.string().trim().min(1).max(8e3)
3403
+ });
3404
+ var RolloutPolicyResponseSchema = z.object({
3405
+ enabled: z.boolean(),
3406
+ environments: z.array(z.enum(ENVIRONMENTS)),
3407
+ approverUserIds: z.array(z.string().uuid())
3408
+ });
3409
+ var PatchRolloutPolicySchema = z.object({
3410
+ enabled: z.boolean(),
3411
+ environments: z.array(z.enum(ENVIRONMENTS)),
3412
+ approverUserIds: z.array(z.string().uuid())
3413
+ });
3414
+ var RolloutCommentMentionUserSchema = z.object({
3415
+ userId: z.string().uuid(),
3416
+ label: z.string()
3417
+ });
3418
+ var RolloutRequestCommentSchema = z.object({
3419
+ id: z.string().uuid(),
3420
+ authorUserId: z.string().uuid(),
3421
+ body: z.string(),
3422
+ kind: RolloutCommentKindSchema,
3423
+ createdAt: z.string().datetime(),
3424
+ mentions: z.array(RolloutCommentMentionUserSchema)
3425
+ });
3426
+ var RolloutRequestSummarySchema = z.object({
3427
+ id: z.string().uuid(),
3428
+ orgId: z.string().uuid(),
3429
+ channelId: z.string().uuid(),
3430
+ channelName: z.string(),
3431
+ channelPublicId: z.string(),
3432
+ channelEnvironment: z.enum(ENVIRONMENTS),
3433
+ appId: z.string().uuid(),
3434
+ appName: z.string(),
3435
+ flowId: z.string().uuid(),
3436
+ flowName: z.string(),
3437
+ flowVersionId: z.string().uuid(),
3438
+ versionNumber: z.number().int().positive(),
3439
+ versionLabel: z.string().nullable().optional(),
3440
+ requestedByUserId: z.string().uuid(),
3441
+ requestedByEmail: z.string(),
3442
+ /** Display: full name, else username, else email. */
3443
+ requestedByLabel: z.string(),
3444
+ status: RolloutRequestStatusSchema,
3445
+ decidedByUserId: z.string().uuid().nullable().optional(),
3446
+ decidedAt: z.string().datetime().nullable().optional(),
3447
+ createdAt: z.string().datetime()
3448
+ });
3449
+ var RolloutRequestDetailSchema = RolloutRequestSummarySchema.extend({
3450
+ comments: z.array(RolloutRequestCommentSchema)
3451
+ });
3452
+ var CreateRolloutRequestsResponseSchema = z.object({
3453
+ items: z.array(
3454
+ z.object({
3455
+ id: z.string().uuid(),
3456
+ channelId: z.string().uuid()
3457
+ })
3458
+ )
3459
+ });
3460
+ var ListRolloutRequestsResponseSchema = z.object({
3461
+ items: z.array(RolloutRequestSummarySchema),
3462
+ total: z.number().int().nonnegative()
3463
+ });
3464
+ var RejectRolloutRequestSchema = z.object({
3465
+ message: z.string().trim().max(4e3).optional()
3466
+ });
3467
+ var ApproveRolloutRequestSchema = z.object({
3468
+ message: z.string().trim().max(4e3).optional()
3469
+ });
3470
+ var AddRolloutCommentSchema = z.object({
3471
+ body: z.string().trim().min(1).max(8e3),
3472
+ mentionedUserIds: z.array(z.string().uuid()).max(20).optional().default([])
3473
+ });
3474
+ var AddRolloutCommentResponseSchema = z.object({
3475
+ comment: RolloutRequestCommentSchema
3476
+ });
3477
+ var FlowTemplateDefaultCommentSchema = z.object({
3478
+ positionX: z.number().finite(),
3479
+ positionY: z.number().finite(),
3480
+ body: z.string().trim().min(1).max(8e3)
3481
+ });
3482
+ var TEMPLATE_COMMENT_AUTHOR_LABEL = "Template";
3483
+ var FlowCommentThreadSourceSchema = z.enum(["user", "template"]);
3484
+
3485
+ // src/dashboard/flowComments.ts
3486
+ var FlowCommentFilterSchema = z.enum(["active", "archived", "all"]);
3487
+ var CreateFlowCommentThreadRequestSchema = z.object({
3488
+ positionX: z.number().finite(),
3489
+ positionY: z.number().finite(),
3490
+ body: z.string().trim().min(1).max(8e3),
3491
+ mentionedUserIds: z.array(z.string().uuid()).max(20).optional().default([]),
3492
+ anchorScreenId: ScreenIdSchema.optional(),
3493
+ anchorLayerId: LayerIdSchema.optional(),
3494
+ anchorDecisionNodeId: DecisionNodeIdSchema.optional(),
3495
+ anchorExternalSurfaceNodeId: ExternalSurfaceNodeIdSchema.optional()
3496
+ }).refine((d) => !d.anchorLayerId || !!d.anchorScreenId, {
3497
+ message: "anchorLayerId requires anchorScreenId",
3498
+ path: ["anchorLayerId"]
3499
+ }).refine(
3500
+ (d) => {
3501
+ const n = (d.anchorScreenId ? 1 : 0) + (d.anchorDecisionNodeId ? 1 : 0) + (d.anchorExternalSurfaceNodeId ? 1 : 0);
3502
+ return n <= 1;
3503
+ },
3504
+ {
3505
+ message: "only one of anchorScreenId, anchorDecisionNodeId, or anchorExternalSurfaceNodeId",
3506
+ path: ["anchorScreenId"]
3507
+ }
3508
+ );
3509
+ var AddFlowCommentMessageRequestSchema = z.object({
3510
+ body: z.string().trim().min(1).max(8e3),
3511
+ parentMessageId: z.string().uuid().nullable().optional(),
3512
+ mentionedUserIds: z.array(z.string().uuid()).max(20).optional().default([])
3513
+ });
3514
+ var FlowCommentMessageSchema = z.object({
3515
+ id: z.string().uuid(),
3516
+ threadId: z.string().uuid(),
3517
+ authorUserId: z.string().uuid(),
3518
+ body: z.string(),
3519
+ parentMessageId: z.string().uuid().nullable(),
3520
+ createdAt: z.string().datetime(),
3521
+ mentions: z.array(RolloutCommentMentionUserSchema)
3522
+ });
3523
+ var FlowCommentThreadSummarySchema = z.object({
3524
+ id: z.string().uuid(),
3525
+ flowId: z.string().uuid(),
3526
+ positionX: z.number(),
3527
+ positionY: z.number(),
3528
+ anchorScreenId: z.string().nullable(),
3529
+ anchorLayerId: z.string().nullable(),
3530
+ anchorDecisionNodeId: z.string().nullable(),
3531
+ anchorExternalSurfaceNodeId: z.string().nullable(),
3532
+ archivedAt: z.string().datetime().nullable(),
3533
+ createdAt: z.string().datetime(),
3534
+ createdByUserId: z.string().uuid(),
3535
+ source: FlowCommentThreadSourceSchema.optional().default("user"),
3536
+ messageCount: z.number().int().nonnegative(),
3537
+ previewSnippet: z.string(),
3538
+ rootMessageAuthorLabel: z.string(),
3539
+ rootMessageCreatedAt: z.string().datetime(),
3540
+ rootMessageBody: z.string()
3541
+ });
3542
+ var ListFlowCommentThreadsResponseSchema = z.object({
3543
+ items: z.array(FlowCommentThreadSummarySchema)
3544
+ });
3545
+ var GetFlowCommentThreadResponseSchema = z.object({
3546
+ thread: FlowCommentThreadSummarySchema,
3547
+ messages: z.array(FlowCommentMessageSchema)
3548
+ });
3549
+ var CreateFlowCommentThreadResponseSchema = z.object({
3550
+ thread: FlowCommentThreadSummarySchema,
3551
+ message: FlowCommentMessageSchema
3552
+ });
3553
+ var AddFlowCommentMessageResponseSchema = z.object({
3554
+ message: FlowCommentMessageSchema
3555
+ });
3556
+ var ArchiveFlowCommentThreadResponseSchema = z.object({
3557
+ thread: FlowCommentThreadSummarySchema
3558
+ });
3559
+ var PublicationSchema = z.object({
3560
+ id: z.string().uuid(),
3561
+ flowId: z.string().uuid(),
3562
+ environment: z.enum(ENVIRONMENTS),
3563
+ revision: z.number().int().positive(),
3564
+ manifest: FlowManifestSchema,
3565
+ publishedAt: z.string().datetime(),
3566
+ supersededAt: z.string().datetime().nullable().optional()
3567
+ });
3568
+ var SignUploadRequestSchema = z.object({
3569
+ type: MediaTypeSchema,
3570
+ contentType: z.string(),
3571
+ sizeBytes: z.number().int().positive(),
3572
+ filename: z.string().min(1).max(200).optional()
3573
+ });
3574
+ var SignUploadResponseSchema = z.object({
3575
+ assetId: z.string().uuid(),
3576
+ uploadUrl: z.string().url(),
3577
+ objectKey: z.string(),
3578
+ publicUrl: z.string().url(),
3579
+ headers: z.record(z.string(), z.string()).optional()
3580
+ });
3581
+ var ConfirmUploadRequestSchema = z.object({
3582
+ assetId: z.string().uuid(),
3583
+ name: z.string().max(200).optional()
3584
+ });
3585
+ var ListMediaResponseSchema = z.object({
3586
+ items: z.array(MediaAssetSchema)
3587
+ });
3588
+ var MediaAssetUsageReferenceSchema = z.object({
3589
+ flowId: z.string().uuid(),
3590
+ flowName: z.string(),
3591
+ appId: z.string().uuid(),
3592
+ appName: z.string(),
3593
+ inDraft: z.boolean(),
3594
+ publishedVersionNumbers: z.array(z.number().int().positive())
3595
+ });
3596
+ var MediaAssetUsageResponseSchema = z.object({
3597
+ references: z.array(MediaAssetUsageReferenceSchema)
3598
+ });
3599
+ var DeleteMediaAssetResponseSchema = z.object({
3600
+ asset: MediaAssetSchema
3601
+ });
3602
+ var UpdateMediaAssetRequestSchema = z.object({
3603
+ nameStem: z.string().trim().min(1).max(200)
3604
+ });
3605
+ var UpdateMediaAssetResponseSchema = z.object({
3606
+ asset: MediaAssetSchema
3607
+ });
3608
+ var ExperimentStatusSchema = z.enum([
3609
+ "draft",
3610
+ "running",
3611
+ "pending_decision",
3612
+ "stopped"
3613
+ ]);
3614
+ var VariantSchema = z.object({
3615
+ id: z.string().uuid(),
3616
+ experimentId: z.string().uuid(),
3617
+ name: z.string().min(1),
3618
+ weight: z.number().int().positive(),
3619
+ flowId: z.string().uuid().nullable(),
3620
+ versionId: z.string().uuid().nullable(),
3621
+ /** Convenience read fields populated by list/get endpoints. */
3622
+ flowName: z.string().nullable().optional(),
3623
+ versionNumber: z.number().int().positive().nullable().optional(),
3624
+ versionLabel: z.string().nullable().optional()
3625
+ });
3626
+ var ExperimentEndedReasonSchema = z.enum([
3627
+ "manual",
3628
+ "scheduled_resolved"
3629
+ ]);
3630
+ var ExperimentSchema = z.object({
3631
+ id: z.string().uuid(),
3632
+ appId: z.string().uuid(),
3633
+ /** Internal channel uuid. */
3634
+ channelId: z.string().uuid(),
3635
+ /** Display name of the channel (denormalized for list views). */
3636
+ channelName: z.string(),
3637
+ /** Test/live env of the channel — kept for badges and analytics filters. */
3638
+ channelEnvironment: z.enum(ENVIRONMENTS),
3639
+ name: z.string(),
3640
+ status: ExperimentStatusSchema,
3641
+ variants: z.array(VariantSchema),
3642
+ startedAt: z.string().datetime().nullable().optional(),
3643
+ stoppedAt: z.string().datetime().nullable().optional(),
3644
+ endsAt: z.string().datetime().nullable().optional(),
3645
+ endedReason: ExperimentEndedReasonSchema.nullable().optional(),
3646
+ archivedAt: z.string().datetime().nullable().optional(),
3647
+ createdAt: z.string().datetime(),
3648
+ /** Dashboard user who created the experiment (null for legacy rows). */
3649
+ createdByUserId: z.string().uuid().nullable().optional(),
3650
+ /** Display: full name, else @username, else email; null when unknown. */
3651
+ createdByLabel: z.string().nullable().optional(),
3652
+ tags: z.array(z.string()),
3653
+ /** Power-analysis inputs; nulls → dashboard defaults for sample accumulation. */
3654
+ statsDesignBaselineCvr: z.number().nullable().optional(),
3655
+ statsDesignMdePp: z.number().nullable().optional(),
3656
+ statsDesignAlpha: z.number().nullable().optional(),
3657
+ statsDesignPower: z.number().nullable().optional()
3658
+ });
3659
+ var EXPERIMENT_STATS_DESIGN_DEFAULTS = {
3660
+ statsDesignBaselineCvr: 0.342,
3661
+ statsDesignMdePp: 3,
3662
+ statsDesignAlpha: 0.05,
3663
+ statsDesignPower: 0.8
3664
+ };
3665
+ var ExperimentStatsDesignInputSchema = z.object({
3666
+ statsDesignBaselineCvr: z.number().min(1e-6).max(0.999999),
3667
+ statsDesignMdePp: z.number().min(0.01).max(50),
3668
+ statsDesignAlpha: z.number().min(1e-3).max(0.5),
3669
+ statsDesignPower: z.number().min(0.5).max(0.999)
3670
+ });
3671
+ var CreateExperimentRequestSchema = z.object({
3672
+ channelId: z.string().uuid(),
3673
+ name: z.string().min(1),
3674
+ /** Required auto-stop. Hour granularity is enforced server-side. */
3675
+ endsAt: z.string().datetime(),
3676
+ tags: TagsSchemaOptional,
3677
+ statsDesignBaselineCvr: z.number().min(1e-6).max(0.999999).optional(),
3678
+ statsDesignMdePp: z.number().min(0.01).max(50).optional(),
3679
+ statsDesignAlpha: z.number().min(1e-3).max(0.5).optional(),
3680
+ statsDesignPower: z.number().min(0.5).max(0.999).optional()
3681
+ });
3682
+ var UpdateExperimentRequestSchema = z.object({
3683
+ name: z.string().min(1).optional(),
3684
+ channelId: z.string().uuid().optional(),
3685
+ endsAt: z.string().datetime().optional(),
3686
+ tags: TagsSchema.optional(),
3687
+ statsDesignBaselineCvr: z.number().min(1e-6).max(0.999999).optional(),
3688
+ statsDesignMdePp: z.number().min(0.01).max(50).optional(),
3689
+ statsDesignAlpha: z.number().min(1e-3).max(0.5).optional(),
3690
+ statsDesignPower: z.number().min(0.5).max(0.999).optional()
3691
+ });
3692
+ var ExtendExperimentRequestSchema = z.object({
3693
+ endsAt: z.string().datetime()
3694
+ });
3695
+ var StopExperimentRequestSchema = z.discriminatedUnion("kind", [
3696
+ z.object({ kind: z.literal("variant"), variantId: z.string().uuid() }),
3697
+ z.object({
3698
+ kind: z.literal("version"),
3699
+ flowId: z.string().uuid(),
3700
+ versionId: z.string().uuid()
3701
+ })
3702
+ ]);
3703
+ var CreateVariantRequestSchema = z.object({
3704
+ weight: z.number().int().positive(),
3705
+ flowId: z.string().uuid().optional(),
3706
+ versionId: z.string().uuid().optional()
3707
+ });
3708
+ var ReorderExperimentVariantsRequestSchema = z.object({
3709
+ variantIds: z.array(z.string().uuid()).min(1)
3710
+ });
3711
+ var UpdateExperimentStatusRequestSchema = z.object({
3712
+ status: ExperimentStatusSchema
3713
+ });
3714
+ var ListExperimentsResponseSchema = z.object({
3715
+ items: z.array(ExperimentSchema)
3716
+ });
3717
+ var ExperimentArmStatsSchema = z.object({
3718
+ variantId: z.string().uuid(),
3719
+ name: z.string(),
3720
+ weight: z.number().int().nonnegative(),
3721
+ trafficShare: z.number(),
3722
+ /** Distinct users with ≥1 `flow_started` in the window. */
3723
+ starts: z.number().int().nonnegative(),
3724
+ /** Distinct users with ≥1 `flow_completed` in the window. */
3725
+ completes: z.number().int().nonnegative(),
3726
+ /** Distinct users with ≥1 `flow_abandoned` in the window. */
3727
+ abandoningUsers: z.number().int().nonnegative(),
3728
+ /** abandoningUsers / starts when starts > 0, else 0. */
3729
+ abandonRate: z.number(),
3730
+ /** Raw event counts (sessions), for debugging / power users. */
3731
+ rawStarts: z.number().int().nonnegative(),
3732
+ rawCompletes: z.number().int().nonnegative(),
3733
+ /** Distinct-user completion rate (`completes / starts`). JSON field name is historical. */
3734
+ conversionRate: z.number(),
3735
+ /** Wilson 95% CI bounds. */
3736
+ ciLow: z.number(),
3737
+ ciHigh: z.number(),
3738
+ lift: z.number().nullable(),
3739
+ pValue: z.number().nullable(),
3740
+ significant: z.boolean().nullable(),
3741
+ /** (completion rate − control) in percentage points; null on control. */
3742
+ liftAbsolutePp: z.number().nullable(),
3743
+ /** 95% CI for absolute completion-rate difference (treatment − control). */
3744
+ liftDiffCiLow: z.number().nullable(),
3745
+ liftDiffCiHigh: z.number().nullable()
3746
+ });
3747
+ var ExperimentFunnelStepSchema = z.object({
3748
+ stepId: z.string(),
3749
+ stepName: z.string().nullable().optional(),
3750
+ views: z.number().int().nonnegative(),
3751
+ completes: z.number().int().nonnegative(),
3752
+ skips: z.number().int().nonnegative(),
3753
+ dropoffs: z.number().int().nonnegative()
3754
+ });
3755
+ var ExperimentAbandonStepRowSchema = z.object({
3756
+ variantId: z.string().uuid(),
3757
+ stepId: z.string(),
3758
+ stepName: z.string().nullable().optional(),
3759
+ users: z.number().int().nonnegative()
3760
+ });
3761
+ var ExperimentSrmSchema = z.object({
3762
+ chiSquareStatistic: z.number(),
3763
+ pValue: z.number().nullable(),
3764
+ /** True when p < 0.01 (observed split unlikely vs configured weights). */
3765
+ flagged: z.boolean()
3766
+ });
3767
+ var ExperimentVariantFunnelSchema = z.object({
3768
+ variantId: z.string().uuid(),
3769
+ steps: z.array(ExperimentFunnelStepSchema)
3770
+ });
3771
+ var ExperimentCohortRuleSchema = z.discriminatedUnion("dimension", [
3772
+ z.object({ dimension: z.literal("platform"), key: z.string().min(1) }),
3773
+ z.object({ dimension: z.literal("locale"), key: z.string().min(1) }),
3774
+ z.object({ dimension: z.literal("app_version"), key: z.string().min(1) }),
3775
+ z.object({ dimension: z.literal("experiment_variant"), key: z.string().min(1) }),
3776
+ z.object({
3777
+ dimension: z.literal("custom_property"),
3778
+ customKey: z.string().regex(/^[A-Za-z0-9._-]{1,64}$/),
3779
+ key: z.string().min(1)
3780
+ })
3781
+ ]);
3782
+ var ExperimentSampleAccumulationSchema = z.object({
3783
+ requiredPerArm: z.number(),
3784
+ /** ISO range used for accumulation starters (same analytics window as results; cohort filters apply). */
3785
+ accumulationRangeStart: z.string().datetime(),
3786
+ accumulationRangeEnd: z.string().datetime(),
3787
+ comparisons: z.number().int(),
3788
+ alphaPerComparison: z.number(),
3789
+ familyAlpha: z.number(),
3790
+ baselineCvr: z.number(),
3791
+ mdePp: z.number(),
3792
+ power: z.number(),
3793
+ /** Distinct starters in the accumulation window (matches Results table when cohorts match). */
3794
+ arms: z.array(
3795
+ z.object({
3796
+ variantId: z.string().uuid(),
3797
+ name: z.string(),
3798
+ observedStarters: z.number().int(),
3799
+ pctOfRequired: z.number()
3800
+ })
3801
+ ),
3802
+ allArmsAboveThreshold: z.boolean()
3803
+ });
3804
+ var ExperimentResultsOverviewSchema = z.object({
3805
+ winningVariant: z.object({ variantId: z.string().uuid(), name: z.string() }).nullable(),
3806
+ /** Sum of distinct starters per arm in the selected stats window. */
3807
+ totalSessions: z.number().int().nonnegative(),
3808
+ experimentTimelineLabel: z.string().nullable(),
3809
+ bestLift: z.object({
3810
+ variantId: z.string().uuid(),
3811
+ name: z.string(),
3812
+ absolutePp: z.number(),
3813
+ relativePct: z.number()
3814
+ }).nullable(),
3815
+ assignmentBalance: z.object({
3816
+ pass: z.boolean(),
3817
+ pValue: z.number().nullable(),
3818
+ chiSquareStatistic: z.number(),
3819
+ threshold: z.number()
3820
+ }),
3821
+ significanceEta: z.object({
3822
+ daysElapsedInclusive: z.number().int().nullable(),
3823
+ daysPlannedInclusive: z.number().int().nullable(),
3824
+ projectedTotalDays: z.number().nullable(),
3825
+ /** Positive = fewer days than planned window to reach projected end. */
3826
+ aheadOfPlanDays: z.number().nullable()
3827
+ }).nullable()
3828
+ });
3829
+ var ExperimentStatsResponseSchema = z.object({
3830
+ rangeStart: z.string().datetime(),
3831
+ rangeEnd: z.string().datetime(),
3832
+ /** Active composite cohort (AND). Null when unsegmented. */
3833
+ cohort: z.array(ExperimentCohortRuleSchema).nullable(),
3834
+ srm: ExperimentSrmSchema,
3835
+ resultsOverview: ExperimentResultsOverviewSchema,
3836
+ arms: z.array(ExperimentArmStatsSchema),
3837
+ abandonByStep: z.array(ExperimentAbandonStepRowSchema),
3838
+ funnel: z.array(ExperimentVariantFunnelSchema),
3839
+ sampleAccumulation: ExperimentSampleAccumulationSchema.optional()
3840
+ });
3841
+ var ExperimentCvrTimeseriesResponseSchema = z.object({
3842
+ keys: z.array(z.string()),
3843
+ points: z.array(
3844
+ z.object({
3845
+ date: z.string(),
3846
+ conversionRates: z.array(z.union([z.number(), z.null()]))
3847
+ })
3848
+ )
3849
+ });
3850
+ var ExperimentEndedPayloadSchema = z.object({
3851
+ appId: z.string().uuid(),
3852
+ experimentId: z.string().uuid(),
3853
+ experimentName: z.string(),
3854
+ channelId: z.string().uuid(),
3855
+ channelName: z.string(),
3856
+ channelEnvironment: z.enum(ENVIRONMENTS)
3857
+ });
3858
+ var NotificationKindSchema = z.enum([
3859
+ "experiment_ended_pick_winner",
3860
+ "rollout_comment_mention",
3861
+ "flow_comment_new",
3862
+ "flow_comment_mention",
3863
+ "flow_comment_reply"
3864
+ ]);
3865
+ var RolloutCommentMentionPayloadSchema = z.object({
3866
+ appId: z.string().uuid(),
3867
+ channelId: z.string().uuid(),
3868
+ requestId: z.string().uuid(),
3869
+ commentId: z.string().uuid(),
3870
+ authorUserId: z.string().uuid(),
3871
+ authorLabel: z.string(),
3872
+ channelName: z.string(),
3873
+ flowName: z.string(),
3874
+ snippet: z.string()
3875
+ });
3876
+ var FlowCommentNotificationBasePayloadSchema = z.object({
3877
+ appId: z.string().uuid(),
3878
+ flowId: z.string().uuid(),
3879
+ flowName: z.string(),
3880
+ threadId: z.string().uuid(),
3881
+ messageId: z.string().uuid(),
3882
+ authorUserId: z.string().uuid(),
3883
+ authorLabel: z.string(),
3884
+ snippet: z.string()
3885
+ });
3886
+ var FlowCommentNewPayloadSchema = FlowCommentNotificationBasePayloadSchema;
3887
+ var FlowCommentMentionPayloadSchema = FlowCommentNotificationBasePayloadSchema;
3888
+ var FlowCommentReplyPayloadSchema = FlowCommentNotificationBasePayloadSchema.extend({
3889
+ parentMessageId: z.string().uuid()
3890
+ });
3891
+ var NotificationBaseSchema = z.object({
3892
+ id: z.string().uuid(),
3893
+ readAt: z.string().datetime().nullable(),
3894
+ createdAt: z.string().datetime()
3895
+ });
3896
+ var NotificationSchema = z.discriminatedUnion("kind", [
3897
+ NotificationBaseSchema.extend({
3898
+ kind: z.literal("experiment_ended_pick_winner"),
3899
+ payload: ExperimentEndedPayloadSchema
3900
+ }),
3901
+ NotificationBaseSchema.extend({
3902
+ kind: z.literal("rollout_comment_mention"),
3903
+ payload: RolloutCommentMentionPayloadSchema
3904
+ }),
3905
+ NotificationBaseSchema.extend({
3906
+ kind: z.literal("flow_comment_new"),
3907
+ payload: FlowCommentNewPayloadSchema
3908
+ }),
3909
+ NotificationBaseSchema.extend({
3910
+ kind: z.literal("flow_comment_mention"),
3911
+ payload: FlowCommentMentionPayloadSchema
3912
+ }),
3913
+ NotificationBaseSchema.extend({
3914
+ kind: z.literal("flow_comment_reply"),
3915
+ payload: FlowCommentReplyPayloadSchema
3916
+ })
3917
+ ]);
3918
+
3919
+ // src/workspaceCapabilities.ts
3920
+ var CLERK_ORG_ADMIN = "org:admin";
3921
+ var CLERK_ORG_MEMBER = "org:member";
3922
+ var WORKSPACE_ROLES = ["owner", "admin", "editor", "viewer"];
3923
+ var WORKSPACE_CAPABILITIES = [
3924
+ "org:read",
3925
+ "billing:manage",
3926
+ "workspace:delete",
3927
+ "workspace:settings",
3928
+ "app:settings",
3929
+ "app:manage",
3930
+ "member:invite",
3931
+ "member:remove",
3932
+ "member:role",
3933
+ "ownership:transfer",
3934
+ "flow:read",
3935
+ "flow:edit",
3936
+ "flow:publish",
3937
+ "channel:read",
3938
+ "channel:manage",
3939
+ "experiment:read",
3940
+ "experiment:manage",
3941
+ "media:manage",
3942
+ "ai:brand_extract",
3943
+ "ai:translate",
3944
+ "store:manage",
3945
+ "analytics:read",
3946
+ "customers:read",
3947
+ "notifications:read",
3948
+ "notifications:write",
3949
+ "apiKey:manage",
3950
+ /** Granted at runtime via workspace-access when the member may approve rollouts. */
3951
+ "rollout:approve"
3952
+ ];
3953
+ var OWNER_CAPS = new Set(
3954
+ WORKSPACE_CAPABILITIES.filter((c) => c !== "rollout:approve")
3955
+ );
3956
+ var caps = (...c) => new Set(c);
3957
+ var ROLE_CAPABILITIES = {
3958
+ admin: caps(
3959
+ "org:read",
3960
+ "workspace:settings",
3961
+ "app:settings",
3962
+ "app:manage",
3963
+ "member:invite",
3964
+ "member:remove",
3965
+ "member:role",
3966
+ "flow:read",
3967
+ "flow:edit",
3968
+ "flow:publish",
3969
+ "channel:read",
3970
+ "channel:manage",
3971
+ "experiment:read",
3972
+ "experiment:manage",
3973
+ "media:manage",
3974
+ "ai:brand_extract",
3975
+ "ai:translate",
3976
+ "store:manage",
3977
+ "analytics:read",
3978
+ "customers:read",
3979
+ "notifications:read",
3980
+ "notifications:write"
3981
+ ),
3982
+ editor: caps(
3983
+ "org:read",
3984
+ "flow:read",
3985
+ "flow:edit",
3986
+ "flow:publish",
3987
+ "channel:read",
3988
+ "channel:manage",
3989
+ "experiment:read",
3990
+ "experiment:manage",
3991
+ "media:manage",
3992
+ "ai:brand_extract",
3993
+ "ai:translate",
3994
+ "store:manage",
3995
+ "analytics:read",
3996
+ "customers:read",
3997
+ "notifications:read",
3998
+ "notifications:write"
3999
+ ),
4000
+ viewer: caps(
4001
+ "org:read",
4002
+ "flow:read",
4003
+ "channel:read",
4004
+ "experiment:read",
4005
+ "analytics:read",
4006
+ "customers:read",
4007
+ "notifications:read",
4008
+ "notifications:write"
4009
+ )
4010
+ };
4011
+ var resolveCapabilities = (role) => {
4012
+ if (role === "owner") return OWNER_CAPS;
4013
+ return ROLE_CAPABILITIES[role];
4014
+ };
4015
+ var hasCapability = (role, capability) => resolveCapabilities(role).has(capability);
4016
+ var hasAnyCapability = (role, capabilities) => {
4017
+ const set = resolveCapabilities(role);
4018
+ return capabilities.some((c) => set.has(c));
4019
+ };
4020
+ var parseWorkspaceRole = (raw) => {
4021
+ if (raw === "owner" || raw === "admin" || raw === "editor" || raw === "viewer") return raw;
4022
+ return null;
4023
+ };
4024
+ var assertWorkspaceRole = (raw) => {
4025
+ const r = parseWorkspaceRole(raw);
4026
+ if (!r) {
4027
+ throw new TypeError(`invalid_workspace_role:${raw}`);
4028
+ }
4029
+ return r;
4030
+ };
4031
+
4032
+ // src/dashboard/workspace.ts
4033
+ var WorkspaceMemberRowSchema = z.object({
4034
+ userId: z.string().uuid(),
4035
+ email: z.string(),
4036
+ /** Same display rule as rollout requester labels. */
4037
+ label: z.string(),
4038
+ workspaceRole: z.enum(WORKSPACE_ROLES),
4039
+ createdAt: z.string()
4040
+ });
4041
+ var ListWorkspaceMembersResponseSchema = z.object({
4042
+ items: z.array(WorkspaceMemberRowSchema)
4043
+ });
4044
+ var ListNotificationsResponseSchema = z.object({
4045
+ items: z.array(NotificationSchema),
4046
+ unreadCount: z.number().int().nonnegative()
4047
+ });
4048
+ var AnalyticsRangeSchema = z.object({
4049
+ flowId: z.string().uuid(),
4050
+ environment: z.enum(ENVIRONMENTS),
4051
+ startDate: z.string().datetime(),
4052
+ endDate: z.string().datetime(),
4053
+ filters: z.object({
4054
+ platform: z.array(z.string()).optional(),
4055
+ locale: z.array(z.string()).optional(),
4056
+ variantId: z.array(z.string()).optional(),
4057
+ customProperties: z.record(z.string(), z.string()).optional()
4058
+ }).optional()
4059
+ });
4060
+ var FunnelResponseSchema = z.object({
4061
+ steps: z.array(
4062
+ z.object({
4063
+ stepId: z.string(),
4064
+ views: z.number().int().nonnegative(),
4065
+ completes: z.number().int().nonnegative(),
4066
+ skips: z.number().int().nonnegative(),
4067
+ dropoffs: z.number().int().nonnegative()
4068
+ })
4069
+ ),
4070
+ totalStarts: z.number().int().nonnegative(),
4071
+ totalCompletes: z.number().int().nonnegative()
4072
+ });
4073
+ var ResponseBreakdownSchema = z.object({
4074
+ fields: z.array(
4075
+ z.object({
4076
+ stepId: z.string(),
4077
+ fieldKey: z.string(),
4078
+ values: z.array(
4079
+ z.object({
4080
+ value: z.string(),
4081
+ count: z.number().int().nonnegative()
4082
+ })
4083
+ )
4084
+ })
4085
+ )
4086
+ });
4087
+ var RoleSchema = z.enum(ROLES);
4088
+ var MembershipSchema = z.object({
4089
+ userId: z.string().uuid(),
4090
+ orgId: z.string().uuid(),
4091
+ role: RoleSchema
4092
+ });
4093
+ var ONBOARDING_TASK_IDS = ["sdk_events"];
4094
+ var OnboardingTaskIdSchema = z.enum(ONBOARDING_TASK_IDS);
4095
+ var OnboardingTaskStatusSchema = z.enum(["pending", "done", "unknown"]);
4096
+ var OnboardingTaskCompletionSourceSchema = z.enum(["auto", "manual"]).nullable();
4097
+ var OnboardingTaskActionSchema = z.object({
4098
+ docsHref: z.string().url().optional(),
4099
+ keysHref: z.string().optional(),
4100
+ verifyable: z.boolean().optional()
4101
+ });
4102
+ var OnboardingTaskSchema = z.object({
4103
+ id: OnboardingTaskIdSchema,
4104
+ title: z.string(),
4105
+ description: z.string(),
4106
+ status: OnboardingTaskStatusSchema,
4107
+ completionSource: OnboardingTaskCompletionSourceSchema,
4108
+ action: OnboardingTaskActionSchema.optional()
4109
+ });
4110
+ var OnboardingChecklistFocusAppSchema = z.object({
4111
+ id: z.string().uuid(),
4112
+ name: z.string()
4113
+ });
4114
+ var OnboardingChecklistResponseSchema = z.object({
4115
+ tasks: z.array(OnboardingTaskSchema),
4116
+ completedCount: z.number().int().nonnegative(),
4117
+ totalCount: z.number().int().nonnegative(),
4118
+ focusApp: OnboardingChecklistFocusAppSchema.nullable(),
4119
+ dismissed: z.boolean(),
4120
+ eligible: z.boolean()
4121
+ });
4122
+ var OnboardingTaskVerifyResponseSchema = z.object({
4123
+ task: OnboardingTaskSchema
4124
+ });
4125
+ var OnboardingTaskCompleteResponseSchema = z.object({
4126
+ task: OnboardingTaskSchema
4127
+ });
4128
+ var OnboardingChecklistDismissResponseSchema = z.object({
4129
+ ok: z.literal(true)
4130
+ });
4131
+
4132
+ // src/sdk.ts
4133
+ var RHEO_DEFAULT_SDK_API_BASE_URL = "https://api.getrheo.io";
4134
+ var SdkResolveRequestSchema = z.object({
4135
+ identity: SdkIdentitySchema,
4136
+ context: SdkContextSchema.optional()
4137
+ });
4138
+ var SdkResolveResponseSchema = z.object({
4139
+ flowId: z.string().uuid(),
4140
+ versionId: z.string().uuid(),
4141
+ versionNumber: z.number().int().positive(),
4142
+ /** Stable id clients can use as an ETag when re-fetching. */
4143
+ assignmentVersion: z.number().int().nonnegative(),
4144
+ environment: z.enum(["test", "live"]),
4145
+ /** PublicId of the channel that resolved this request (for client cache keys). */
4146
+ channelId: z.string(),
4147
+ experimentId: z.string().uuid().nullable(),
4148
+ variantId: z.string().nullable(),
4149
+ manifest: FlowManifestSchema,
4150
+ mediaMap: z.record(z.string(), z.string().url()),
4151
+ /** App branding (gradient presets, etc.) when present on the app record. */
4152
+ branding: BrandingSchema.optional(),
4153
+ /** Workspace-gated SDK capabilities for this resolve. */
4154
+ features: z.object({
4155
+ /** When false, the SDK should not start MMP attribution listeners (Indie / lapsed billing). */
4156
+ attribution: z.boolean()
4157
+ }).optional(),
4158
+ /** Per-app integration toggles from the dashboard; SDK should respect these after resolve. */
4159
+ integrations: ResolvedAppIntegrationsSchema
4160
+ });
4161
+ var SdkResolveAllResponseSchema = z.object({
4162
+ channels: z.array(SdkResolveResponseSchema)
4163
+ });
4164
+ var SdkResolveAssignmentSchema = SdkResolveResponseSchema.omit({
4165
+ manifest: true,
4166
+ mediaMap: true
4167
+ });
4168
+ var FlowTerminalCorrelationSchema = z.object({
4169
+ channelId: z.string(),
4170
+ flowId: z.string().uuid(),
4171
+ versionId: z.string().uuid(),
4172
+ assignmentVersion: z.number().int().nonnegative(),
4173
+ environment: z.enum(["test", "live"]),
4174
+ experimentId: z.string().uuid().nullable(),
4175
+ variantId: z.string().nullable()
4176
+ });
4177
+ var FlowTerminalDeviceSchema = z.object({
4178
+ locale: z.string(),
4179
+ platform: z.string(),
4180
+ appVersion: z.string().optional(),
4181
+ customProperties: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional()
4182
+ });
4183
+ var FlowTerminalSnapshotSchema = z.object({
4184
+ schemaVersion: z.literal(1),
4185
+ terminal: z.enum(["completed", "abandoned"]),
4186
+ /** When the flow reached a terminal status (`FlowState.completedAt`). */
4187
+ occurredAt: z.string().nullable(),
4188
+ correlation: FlowTerminalCorrelationSchema,
4189
+ subject: SdkIdentitySchema,
4190
+ device: FlowTerminalDeviceSchema,
4191
+ /**
4192
+ * Normalized field-key → value summary (same shape as analytics completion map).
4193
+ * Includes every capture field from visited screens (input layers, checkboxes, OS permission keys):
4194
+ * keys with no recorded response appear as `null`. OAuth / email-password auth keys are omitted;
4195
+ * use auth provider callbacks for those.
4196
+ */
4197
+ answers: z.record(z.string(), z.unknown()),
4198
+ /** Single merged SDK/decision context at terminal time (host + attribution + patches). */
4199
+ traits: z.record(z.string(), z.unknown()),
4200
+ /** Walked screen / surface node ids when `includePathInTerminalPayload` is true. */
4201
+ path: z.array(z.string()).optional(),
4202
+ /** Raw step responses (minus auth keys) when `includeAnswerDetailInTerminalPayload` is true. */
4203
+ answersDetail: z.record(z.string(), z.unknown()).optional(),
4204
+ manifest: FlowManifestSchema.optional()
4205
+ });
4206
+ var SdkCompletionPayloadSchema = FlowTerminalSnapshotSchema;
4207
+ var EventNameSchema = z.enum(EVENT_NAMES);
4208
+ var SdkEventSchema = z.object({
4209
+ eventId: z.string().uuid(),
4210
+ name: EventNameSchema,
4211
+ timestamp: z.string().datetime(),
4212
+ flowId: z.string().uuid(),
4213
+ /** Resolved version the SDK was rendering when the event occurred. */
4214
+ versionId: z.string().uuid(),
4215
+ experimentId: z.string().uuid().nullable().optional(),
4216
+ variantId: z.string().nullable().optional(),
4217
+ stepId: z.string().nullable().optional(),
4218
+ identity: SdkIdentitySchema,
4219
+ context: SdkContextSchema.optional(),
4220
+ properties: z.record(
4221
+ z.string(),
4222
+ z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(z.string())])
4223
+ ).optional(),
4224
+ /** for text_submitted, marks this value as sensitive so backend redacts */
4225
+ fieldClassification: z.enum(["safe", "sensitive"]).optional()
4226
+ });
4227
+ var SdkEventBatchSchema = z.object({
4228
+ events: z.array(SdkEventSchema).min(1).max(500)
4229
+ });
4230
+ var IapPurchasePeriodTypeSchema = z.enum(["normal", "intro", "trial"]);
4231
+ var IapPurchaseEventPropertiesSchema = z.object({
4232
+ /** External surface provider that produced the purchase. */
4233
+ provider: z.literal("revenuecat"),
4234
+ /** Manifest node id of the surface (e.g. `surf_paywall_welcome`). */
4235
+ surface_node_id: z.string().min(1).max(128),
4236
+ /** Store product identifier (e.g. `pro_annual`). */
4237
+ product_id: z.string().min(1).max(256),
4238
+ /** Optional RevenueCat offering id (manifest config or RC metadata). */
4239
+ offering_id: z.string().min(1).max(128).optional(),
4240
+ /** Optional RevenueCat package identifier within the offering (e.g. `$rc_annual`). */
4241
+ package_id: z.string().min(1).max(128).optional(),
4242
+ /** Localized gross store price at purchase time (non-negative). */
4243
+ price: z.number().nonnegative().optional(),
4244
+ /** ISO 4217 currency code (e.g. `USD`, `EUR`). Stored uppercase. */
4245
+ currency: z.string().regex(/^[A-Za-z]{3}$/, "currency must be a 3-letter ISO 4217 code").transform((s) => s.toUpperCase()).optional(),
4246
+ /** Period type when known. */
4247
+ period_type: IapPurchasePeriodTypeSchema.optional()
4248
+ }).refine(
4249
+ (v) => v.price === void 0 === (v.currency === void 0),
4250
+ {
4251
+ message: "price and currency must be provided together",
4252
+ path: ["price"]
4253
+ }
4254
+ );
4255
+ var IapPurchaseStoredPropertiesSchema = IapPurchaseEventPropertiesSchema.innerType().extend({
4256
+ /** USD-normalized price computed server-side from daily FX rates. Null when FX missing. */
4257
+ price_usd: z.number().nonnegative().nullable().optional(),
4258
+ /** True when client provided price + currency but FX conversion was unavailable. */
4259
+ fx_unavailable: z.boolean().optional()
4260
+ });
4261
+
4262
+ // src/externalSurfaceIntegrations.ts
4263
+ var listEnabledExternalSurfaceProviders = (integrations) => {
4264
+ const out = [];
4265
+ if (integrations.revenuecat.enabled) out.push("revenuecat");
4266
+ return out;
4267
+ };
4268
+ var externalSurfaceProviderLabel = (provider) => {
4269
+ switch (provider) {
4270
+ case "unspecified":
4271
+ return "Not selected";
4272
+ case "revenuecat":
4273
+ return "RevenueCat";
4274
+ default: {
4275
+ const _exhaustive = provider;
4276
+ return _exhaustive;
4277
+ }
4278
+ }
4279
+ };
4280
+ var externalSurfaceProviderMenuDescription = (provider) => {
4281
+ switch (provider) {
4282
+ case "revenuecat":
4283
+ return "Present the host RevenueCat paywall and branch on purchase, restore, dismiss, or failure.";
4284
+ default: {
4285
+ const _exhaustive = provider;
4286
+ return _exhaustive;
4287
+ }
4288
+ }
4289
+ };
4290
+ var createExternalSurfaceConfig = (provider, options) => {
4291
+ switch (provider) {
4292
+ case "unspecified":
4293
+ return { provider: "unspecified" };
4294
+ case "revenuecat":
4295
+ return {
4296
+ provider: "revenuecat",
4297
+ ...options?.offeringId ? { offeringId: options.offeringId } : {},
4298
+ ...options?.placementId ? { placementId: options.placementId } : {},
4299
+ ...options?.presentation ? { presentation: options.presentation } : {}
4300
+ };
4301
+ default: {
4302
+ const _exhaustive = provider;
4303
+ return _exhaustive;
4304
+ }
4305
+ }
4306
+ };
4307
+
4308
+ // src/planEntitlements.ts
4309
+ var CONCURRENT_EXPERIMENT_STATUSES = [
4310
+ "draft",
4311
+ "running",
4312
+ "pending_decision"
4313
+ ];
4314
+ var BILLING_PLAN_KEYS = ["indie", "grow", "scale", "enterprise"];
4315
+ var PLAN_ENTITLEMENTS = {
4316
+ indie: {
4317
+ maxApps: 1,
4318
+ maxChannelsPerEnvironment: 1,
4319
+ maxSeats: 1,
4320
+ includedMauLive: 1e3,
4321
+ experiments: false,
4322
+ translations: false,
4323
+ animations: false,
4324
+ ai: false,
4325
+ allowInvites: false,
4326
+ integrations: false,
4327
+ rolloutApprovals: false,
4328
+ maxConcurrentExperiments: 0,
4329
+ attribution: false
4330
+ },
4331
+ grow: {
4332
+ maxApps: 3,
4333
+ maxChannelsPerEnvironment: 3,
4334
+ maxSeats: 5,
4335
+ includedMauLive: 1e4,
4336
+ experiments: true,
4337
+ translations: true,
4338
+ animations: true,
4339
+ ai: true,
4340
+ allowInvites: true,
4341
+ integrations: true,
4342
+ rolloutApprovals: false,
4343
+ maxConcurrentExperiments: 2,
4344
+ attribution: true
4345
+ },
4346
+ scale: {
4347
+ maxApps: 10,
4348
+ maxChannelsPerEnvironment: 10,
4349
+ maxSeats: 25,
4350
+ includedMauLive: 1e5,
4351
+ experiments: true,
4352
+ translations: true,
4353
+ animations: true,
4354
+ ai: true,
4355
+ allowInvites: true,
4356
+ integrations: true,
4357
+ rolloutApprovals: true,
4358
+ maxConcurrentExperiments: 5,
4359
+ attribution: true
4360
+ },
4361
+ enterprise: {
4362
+ maxApps: null,
4363
+ maxChannelsPerEnvironment: null,
4364
+ maxSeats: null,
4365
+ includedMauLive: null,
4366
+ experiments: true,
4367
+ translations: true,
4368
+ animations: true,
4369
+ ai: true,
4370
+ allowInvites: true,
4371
+ integrations: true,
4372
+ rolloutApprovals: true,
4373
+ maxConcurrentExperiments: null,
4374
+ attribution: true
4375
+ }
4376
+ };
4377
+ var parseBillingPlanKey = (raw) => {
4378
+ if (!raw?.trim()) return null;
4379
+ const k = raw.trim();
4380
+ return BILLING_PLAN_KEYS.includes(k) ? k : null;
4381
+ };
4382
+ var getPlanEntitlements = (plan) => PLAN_ENTITLEMENTS[plan];
4383
+ var isPlanLimitUnlimited = (limit) => limit === null;
4384
+ var isWithinPlanNumericLimit = (count, limit) => limit === null || count <= limit;
4385
+ var countsTowardConcurrentExperimentLimit = (status) => CONCURRENT_EXPERIMENT_STATUSES.includes(status);
4386
+ var isWithinConcurrentExperimentLimit = (count, limit) => isWithinPlanNumericLimit(count, limit);
4387
+ var LIVE_MAU_OVERAGE_USD_PER_UNIT = 0.01;
4388
+ var formatLiveMauOverageRate = (usdPerUnit = LIVE_MAU_OVERAGE_USD_PER_UNIT) => usdPerUnit.toLocaleString("en-US", {
4389
+ style: "currency",
4390
+ currency: "USD",
4391
+ minimumFractionDigits: 2,
4392
+ maximumFractionDigits: 2
4393
+ });
4394
+ var isPricingTableMauIncludedLimit = (limit) => /mau included/i.test(limit.detail);
4395
+ var pricingTableMauOverageFootnote = (planId) => {
4396
+ switch (planId) {
4397
+ case "indie":
4398
+ return "Exceeding quota pauses the SDK until the next month or plan upgrade.";
4399
+ case "grow":
4400
+ case "scale":
4401
+ return `Additional MAU billed at ${formatLiveMauOverageRate()} per MAU per month.`;
4402
+ case "enterprise":
4403
+ return null;
4404
+ }
4405
+ };
4406
+ var liveMauOverageUnits = (liveMau, plan) => {
4407
+ const inc = PLAN_ENTITLEMENTS[plan].includedMauLive;
4408
+ if (inc === null) return 0;
4409
+ return Math.max(0, liveMau - inc);
4410
+ };
4411
+ var filterCapabilitiesForPlan = (caps2, ent) => [...caps2].filter((c) => {
4412
+ if (!ent.allowInvites && c === "member:invite") return false;
4413
+ if (!ent.ai && (c === "ai:brand_extract" || c === "ai:translate")) return false;
4414
+ if (!ent.experiments && c === "experiment:manage") return false;
4415
+ return true;
4416
+ });
4417
+ var mergeCanvasEditorGatesForPlan = (gates, ent) => ({
4418
+ ...gates,
4419
+ lottie: gates.lottie && ent.animations
4420
+ });
4421
+
4422
+ // src/billingPeriod.ts
4423
+ var MAU_USAGE_ALERT_THRESHOLD_50 = 0.5;
4424
+ var MAU_USAGE_ALERT_THRESHOLD_80 = 0.8;
4425
+ var MAU_USAGE_ALERT_LEVELS = ["50", "80", "100"];
4426
+ var getUtcCalendarMonthPeriod = (now = /* @__PURE__ */ new Date()) => {
4427
+ const y = now.getUTCFullYear();
4428
+ const m = now.getUTCMonth();
4429
+ const start = new Date(Date.UTC(y, m, 1, 0, 0, 0, 0));
4430
+ const end = new Date(Date.UTC(y, m + 1, 0, 23, 59, 59, 999));
4431
+ const periodKey = `${y}-${String(m + 1).padStart(2, "0")}`;
4432
+ return {
4433
+ periodKey,
4434
+ startIso: start.toISOString(),
4435
+ endIso: end.toISOString()
4436
+ };
4437
+ };
4438
+ var mauUsageThreshold = (liveMau, includedMau) => {
4439
+ if (includedMau <= 0) return "none";
4440
+ if (liveMau > includedMau) return "suspended";
4441
+ const at80 = includedMau * MAU_USAGE_ALERT_THRESHOLD_80;
4442
+ const at50 = includedMau * MAU_USAGE_ALERT_THRESHOLD_50;
4443
+ if (liveMau >= at80) return "80";
4444
+ if (liveMau >= at50) return "50";
4445
+ return "none";
4446
+ };
4447
+ var mauUsageBannerLevel = (threshold) => {
4448
+ if (threshold === "suspended") return "100";
4449
+ if (threshold === "80") return "80";
4450
+ return null;
4451
+ };
4452
+ var mauUsageEmailAlertLevel = (threshold) => {
4453
+ if (threshold === "none") return null;
4454
+ if (threshold === "suspended") return "100";
4455
+ return threshold;
4456
+ };
4457
+
4458
+ // src/experiment-sample-size.ts
4459
+ var quantileNormal = (p) => {
4460
+ if (p <= 0 || p >= 1 || Number.isNaN(p)) throw new RangeError("quantileNormal: p must be in (0,1)");
4461
+ let lo = -9;
4462
+ let hi = 9;
4463
+ for (let i = 0; i < 90; i++) {
4464
+ const mid = (lo + hi) / 2;
4465
+ if (normalCdf(mid) < p) lo = mid;
4466
+ else hi = mid;
4467
+ }
4468
+ return (lo + hi) / 2;
4469
+ };
4470
+ var erf = (x) => {
4471
+ const sign = x < 0 ? -1 : 1;
4472
+ const ax = Math.abs(x);
4473
+ const a1 = 0.254829592;
4474
+ const a2 = -0.284496736;
4475
+ const a3 = 1.421413741;
4476
+ const a4 = -1.453152027;
4477
+ const a5 = 1.061405429;
4478
+ const t = 1 / (1 + 0.3275911 * ax);
4479
+ const y = 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-ax * ax);
4480
+ return sign * y;
4481
+ };
4482
+ var normalCdf = (x) => {
4483
+ return 0.5 * (1 + erf(x / Math.SQRT2));
4484
+ };
4485
+ var DEFAULT_STATS_BASELINE_CVR = EXPERIMENT_STATS_DESIGN_DEFAULTS.statsDesignBaselineCvr;
4486
+ var DEFAULT_STATS_MDE_PP = EXPERIMENT_STATS_DESIGN_DEFAULTS.statsDesignMdePp;
4487
+ var DEFAULT_STATS_FAMILY_ALPHA = EXPERIMENT_STATS_DESIGN_DEFAULTS.statsDesignAlpha;
4488
+ var DEFAULT_STATS_POWER = EXPERIMENT_STATS_DESIGN_DEFAULTS.statsDesignPower;
4489
+ var resolveExperimentSampleDesign = (row) => {
4490
+ const baselineCvr = row.statsDesignBaselineCvr ?? DEFAULT_STATS_BASELINE_CVR;
4491
+ const mdePp = row.statsDesignMdePp ?? DEFAULT_STATS_MDE_PP;
4492
+ const familyAlpha = row.statsDesignAlpha ?? DEFAULT_STATS_FAMILY_ALPHA;
4493
+ const power = row.statsDesignPower ?? DEFAULT_STATS_POWER;
4494
+ const comparisons = Math.max(1, Math.max(0, row.variantCount - 1));
4495
+ const alphaPerComparison = familyAlpha / comparisons;
4496
+ const p0 = Math.min(1, Math.max(0, baselineCvr));
4497
+ const delta = mdePp / 100;
4498
+ const p1 = Math.min(1, Math.max(0, p0 + delta));
4499
+ const requiredPerArm = requiredSamplePerArm({
4500
+ p0,
4501
+ p1,
4502
+ alphaTwoSidedPerComparison: alphaPerComparison,
4503
+ power
4504
+ });
4505
+ return {
4506
+ baselineCvr,
4507
+ mdePp,
4508
+ familyAlpha,
4509
+ power,
4510
+ comparisons,
4511
+ alphaPerComparison,
4512
+ p0,
4513
+ p1,
4514
+ requiredPerArm
4515
+ };
4516
+ };
4517
+ var requiredSamplePerArm = (opts) => {
4518
+ const { p0, p1, alphaTwoSidedPerComparison, power } = opts;
4519
+ const delta = p1 - p0;
4520
+ if (delta <= 0 || delta >= 1) return Number.POSITIVE_INFINITY;
4521
+ if (alphaTwoSidedPerComparison <= 0 || alphaTwoSidedPerComparison >= 1)
4522
+ return Number.POSITIVE_INFINITY;
4523
+ if (power <= 0 || power >= 1) return Number.POSITIVE_INFINITY;
4524
+ const zAlpha = quantileNormal(1 - alphaTwoSidedPerComparison / 2);
4525
+ const zBeta = quantileNormal(power);
4526
+ const pBar = (p0 + p1) / 2;
4527
+ const num = 2 * Math.pow(zAlpha + zBeta, 2) * pBar * (1 - pBar);
4528
+ const den = delta * delta;
4529
+ const n = num / den;
4530
+ if (!Number.isFinite(n) || n <= 0) return Number.POSITIVE_INFINITY;
4531
+ return Math.ceil(n);
4532
+ };
4533
+
4534
+ // src/experimentVariantLabel.ts
4535
+ var experimentVariantVersionDescriptor = (versionLabel, versionNumber) => {
4536
+ if (versionLabel != null && String(versionLabel).trim() !== "") {
4537
+ return String(versionLabel).trim();
4538
+ }
4539
+ if (versionNumber != null && versionNumber > 0) {
4540
+ return `v${versionNumber}`;
4541
+ }
4542
+ return "\u2014";
4543
+ };
4544
+ var formatExperimentVariantDerivedName = (p) => {
4545
+ const flow = (p.flowName ?? "").trim() || "Flow";
4546
+ const vd = experimentVariantVersionDescriptor(p.versionLabel, p.versionNumber);
4547
+ const base = `${flow} \xB7 ${vd}`;
4548
+ const ord = p.duplicateOrdinal ?? 0;
4549
+ if (ord > 0) {
4550
+ return `${base} (${ord + 1})`;
4551
+ }
4552
+ return base;
4553
+ };
4554
+
4555
+ export { ANIMATABLE_PROPERTIES, ANIMATION_TRIGGERS, API_VERSION, APP_INTEGRATIONS_DEFAULTS, APP_REVIEW_CAPTURE_FIELD_KEY_PREFIX, APP_REVIEW_OUTCOMES, AUTOSAVE_DEBOUNCE_MS, AddFlowCommentMessageRequestSchema, AddFlowCommentMessageResponseSchema, AddRolloutCommentResponseSchema, AddRolloutCommentSchema, AiFlowPromptSchema, AnalyticsRangeSchema, AnimatablePropertySchema, AnimationClipSchema, AnimationTriggerSchema, AppIconSchema, AppIntegrationsSchema, AppReviewOutcomeSchema, AppSchema, ApproveRolloutRequestSchema, AppsFlyerIntegrationSchema, ArchiveChannelRequestSchema, ArchiveFlowCommentThreadResponseSchema, AssignmentClearedPayloadSchema, AttributionProviderSignalQuerySchema, AttributionProviderSignalResponseSchema, AutosaveDraftRequestSchema, AutosaveDraftResponseSchema, BILLING_PLAN_KEYS, BUTTON_LAYER_VARIANTS, BackButtonLayerSchema, BorderSchema, BranchConditionSchema, BrandColorSchema, BrandGradientSchema, BrandGradientStopSchema, BrandingSchema, BuilderMetaSchema, ButtonActionSchema, ButtonLayerSchema, ButtonLayerVariantSchema, ButtonLayoutBreakpointsSchema, ButtonStyleBreakpointsSchema, ButtonStyleSchema, CANVAS_EDITOR_GATE_KEYS, CLERK_ORG_ADMIN, CLERK_ORG_MEMBER, CONCURRENT_EXPERIMENT_STATUSES, COUNTER_DISPLAY_KINDS, COUNTER_TIME_FORMATS, CREATE_FLOW_AI_PROMPT_MAX, CanvasEditorGatesPatchSchema, CanvasEditorGatesResolvedSchema, CarouselIndicatorsStyleSchema, CarouselLayerSchema, CarouselPageControlSchema, ChannelArchivedPayloadSchema, ChannelAssignmentKindSchema, ChannelAssignmentRequestSchema, ChannelCreatedPayloadSchema, ChannelDirectAssignmentSchema, ChannelEventPayloadSchema, ChannelEventSchema, ChannelEventTypeSchema, ChannelExperimentAssignmentSchema, ChannelHistoryExperimentSnapshotSchema, ChannelHistoryFlowVersionSnapshotSchema, ChannelHistoryPreviousAssignmentSchema, ChannelRenamedPayloadSchema, ChannelSchema, ChannelUnarchivedPayloadSchema, CheckboxGlyphStyleSchema, CheckboxLayerSchema, ChoiceBranchingSchema, ChoiceOptionBindingSchema, CommonLayoutHeightSchema, CommonStyleBreakpointsSchema, CommonStyleSchema, ConfirmUploadRequestSchema, CounterLayerSchema, CreateAppRequestSchema, CreateAppResponseSchema, CreateChannelRequestSchema, CreateExperimentRequestSchema, CreateFlowCommentThreadRequestSchema, CreateFlowCommentThreadResponseSchema, CreateFlowRequestSchema, CreateFlowResponseSchema, CreateRolloutRequestsBodySchema, CreateRolloutRequestsResponseSchema, CreateVariantRequestSchema, DASHBOARD_ATTRIBUTION_INTEGRATION_PROVIDER_IDS, DASHBOARD_MAX_TAGS, DASHBOARD_MAX_TAG_LEN, DECISION_ELSE_SOURCE_HANDLE, DEFAULT_ANIMATION_CLIP_DURATION_MS, DEFAULT_LOCALE, DEFAULT_OAUTH_PRESET_BUTTON_LABEL, DEFAULT_STATS_BASELINE_CVR, DEFAULT_STATS_FAMILY_ALPHA, DEFAULT_STATS_MDE_PP, DEFAULT_STATS_POWER, DEFAULT_THEMED_FOREGROUND, DashboardAttributionIntegrationProviderIdSchema, DecisionBooleanPredicateSchema, DecisionBuiltinNameSchema, DecisionCaseSchema, DecisionChoicePredicateSchema, DecisionExprSchema, DecisionMultiPredicateSchema, DecisionNodeIdSchema, DecisionNodeSchema, DecisionNumberPredicateSchema, DecisionPredicatePayloadSchema, DecisionStringPredicateSchema, DecisionVariableRefSchema, DeleteAppRequestSchema, DeleteAppResponseSchema, DeleteMediaAssetResponseSchema, DirectPinnedPayloadSchema, DropShadowSchema, DuplicateFlowRequestSchema, EASING_TOKENS, EMAIL_PASSWORD_AUTH_MODES, EMAIL_PASSWORD_SLOTS, EMPTY_BRANDING, ENVIRONMENTS, EVENT_NAMES, EXPERIMENT_STATS_DESIGN_DEFAULTS, EXTERNAL_SURFACE_NO_NEXT, EasingTokenSchema, EmailPasswordAuthLayerSchema, EmailPasswordAuthModeSchema, EmailPasswordFieldLayerSchema, EmailPasswordSubmitLayerSchema, EventNameSchema, ExperimentAbandonStepRowSchema, ExperimentArmStatsSchema, ExperimentAssignedPayloadSchema, ExperimentCohortRuleSchema, ExperimentCvrTimeseriesResponseSchema, ExperimentEndedPayloadSchema, ExperimentEndedReasonSchema, ExperimentFunnelStepSchema, ExperimentResultsOverviewSchema, ExperimentSampleAccumulationSchema, ExperimentSchema, ExperimentSrmSchema, ExperimentStatsDesignInputSchema, ExperimentStatsResponseSchema, ExperimentStatusSchema, ExperimentStoppedRepinnedPayloadSchema, ExperimentVariantFunnelSchema, ExperimentWinnerPromotedPayloadSchema, ExtendExperimentRequestSchema, ExternalSurfaceConfigSchema, ExternalSurfaceNodeIdSchema, ExternalSurfaceNodeSchema, ExternalSurfaceOutcomesMapSchema, FIELD_CLASSIFICATIONS, FIELD_KEY_RE, FLOW_TEMPLATE_CATALOG, FLOW_TEMPLATE_CATEGORIES, FLOW_TEMPLATE_CATEGORY_LABELS, FLOW_TEMPLATE_IDS, FONT_FILE_EXTENSIONS, FONT_MIME_TYPES, FieldClassificationSchema, FieldKeySchema, FlowAiGenerationRunStatusResponseSchema, FlowAiGenerationRunStatusSchema, FlowCommentFilterSchema, FlowCommentMentionPayloadSchema, FlowCommentMessageSchema, FlowCommentNewPayloadSchema, FlowCommentNotificationBasePayloadSchema, FlowCommentReplyPayloadSchema, FlowCommentThreadSourceSchema, FlowCommentThreadSummarySchema, FlowDraftSchema, FlowJumpTargetSchema, FlowManifestObjectBaseSchema, FlowManifestObjectSchema, FlowManifestSchema, FlowPreviewSchema, FlowStatusSchema, FlowSummarySchema, FlowTemplateDefaultCommentSchema, FlowTemplateIdSchema, FlowTerminalCorrelationSchema, FlowTerminalDeviceSchema, FlowTerminalSnapshotSchema, FlowVersionSchema, FlowVersionWithManifestSchema, FontFamilySchema, FontStyleSchema, FunnelResponseSchema, GetFlowCommentThreadResponseSchema, HEIGHT_PRESETS, HyperlinkLayerSchema, ICON_FAMILIES, IMAGE_MIME_TYPES, INPUT_LAYER_KINDS, IapPurchaseEventPropertiesSchema, IapPurchasePeriodTypeSchema, IapPurchaseStoredPropertiesSchema, IconLayerSchema, IconStyleBreakpointsSchema, IconStyleSchema, ImageLayerSchema, ImageStyleBreakpointsSchema, ImageStyleSchema, KeyframeSchema, KeyframeTrackSchema, LAYER_KINDS, LIVE_MAU_OVERAGE_USD_PER_UNIT, LOTTIE_MIME_TYPES, LayerIdSchema, LayerSchema, ListChannelHistoryResponseSchema, ListChannelsResponseSchema, ListExperimentsResponseSchema, ListFlowCommentThreadsResponseSchema, ListMediaResponseSchema, ListNotificationsResponseSchema, ListRolloutRequestsResponseSchema, ListVersionsResponseSchema, ListWorkspaceMembersResponseSchema, LoaderLayerSchema, LoaderOnCompleteSchema, LocaleCode, LocalizedTextSchema, LottieLayerSchema, MANIFEST_SCHEMA_VERSION, MAU_USAGE_ALERT_LEVELS, MAU_USAGE_ALERT_THRESHOLD_50, MAU_USAGE_ALERT_THRESHOLD_80, MAX_FONT_BYTES, MAX_IMAGE_BYTES, MAX_LOTTIE_BYTES, MAX_VIDEO_BYTES, MEDIA_TYPES, MediaAssetSchema, MediaAssetUsageReferenceSchema, MediaAssetUsageResponseSchema, MediaReferenceSchema, MediaTypeSchema, MembershipSchema, MultipleChoiceLayerSchema, NORMALIZED_SURFACE_OUTCOMES, NonNegativePxSchema, NormalizedSurfaceOutcomeSchema, NotificationKindSchema, NotificationSchema, OAUTH_LOGIN_PRESETS, OAUTH_LOGIN_PRESET_DISPLAY, OAuthLoginCustomProviderSchema, OAuthLoginLayerSchema, OAuthLoginPresetProviderSchema, OAuthLoginProviderSchema, OAuthLoginProvidersArraySchema, OAuthPresetButtonChromeBreakpointsSchema, OAuthPresetButtonChromeSchema, OAuthProviderCustomLayerSchema, OAuthProviderLayerSchema, OAuthProviderPresetLayerSchema, ONBOARDING_TASK_IDS, OS_PERMISSION_KEYS, OS_PERMISSION_OUTCOME_CONTINUE, OS_PERMISSION_OUTCOME_END, OnboardingChecklistDismissResponseSchema, OnboardingChecklistFocusAppSchema, OnboardingChecklistResponseSchema, OnboardingTaskActionSchema, OnboardingTaskCompleteResponseSchema, OnboardingTaskCompletionSourceSchema, OnboardingTaskIdSchema, OnboardingTaskSchema, OnboardingTaskStatusSchema, OnboardingTaskVerifyResponseSchema, OsPermissionKeySchema, OsPermissionOutcomeBranchTargetSchema, PERMISSION_CAPTURE_FIELD_KEY_PREFIX, PERMISSION_OUTCOME_VALUES, PLAN_ENTITLEMENTS, PRIMARY_FILLED_LABEL, PUBLISHABLE_KEY_PREFIX, PaddingSchema, PatchRolloutPolicySchema, PermissionOutcomeSchema, ProgressLayerSchema, PublicationSchema, PublishRequestSchema, PublishResponseSchema, PublishValidationErrorSchema, PublishableKeySchema, RESERVED_RC_SDK_KEYS, RESTING_MOTION_PRESETS, RESTING_MOTION_ROTATE_DIRECTIONS, RESTING_MOTION_SCALE_DIRECTIONS, RHEO_AGENT_IMAGE_MIME_TYPES, RHEO_AGENT_MAX_IMAGE_ATTACHMENTS, RHEO_DEFAULT_SDK_API_BASE_URL, ROLES, RejectRolloutRequestSchema, RenameChannelRequestSchema, ReorderExperimentVariantsRequestSchema, ResolvedAppIntegrationsSchema, ResponseBreakdownSchema, RestingMotionEntrySchema, RestingMotionPresetSchema, RestingMotionRotateDirectionSchema, RestingMotionScaleDirectionSchema, RestingMotionSchema, RevenueCatIntegrationSchema, RevenueCatSurfaceConfigSchema, RevenueCatSurfacePresentationSchema, RheoAgentApplyingManifestEventSchema, RheoAgentAttemptEventSchema, RheoAgentChatRequestSchema, RheoAgentDoneEventSchema, RheoAgentErrorEventSchema, RheoAgentImageAttachmentSchema, RheoAgentManifestEventSchema, RheoAgentMessageSchema, RheoAgentSelectionSchema, RheoAgentStreamEventSchema, RheoAgentTextDeltaEventSchema, RoleSchema, RolloutCommentKindSchema, RolloutCommentMentionPayloadSchema, RolloutCommentMentionUserSchema, RolloutFlowPayloadSchema, RolloutPolicyResponseSchema, RolloutRequestCommentSchema, RolloutRequestDetailSchema, RolloutRequestStatusSchema, RolloutRequestSummarySchema, SCREEN_BACKGROUND_PLAYBACK_PREFIX, SDK_EVENT_FLUSH_MS, STEP_TYPES, ScaleInputLabelStyleSchema, ScaleInputLayerSchema, ScreenBackgroundColorFillSchema, ScreenBackgroundFillPatchSchema, ScreenBackgroundFillSchema, ScreenBackgroundFitSchema, ScreenBackgroundImageFillSchema, ScreenBackgroundScrimSchema, ScreenBackgroundVideoFillSchema, ScreenContainerStyleBreakpointsSchema, ScreenContainerStyleSchema, ScreenIdSchema, ScreenNextSchema, ScreenRegionsSchema, ScreenSchema, ScreenStaggerSchema, SdkCompletionPayloadSchema, SdkContextSchema, SdkEventBatchSchema, SdkEventSchema, SdkIdentitySchema, SdkResolveAllResponseSchema, SdkResolveAssignmentSchema, SdkResolveRequestSchema, SdkResolveResponseSchema, SignUploadRequestSchema, SignUploadResponseSchema, SingleChoiceLayerSchema, StackLayerSchema, StackLayoutBreakpointsSchema, StartAiFlowGenerationRequestSchema, StopExperimentRequestSchema, StoreListingInputSchema, StoreListingLookupResponseSchema, SurfaceProviderSchema, TEMPLATE_COMMENT_AUTHOR_LABEL, TEXT_INPUT_TYPES, TagsSchema, TagsSchemaOptional, TextInputLayerSchema, TextInputTypeSchema, TextLayerSchema, TextStyleBreakpointsSchema, TextStyleSchema, ThemeSchema, ThemedColorModesSchema, ThemedColorSchema, UnarchiveChannelResponseSchema, UnspecifiedExternalSurfaceConfigSchema, UpdateAppBrandingRequestSchema, UpdateAppRequestSchema, UpdateExperimentRequestSchema, UpdateExperimentStatusRequestSchema, UpdateFlowRequestSchema, UpdateMediaAssetRequestSchema, UpdateMediaAssetResponseSchema, VIDEO_MIME_TYPES, VariantSchema, VideoLayerSchema, WIDTH_PRESETS, WORKSPACE_CAPABILITIES, WORKSPACE_ROLES, WidthValueSchema, WorkspaceMemberRowSchema, appReviewCaptureFieldKey, assertWorkspaceRole, baseLayerShape, collectAnswerCaptureFieldKeysFromScreen, collectCanvasGateViolations, collectDecisionFieldKeys, collectDecisionFieldKeysFromNode, collectDecisionSdkKeys, collectDecisionSdkKeysFromNode, commonStyleHasAbsolutePosition, countsTowardConcurrentExperimentLimit, createExternalSurfaceConfig, defaultOAuthPresetButtonLabel, defaultScreenBackgroundColorFill, defaultScreenBackgroundImageFill, defaultScreenBackgroundVideoFill, describeCanvasGatesForAi, emailPasswordAuthResponseKey, experimentVariantVersionDescriptor, externalSurfaceProviderLabel, externalSurfaceProviderMenuDescription, filterCapabilitiesForPlan, formatExperimentVariantDerivedName, formatLiveMauOverageRate, getPlanEntitlements, getUtcCalendarMonthPeriod, hasAnyCapability, hasCapability, isInputLayer, isParentLayer, isPlanLimitUnlimited, isPricingTableMauIncludedLimit, isReservedSdkKey, isScreenBackgroundPlaybackId, isWithinConcurrentExperimentLimit, isWithinPlanNumericLimit, layerHasAbsolutePositionAuthored, layerSchemaStore, layerSubtreeContainsAbsolutePosition, listEnabledExternalSurfaceProviders, liveMauOverageUnits, manifestPassesCanvasGates, manifestScreenLayerKinds, mauUsageBannerLevel, mauUsageEmailAlertLevel, mauUsageThreshold, mediaExtensionFromContentType, mergeCanvasEditorGatesForPlan, mergeMediaFileNameStem, migrateLegacyDecisionNodeInPlace, migrateLegacyManifest, minimalLayerExamples, normalCdf, normalizeDashboardTags, oauthLoginManifestProviderFromLayer, oauthLoginResponseKey, oauthPresetEffectiveLabel, parseAppIntegrations, parseBillingPlanKey, parseCanvasEditorGates, parseHyperlinkHref, parseWorkspaceRole, permissionCaptureFieldKey, pricingTableMauOverageFootnote, quantileNormal, requiredSamplePerArm, resolveCapabilities, resolveExperimentSampleDesign, resolveExternalSurfaceTarget, resolveLocalizedText, screenBackgroundPlaybackId, splitMediaFileName, validateChoiceChildrenAndBindings, walkScreenLayers, walkScreenLayersWithLayoutContext };
4556
+ //# sourceMappingURL=index.js.map
4557
+ //# sourceMappingURL=index.js.map