@orion-studios/payload-studio 0.6.0-beta.45 → 0.6.0-beta.47

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.
@@ -15,18 +15,76 @@ type BuilderV2ValidationIssue = {
15
15
  path: string;
16
16
  severity: 'error' | 'warning';
17
17
  };
18
+ type BuilderV2Role = 'admin' | 'client' | 'developer' | 'editor';
19
+ type BuilderV2PermissionSet = {
20
+ canEditCustomCode?: boolean;
21
+ canManageGlobalStyles?: boolean;
22
+ canManageReusableSections?: boolean;
23
+ canPublish?: boolean;
24
+ canUseEmbeds?: boolean;
25
+ role?: BuilderV2Role;
26
+ };
18
27
  type BuilderV2CompiledOutput = {
19
28
  css: string;
20
29
  dynamicComponents: BuilderV2DynamicComponentInstance[];
21
30
  html: string;
31
+ validationIssues?: BuilderV2ValidationIssue[];
22
32
  };
23
33
  type BuilderV2ProjectData = Record<string, unknown>;
34
+ type BuilderV2ThemeTokens = {
35
+ buttons?: Record<string, unknown>;
36
+ colors?: Record<string, string>;
37
+ fonts?: Record<string, string>;
38
+ radii?: Record<string, string>;
39
+ shadows?: Record<string, string>;
40
+ spacing?: Record<string, string>;
41
+ typography?: Record<string, unknown>;
42
+ };
43
+ type BuilderV2PageTreeNode = {
44
+ children?: BuilderV2PageTreeNode[];
45
+ id: number | string;
46
+ parentId?: number | string | null;
47
+ path: string;
48
+ slug: string;
49
+ status?: 'draft' | 'published';
50
+ title: string;
51
+ };
52
+ type BuilderV2VersionSnapshot = {
53
+ compiledCss?: string;
54
+ compiledHtml?: string;
55
+ createdAt: string;
56
+ id: string;
57
+ label: string;
58
+ projectData?: BuilderV2ProjectData | null;
59
+ published?: boolean;
60
+ };
61
+ type BuilderV2ReusableSection = {
62
+ category?: string;
63
+ id: string;
64
+ name: string;
65
+ projectData: BuilderV2ProjectData;
66
+ thumbnail?: string;
67
+ };
68
+ type BuilderV2EditorMeta = {
69
+ pageTree?: BuilderV2PageTreeNode[];
70
+ permissions?: BuilderV2PermissionSet;
71
+ themeTokens?: BuilderV2ThemeTokens;
72
+ };
24
73
  type BuilderV2PageData = {
74
+ builderAutosaveProjectData?: BuilderV2ProjectData | null;
25
75
  builderDynamicComponents?: BuilderV2DynamicComponentInstance[];
76
+ builderLastPublishedAt?: string;
77
+ builderLastSavedAt?: string;
78
+ builderLockedAreas?: string[];
26
79
  builderMode?: string;
27
80
  builderProjectData?: BuilderV2ProjectData | null;
28
81
  builderPublishedProjectData?: BuilderV2ProjectData | null;
82
+ builderPublishedSnapshot?: BuilderV2VersionSnapshot | null;
83
+ builderReusableSections?: BuilderV2ReusableSection[];
84
+ builderSeo?: Record<string, unknown> | null;
85
+ builderThemeTokens?: BuilderV2ThemeTokens | null;
29
86
  builderValidationIssues?: BuilderV2ValidationIssue[];
87
+ builderVersions?: BuilderV2VersionSnapshot[];
30
88
  compiledCss?: string;
31
89
  compiledHtml?: string;
32
90
  id?: number | string;
@@ -70,11 +128,13 @@ type BuilderV2TraitDefinition = {
70
128
  type BuilderV2ProjectAdapter = {
71
129
  components?: Record<string, BuilderV2ProjectComponentDefinition | BuilderV2RuntimeComponent>;
72
130
  dataProviders?: Record<string, unknown>;
131
+ defaultThemeTokens?: BuilderV2ThemeTokens;
73
132
  id: string;
74
133
  label?: string;
75
134
  themeTokens?: Record<string, unknown>;
76
135
  };
77
136
  type BuilderV2EditorInitialData = {
137
+ meta?: BuilderV2EditorMeta;
78
138
  projectData?: BuilderV2ProjectData | null;
79
139
  title?: string;
80
140
  };
@@ -145,6 +205,19 @@ declare const createBuilderV2PageService: ({ collectionSlug, payload, user, }: C
145
205
  declare const createEmptyBuilderV2ProjectData: (title?: string) => BuilderV2ProjectData;
146
206
  declare const normalizeBuilderV2ProjectData: (value: unknown, fallbackTitle?: string) => BuilderV2ProjectData;
147
207
 
208
+ type PageLike = {
209
+ id: number | string;
210
+ parent?: number | string | {
211
+ id?: number | string;
212
+ } | null;
213
+ parentId?: number | string | null;
214
+ path?: string | null;
215
+ slug?: string | null;
216
+ title?: string | null;
217
+ _status?: 'draft' | 'published';
218
+ };
219
+ declare const buildBuilderV2PageTree: (pages: PageLike[]) => BuilderV2PageTreeNode[];
220
+
148
221
  declare function BuilderPageRuntime({ adapter, className, page }: BuilderV2RuntimeProps): react_jsx_runtime.JSX.Element;
149
222
 
150
223
  declare const parseBuilderV2DynamicComponents: (html: string) => BuilderV2DynamicComponentInstance[];
@@ -152,5 +225,12 @@ declare const splitBuilderV2HtmlIntoChunks: (html: string) => BuilderV2Renderabl
152
225
 
153
226
  declare const sanitizeBuilderHtml: (value: unknown) => string;
154
227
  declare const sanitizeBuilderCss: (value: unknown) => string;
228
+ declare const scopeBuilderCss: (value: unknown, scope?: string) => string;
229
+
230
+ declare const validateBuilderV2Output: (input: {
231
+ css?: unknown;
232
+ html?: unknown;
233
+ }) => BuilderV2ValidationIssue[];
234
+ declare const hasBlockingBuilderV2Issues: (issues: BuilderV2ValidationIssue[]) => boolean;
155
235
 
156
- export { BuilderPageRuntime, type BuilderV2Asset, type BuilderV2CompiledOutput, type BuilderV2DynamicComponentInstance, type BuilderV2EditorInitialData, type BuilderV2FieldOptions, type BuilderV2Mode, type BuilderV2PageData, type BuilderV2PagePayloadDoc, type BuilderV2ProjectAdapter, type BuilderV2ProjectComponentDefinition, type BuilderV2ProjectData, type BuilderV2RenderResult, type BuilderV2RenderableChunk, type BuilderV2RuntimeComponent, type BuilderV2RuntimeComponentProps, type BuilderV2RuntimeProps, type BuilderV2TraitDefinition, type BuilderV2ValidationIssue, type CreateBuilderV2PageServiceArgs, type SaveBuilderV2PageInput, appendBuilderV2PageFields, compileBuilderV2Output, createBuilderV2PageFields, createBuilderV2PageService, createEmptyBuilderV2ProjectData, normalizeBuilderV2ProjectData, parseBuilderV2DynamicComponents, sanitizeBuilderCss, sanitizeBuilderHtml, splitBuilderV2HtmlIntoChunks, toBuilderV2EditorInitialData };
236
+ export { BuilderPageRuntime, type BuilderV2Asset, type BuilderV2CompiledOutput, type BuilderV2DynamicComponentInstance, type BuilderV2EditorInitialData, type BuilderV2FieldOptions, type BuilderV2Mode, type BuilderV2PageData, type BuilderV2PagePayloadDoc, type BuilderV2PageTreeNode, type BuilderV2PermissionSet, type BuilderV2ProjectAdapter, type BuilderV2ProjectComponentDefinition, type BuilderV2ProjectData, type BuilderV2RenderResult, type BuilderV2RenderableChunk, type BuilderV2RuntimeComponent, type BuilderV2RuntimeComponentProps, type BuilderV2RuntimeProps, type BuilderV2ThemeTokens, type BuilderV2TraitDefinition, type BuilderV2ValidationIssue, type BuilderV2VersionSnapshot, type CreateBuilderV2PageServiceArgs, type SaveBuilderV2PageInput, appendBuilderV2PageFields, buildBuilderV2PageTree, compileBuilderV2Output, createBuilderV2PageFields, createBuilderV2PageService, createEmptyBuilderV2ProjectData, hasBlockingBuilderV2Issues, normalizeBuilderV2ProjectData, parseBuilderV2DynamicComponents, sanitizeBuilderCss, sanitizeBuilderHtml, scopeBuilderCss, splitBuilderV2HtmlIntoChunks, toBuilderV2EditorInitialData, validateBuilderV2Output };
@@ -32,16 +32,20 @@ var builder_v2_exports = {};
32
32
  __export(builder_v2_exports, {
33
33
  BuilderPageRuntime: () => BuilderPageRuntime,
34
34
  appendBuilderV2PageFields: () => appendBuilderV2PageFields,
35
+ buildBuilderV2PageTree: () => buildBuilderV2PageTree,
35
36
  compileBuilderV2Output: () => compileBuilderV2Output,
36
37
  createBuilderV2PageFields: () => createBuilderV2PageFields,
37
38
  createBuilderV2PageService: () => createBuilderV2PageService,
38
39
  createEmptyBuilderV2ProjectData: () => createEmptyBuilderV2ProjectData,
40
+ hasBlockingBuilderV2Issues: () => hasBlockingBuilderV2Issues,
39
41
  normalizeBuilderV2ProjectData: () => normalizeBuilderV2ProjectData,
40
42
  parseBuilderV2DynamicComponents: () => parseBuilderV2DynamicComponents,
41
43
  sanitizeBuilderCss: () => sanitizeBuilderCss,
42
44
  sanitizeBuilderHtml: () => sanitizeBuilderHtml,
45
+ scopeBuilderCss: () => scopeBuilderCss,
43
46
  splitBuilderV2HtmlIntoChunks: () => splitBuilderV2HtmlIntoChunks,
44
- toBuilderV2EditorInitialData: () => toBuilderV2EditorInitialData
47
+ toBuilderV2EditorInitialData: () => toBuilderV2EditorInitialData,
48
+ validateBuilderV2Output: () => validateBuilderV2Output
45
49
  });
46
50
  module.exports = __toCommonJS(builder_v2_exports);
47
51
 
@@ -75,6 +79,13 @@ var createBuilderV2PageFields = (options = {}) => {
75
79
  },
76
80
  hidden
77
81
  ),
82
+ withHiddenAdmin(
83
+ {
84
+ name: "builderAutosaveProjectData",
85
+ type: "json"
86
+ },
87
+ hidden
88
+ ),
78
89
  withHiddenAdmin(
79
90
  {
80
91
  name: "builderPublishedProjectData",
@@ -109,6 +120,62 @@ var createBuilderV2PageFields = (options = {}) => {
109
120
  type: "json"
110
121
  },
111
122
  hidden
123
+ ),
124
+ withHiddenAdmin(
125
+ {
126
+ name: "builderVersions",
127
+ type: "json"
128
+ },
129
+ hidden
130
+ ),
131
+ withHiddenAdmin(
132
+ {
133
+ name: "builderPublishedSnapshot",
134
+ type: "json"
135
+ },
136
+ hidden
137
+ ),
138
+ withHiddenAdmin(
139
+ {
140
+ name: "builderReusableSections",
141
+ type: "json"
142
+ },
143
+ hidden
144
+ ),
145
+ withHiddenAdmin(
146
+ {
147
+ name: "builderThemeTokens",
148
+ type: "json"
149
+ },
150
+ hidden
151
+ ),
152
+ withHiddenAdmin(
153
+ {
154
+ name: "builderLockedAreas",
155
+ type: "json"
156
+ },
157
+ hidden
158
+ ),
159
+ withHiddenAdmin(
160
+ {
161
+ name: "builderSeo",
162
+ type: "json"
163
+ },
164
+ hidden
165
+ ),
166
+ withHiddenAdmin(
167
+ {
168
+ name: "builderLastSavedAt",
169
+ type: "date"
170
+ },
171
+ hidden
172
+ ),
173
+ withHiddenAdmin(
174
+ {
175
+ name: "builderLastPublishedAt",
176
+ type: "date"
177
+ },
178
+ hidden
112
179
  )
113
180
  ];
114
181
  };
@@ -228,6 +295,7 @@ var allowedIframeHosts = [
228
295
  "calendar.google.com",
229
296
  "calendly.com",
230
297
  "player.vimeo.com",
298
+ "www.google.com",
231
299
  "www.youtube.com",
232
300
  "youtube.com"
233
301
  ];
@@ -253,15 +321,119 @@ var sanitizeBuilderCss = (value) => {
253
321
  }
254
322
  return value.replace(/@import\s+[^;]+;/gi, "").replace(/expression\s*\(/gi, "").replace(/javascript\s*:/gi, "");
255
323
  };
324
+ var scopeSelector = (selector, scope) => selector.split(",").map((part) => {
325
+ const trimmed = part.trim();
326
+ if (!trimmed || trimmed.startsWith(scope) || trimmed.startsWith("@")) {
327
+ return trimmed;
328
+ }
329
+ if (/^(html|body|:root)\b/i.test(trimmed)) {
330
+ return trimmed.replace(/^(html|body|:root)\b/i, scope);
331
+ }
332
+ return `${scope} ${trimmed}`;
333
+ }).filter(Boolean).join(", ");
334
+ var scopeBuilderCss = (value, scope = ".orion-builder-v2-runtime") => {
335
+ const css = sanitizeBuilderCss(value);
336
+ if (!css) {
337
+ return "";
338
+ }
339
+ let output = "";
340
+ let cursor = 0;
341
+ const rulePattern = /([^{}]+)\{/g;
342
+ let match;
343
+ while ((match = rulePattern.exec(css)) !== null) {
344
+ const selectorStart = match.index;
345
+ const selector = match[1];
346
+ output += css.slice(cursor, selectorStart);
347
+ const trimmedSelector = selector.trim();
348
+ if (trimmedSelector.startsWith("@keyframes") || trimmedSelector.startsWith("@font-face") || trimmedSelector.startsWith("@page")) {
349
+ output += `${selector}{`;
350
+ } else if (trimmedSelector.startsWith("@media") || trimmedSelector.startsWith("@supports")) {
351
+ output += `${selector}{`;
352
+ } else {
353
+ output += `${scopeSelector(selector, scope)} {`;
354
+ }
355
+ cursor = rulePattern.lastIndex;
356
+ }
357
+ output += css.slice(cursor);
358
+ return output;
359
+ };
360
+
361
+ // src/builder-v2/validation.ts
362
+ var hasMatch = (value, pattern) => pattern.test(value);
363
+ var validateBuilderV2Output = (input) => {
364
+ const html = typeof input.html === "string" ? input.html : "";
365
+ const css = typeof input.css === "string" ? input.css : "";
366
+ const issues = [];
367
+ if (!html.trim()) {
368
+ issues.push({
369
+ code: "empty-page",
370
+ message: "This page has no rendered content.",
371
+ path: "compiledHtml",
372
+ severity: "error"
373
+ });
374
+ }
375
+ if (!hasMatch(html, /<h1\b/i)) {
376
+ issues.push({
377
+ code: "missing-h1",
378
+ message: "Add one H1 so the published page has a clear primary heading.",
379
+ path: "compiledHtml",
380
+ severity: "warning"
381
+ });
382
+ }
383
+ if (hasMatch(html, /\son[a-z]+\s*=/i)) {
384
+ issues.push({
385
+ code: "inline-event-handler",
386
+ message: "Inline event handlers are not allowed in published builder HTML.",
387
+ path: "compiledHtml",
388
+ severity: "error"
389
+ });
390
+ }
391
+ if (hasMatch(html, /<(script|object|embed)\b/i)) {
392
+ issues.push({
393
+ code: "unsafe-element",
394
+ message: "Script, object, and embed tags are not allowed in builder content.",
395
+ path: "compiledHtml",
396
+ severity: "error"
397
+ });
398
+ }
399
+ if (hasMatch(html, /\b(?:href|src)=["']\s*javascript:/i)) {
400
+ issues.push({
401
+ code: "unsafe-url",
402
+ message: "Links and media cannot use javascript URLs.",
403
+ path: "compiledHtml",
404
+ severity: "error"
405
+ });
406
+ }
407
+ if (hasMatch(css, /@import\s/i)) {
408
+ issues.push({
409
+ code: "css-import",
410
+ message: "CSS imports are removed at publish time. Use the site font and theme managers instead.",
411
+ path: "compiledCss",
412
+ severity: "warning"
413
+ });
414
+ }
415
+ if (hasMatch(css, /position\s*:\s*fixed/i)) {
416
+ issues.push({
417
+ code: "fixed-position",
418
+ message: "Fixed positioning can cover site navigation or dialogs. Review this before publishing.",
419
+ path: "compiledCss",
420
+ severity: "warning"
421
+ });
422
+ }
423
+ return issues;
424
+ };
425
+ var hasBlockingBuilderV2Issues = (issues) => issues.some((issue) => issue.severity === "error");
256
426
 
257
427
  // src/builder-v2/payload/compile.ts
258
428
  var compileBuilderV2Output = (input) => {
259
429
  const html = sanitizeBuilderHtml(input.html);
260
- const css = sanitizeBuilderCss(input.css);
430
+ const css = scopeBuilderCss(input.css);
431
+ const validationIssues = validateBuilderV2Output({ css: input.css, html: input.html });
261
432
  return {
262
433
  css,
263
434
  dynamicComponents: parseBuilderV2DynamicComponents(html),
264
- html
435
+ html,
436
+ validationIssues
265
437
  };
266
438
  };
267
439
 
@@ -309,6 +481,25 @@ var normalizeBuilderV2ProjectData = (value, fallbackTitle = "Untitled Page") =>
309
481
 
310
482
  // src/builder-v2/payload/pageService.ts
311
483
  var pageTitle = (page) => typeof page.title === "string" && page.title.trim().length > 0 ? page.title : "Untitled Page";
484
+ var normalizeVersions = (value) => Array.isArray(value) ? value.filter((item) => Boolean(item && typeof item === "object")) : [];
485
+ var createVersionSnapshot = ({
486
+ compiled,
487
+ label,
488
+ projectData,
489
+ published = false
490
+ }) => {
491
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
492
+ return {
493
+ compiledCss: compiled.css,
494
+ compiledHtml: compiled.html,
495
+ createdAt,
496
+ id: `builder-v2-${createdAt.replace(/[^0-9]/g, "")}`,
497
+ label,
498
+ projectData,
499
+ published
500
+ };
501
+ };
502
+ var appendVersionSnapshot = (current, snapshot) => [snapshot, ...normalizeVersions(current)].slice(0, 50);
312
503
  var toBuilderV2EditorInitialData = (page) => ({
313
504
  projectData: normalizeBuilderV2ProjectData(
314
505
  page.builderProjectData || page.builderPublishedProjectData,
@@ -338,14 +529,33 @@ var createBuilderV2PageService = ({
338
529
  },
339
530
  saveDraft: async (pageID, input) => {
340
531
  const compiled = compileBuilderV2Output(input.compiled);
532
+ const existing = await payload.findByID({
533
+ collection: collectionSlug,
534
+ depth: 0,
535
+ draft: true,
536
+ id: pageID,
537
+ overrideAccess: false,
538
+ user
539
+ });
540
+ const validationIssues = input.validationIssues || compiled.validationIssues || [];
341
541
  await payload.update({
342
542
  collection: collectionSlug,
343
543
  data: {
344
544
  _status: "draft",
545
+ builderAutosaveProjectData: null,
345
546
  builderDynamicComponents: compiled.dynamicComponents,
547
+ builderLastSavedAt: (/* @__PURE__ */ new Date()).toISOString(),
346
548
  builderMode: "grapes-v2",
347
549
  builderProjectData: input.projectData,
348
- builderValidationIssues: input.validationIssues || [],
550
+ builderValidationIssues: validationIssues,
551
+ builderVersions: appendVersionSnapshot(
552
+ existing.builderVersions,
553
+ createVersionSnapshot({
554
+ compiled,
555
+ label: "Draft saved",
556
+ projectData: input.projectData
557
+ })
558
+ ),
349
559
  compiledCss: compiled.css,
350
560
  compiledHtml: compiled.html,
351
561
  ...input.title ? { title: input.title } : {}
@@ -362,15 +572,35 @@ var createBuilderV2PageService = ({
362
572
  },
363
573
  publish: async (pageID, input) => {
364
574
  const compiled = compileBuilderV2Output(input.compiled);
575
+ const existing = await payload.findByID({
576
+ collection: collectionSlug,
577
+ depth: 0,
578
+ draft: true,
579
+ id: pageID,
580
+ overrideAccess: false,
581
+ user
582
+ });
583
+ const validationIssues = input.validationIssues || compiled.validationIssues || [];
584
+ const snapshot = createVersionSnapshot({
585
+ compiled,
586
+ label: "Published",
587
+ projectData: input.projectData,
588
+ published: true
589
+ });
365
590
  await payload.update({
366
591
  collection: collectionSlug,
367
592
  data: {
368
593
  _status: "published",
594
+ builderAutosaveProjectData: null,
369
595
  builderDynamicComponents: compiled.dynamicComponents,
596
+ builderLastPublishedAt: snapshot.createdAt,
597
+ builderLastSavedAt: snapshot.createdAt,
370
598
  builderMode: "grapes-v2",
371
599
  builderProjectData: input.projectData,
372
600
  builderPublishedProjectData: input.projectData,
373
- builderValidationIssues: input.validationIssues || [],
601
+ builderPublishedSnapshot: snapshot,
602
+ builderValidationIssues: validationIssues,
603
+ builderVersions: appendVersionSnapshot(existing.builderVersions, snapshot),
374
604
  compiledCss: compiled.css,
375
605
  compiledHtml: compiled.html,
376
606
  ...input.title ? { title: input.title } : {}
@@ -387,6 +617,46 @@ var createBuilderV2PageService = ({
387
617
  }
388
618
  });
389
619
 
620
+ // src/builder-v2/pageTree.ts
621
+ var relationId = (value) => {
622
+ if (typeof value === "number" || typeof value === "string") {
623
+ return value;
624
+ }
625
+ if (value && typeof value === "object") {
626
+ const id = value.id;
627
+ return typeof id === "number" || typeof id === "string" ? id : null;
628
+ }
629
+ return null;
630
+ };
631
+ var buildBuilderV2PageTree = (pages) => {
632
+ const nodes = /* @__PURE__ */ new Map();
633
+ const roots = [];
634
+ pages.forEach((page) => {
635
+ nodes.set(page.id, {
636
+ children: [],
637
+ id: page.id,
638
+ parentId: page.parentId ?? relationId(page.parent),
639
+ path: page.path || (page.slug ? `/${page.slug}` : "/"),
640
+ slug: page.slug || "",
641
+ status: page._status,
642
+ title: page.title || "Untitled page"
643
+ });
644
+ });
645
+ nodes.forEach((node) => {
646
+ if (node.parentId && nodes.has(node.parentId)) {
647
+ nodes.get(node.parentId)?.children?.push(node);
648
+ } else {
649
+ roots.push(node);
650
+ }
651
+ });
652
+ const sortNodes = (items) => {
653
+ items.sort((a, b) => a.path.localeCompare(b.path));
654
+ items.forEach((item) => sortNodes(item.children || []));
655
+ };
656
+ sortNodes(roots);
657
+ return roots;
658
+ };
659
+
390
660
  // src/builder-v2/runtime/BuilderPageRuntime.tsx
391
661
  var import_react = require("react");
392
662
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -402,7 +672,7 @@ var resolveRuntimeComponent = (adapter, type) => {
402
672
  };
403
673
  function BuilderPageRuntime({ adapter, className, page }) {
404
674
  const html = sanitizeBuilderHtml(page.compiledHtml);
405
- const css = sanitizeBuilderCss(page.compiledCss);
675
+ const css = scopeBuilderCss(page.compiledCss);
406
676
  const chunks = splitBuilderV2HtmlIntoChunks(html);
407
677
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: ["orion-builder-v2-runtime", className].filter(Boolean).join(" "), children: [
408
678
  css ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: { __html: css } }) : null,
@@ -436,14 +706,18 @@ function BuilderPageRuntime({ adapter, className, page }) {
436
706
  0 && (module.exports = {
437
707
  BuilderPageRuntime,
438
708
  appendBuilderV2PageFields,
709
+ buildBuilderV2PageTree,
439
710
  compileBuilderV2Output,
440
711
  createBuilderV2PageFields,
441
712
  createBuilderV2PageService,
442
713
  createEmptyBuilderV2ProjectData,
714
+ hasBlockingBuilderV2Issues,
443
715
  normalizeBuilderV2ProjectData,
444
716
  parseBuilderV2DynamicComponents,
445
717
  sanitizeBuilderCss,
446
718
  sanitizeBuilderHtml,
719
+ scopeBuilderCss,
447
720
  splitBuilderV2HtmlIntoChunks,
448
- toBuilderV2EditorInitialData
721
+ toBuilderV2EditorInitialData,
722
+ validateBuilderV2Output
449
723
  });