@shoppexio/builder-contracts 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fields.d.ts +4 -4
- package/dist/migrations.d.ts +1 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +25 -0
- package/dist/persistence.d.ts +9 -0
- package/dist/persistence.d.ts.map +1 -1
- package/dist/persistence.js +80 -0
- package/dist/preview-protocol.d.ts +88 -4
- package/dist/preview-protocol.d.ts.map +1 -1
- package/dist/preview-protocol.js +57 -7
- package/dist/storefront-initial-data-html.js +1 -1
- package/dist/theme-manifest.d.ts +2 -2
- package/dist/theme-schemes.d.ts +2 -2
- package/dist/theme-schemes.d.ts.map +1 -1
- package/dist/theme-schemes.js +1 -0
- package/package.json +1 -1
- package/src/builder-contracts.test.ts +49 -1
- package/src/migrations.ts +36 -0
- package/src/persistence.ts +107 -0
- package/src/preview-protocol.test.ts +90 -0
- package/src/preview-protocol.ts +67 -8
- package/src/storefront-initial-data-html.test.ts +8 -0
- package/src/storefront-initial-data-html.ts +1 -1
- package/src/theme-schemes.ts +1 -0
package/dist/fields.d.ts
CHANGED
|
@@ -14,13 +14,13 @@ export declare const ListItemFieldTypeSchema: z.ZodEnum<{
|
|
|
14
14
|
number: "number";
|
|
15
15
|
boolean: "boolean";
|
|
16
16
|
link: "link";
|
|
17
|
+
product: "product";
|
|
17
18
|
text: "text";
|
|
18
19
|
richtext: "richtext";
|
|
19
20
|
image: "image";
|
|
20
21
|
range: "range";
|
|
21
22
|
select: "select";
|
|
22
23
|
color: "color";
|
|
23
|
-
product: "product";
|
|
24
24
|
}>;
|
|
25
25
|
export type ListItemFieldType = z.infer<typeof ListItemFieldTypeSchema>;
|
|
26
26
|
export declare const ListItemFieldSchema: z.ZodObject<{
|
|
@@ -38,13 +38,13 @@ export declare const ListItemFieldSchema: z.ZodObject<{
|
|
|
38
38
|
number: "number";
|
|
39
39
|
boolean: "boolean";
|
|
40
40
|
link: "link";
|
|
41
|
+
product: "product";
|
|
41
42
|
text: "text";
|
|
42
43
|
richtext: "richtext";
|
|
43
44
|
image: "image";
|
|
44
45
|
range: "range";
|
|
45
46
|
select: "select";
|
|
46
47
|
color: "color";
|
|
47
|
-
product: "product";
|
|
48
48
|
}>;
|
|
49
49
|
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
50
50
|
label: z.ZodString;
|
|
@@ -266,13 +266,13 @@ export declare const BuilderFieldSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
266
266
|
number: "number";
|
|
267
267
|
boolean: "boolean";
|
|
268
268
|
link: "link";
|
|
269
|
+
product: "product";
|
|
269
270
|
text: "text";
|
|
270
271
|
richtext: "richtext";
|
|
271
272
|
image: "image";
|
|
272
273
|
range: "range";
|
|
273
274
|
select: "select";
|
|
274
275
|
color: "color";
|
|
275
|
-
product: "product";
|
|
276
276
|
}>;
|
|
277
277
|
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
278
278
|
label: z.ZodString;
|
|
@@ -495,13 +495,13 @@ export declare const BlockSettingsSchema: z.ZodRecord<z.ZodString, z.ZodDiscrimi
|
|
|
495
495
|
number: "number";
|
|
496
496
|
boolean: "boolean";
|
|
497
497
|
link: "link";
|
|
498
|
+
product: "product";
|
|
498
499
|
text: "text";
|
|
499
500
|
richtext: "richtext";
|
|
500
501
|
image: "image";
|
|
501
502
|
range: "range";
|
|
502
503
|
select: "select";
|
|
503
504
|
color: "color";
|
|
504
|
-
product: "product";
|
|
505
505
|
}>;
|
|
506
506
|
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
507
507
|
label: z.ZodString;
|
package/dist/migrations.d.ts
CHANGED
|
@@ -27,5 +27,6 @@ export declare function createBlockInstance(input: {
|
|
|
27
27
|
export declare function createPageLayoutFromBlocks(blocks: BlockInstance[]): PageLayout;
|
|
28
28
|
export declare function migrateLegacyBuilderSettings(input: LegacyBuilderSettingsInput, revision?: number): BuilderSettings;
|
|
29
29
|
export declare function applyManifestDefaultLayout(settings: BuilderSettings, manifest: ThemeManifest): BuilderSettings;
|
|
30
|
+
export declare function mapLegacyNestedThemeTypographyToStyleSlots(theme: Record<string, unknown>, baseSlots?: StyleSlots): StyleSlots;
|
|
30
31
|
export declare function mapLegacyTokenOverridesToStyleSlots(tokens: Record<string, unknown>): StyleSlots;
|
|
31
32
|
//# sourceMappingURL=migrations.d.ts.map
|
package/dist/migrations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,QAAQ,SAAI,GAAG,eAAe,CAYxE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,UAAU,CAAC;CAC9B,GAAG,aAAa,CAShB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,UAAU,CAE9E;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,0BAA0B,EAAE,QAAQ,SAAI,GAAG,eAAe,CAoB7G;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,GAAG,eAAe,CAwB9G;AAED,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAuC/F"}
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,QAAQ,SAAI,GAAG,eAAe,CAYxE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,UAAU,CAAC;CAC9B,GAAG,aAAa,CAShB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,UAAU,CAE9E;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,0BAA0B,EAAE,QAAQ,SAAI,GAAG,eAAe,CAoB7G;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,GAAG,eAAe,CAwB9G;AAED,wBAAgB,0CAA0C,CACxD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,GAAE,UAAe,GACzB,UAAU,CAkBZ;AAeD,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAuC/F"}
|
package/dist/migrations.js
CHANGED
|
@@ -69,6 +69,31 @@ export function applyManifestDefaultLayout(settings, manifest) {
|
|
|
69
69
|
}
|
|
70
70
|
return BuilderSettingsSchema.parse(next);
|
|
71
71
|
}
|
|
72
|
+
export function mapLegacyNestedThemeTypographyToStyleSlots(theme, baseSlots = {}) {
|
|
73
|
+
const slots = { ...baseSlots };
|
|
74
|
+
const typography = theme.typography;
|
|
75
|
+
if (!isRecord(typography)) {
|
|
76
|
+
return slots;
|
|
77
|
+
}
|
|
78
|
+
const bodyFont = readLegacyTypographyString(typography, 'font_family', 'fontFamily');
|
|
79
|
+
const headingFont = readLegacyTypographyString(typography, 'heading_font', 'headingFont');
|
|
80
|
+
if (bodyFont && slots['theme.typography.font.family'] === undefined) {
|
|
81
|
+
slots['theme.typography.font.family'] = bodyFont;
|
|
82
|
+
}
|
|
83
|
+
if (headingFont && slots['theme.typography.heading.font'] === undefined) {
|
|
84
|
+
slots['theme.typography.heading.font'] = headingFont;
|
|
85
|
+
}
|
|
86
|
+
return slots;
|
|
87
|
+
}
|
|
88
|
+
function readLegacyTypographyString(typography, ...keys) {
|
|
89
|
+
for (const key of keys) {
|
|
90
|
+
const value = typography[key];
|
|
91
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
92
|
+
return value.trim();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
72
97
|
export function mapLegacyTokenOverridesToStyleSlots(tokens) {
|
|
73
98
|
const slots = {};
|
|
74
99
|
assignResponsiveNumber(tokens, slots, 'buttons.borderRadius', 'button.radius');
|
package/dist/persistence.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type BuilderSettings } from './builder-settings.ts';
|
|
2
2
|
type JsonRecord = Record<string, unknown>;
|
|
3
3
|
export declare function extractPersistedBuilderSettings(input: unknown): BuilderSettings | null;
|
|
4
|
+
/**
|
|
5
|
+
* Single read boundary for builder v2 state: strict extract first, then legacy migration.
|
|
6
|
+
* Strips invalid keys such as nested `theme.typography` while preserving style_slots and pages.
|
|
7
|
+
*/
|
|
8
|
+
export declare function coercePersistedBuilderSettings(input: unknown): BuilderSettings | null;
|
|
9
|
+
/**
|
|
10
|
+
* Coerces builder v2 fields for storefront export while preserving non-v2 siblings (seo, appearance, …).
|
|
11
|
+
*/
|
|
12
|
+
export declare function exportCoercedBuilderSettingsBlob(builderSettingsBlob: unknown): JsonRecord | null;
|
|
4
13
|
export declare function sanitizeBuilderSettingsState(settings: BuilderSettings): BuilderSettings;
|
|
5
14
|
export declare function mergeBuilderSettingsIntoThemeSettings(currentSettings: unknown, builderSettings: BuilderSettings): JsonRecord;
|
|
6
15
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AAQ/B,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAmB1C,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAYtF;AA0BD;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAkDrF;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,mBAAmB,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAgBhG;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CASvF;AAaD,wBAAgB,qCAAqC,CACnD,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,eAAe,GAC/B,UAAU,CAaZ"}
|
package/dist/persistence.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BuilderSettingsSchema, } from "./builder-settings.js";
|
|
2
|
+
import { mapLegacyNestedThemeTypographyToStyleSlots, mapLegacyTokenOverridesToStyleSlots, migrateLegacyBuilderSettings, } from "./migrations.js";
|
|
2
3
|
const RESERVED_THEME_CONTENT_KEYS = new Set(['layout']);
|
|
3
4
|
function isRecord(value) {
|
|
4
5
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -24,6 +25,85 @@ export function extractPersistedBuilderSettings(input) {
|
|
|
24
25
|
const parsedNested = BuilderSettingsSchema.safeParse(pickBuilderSettingsFields(input.builder_settings));
|
|
25
26
|
return parsedNested.success ? sanitizeBuilderSettingsState(parsedNested.data) : null;
|
|
26
27
|
}
|
|
28
|
+
function parseBuilderSettingsRevision(input) {
|
|
29
|
+
return typeof input === 'number' && Number.isInteger(input) && input >= 0 ? input : 0;
|
|
30
|
+
}
|
|
31
|
+
function unwrapBuilderSettingsRecord(input) {
|
|
32
|
+
if (!isRecord(input)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (isRecord(input.builder_settings)) {
|
|
36
|
+
return input.builder_settings;
|
|
37
|
+
}
|
|
38
|
+
if ('version' in input || 'revision' in input || 'theme' in input) {
|
|
39
|
+
return input;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function readStyleSlotsRecord(theme) {
|
|
44
|
+
return isRecord(theme.style_slots) ? theme.style_slots : {};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Single read boundary for builder v2 state: strict extract first, then legacy migration.
|
|
48
|
+
* Strips invalid keys such as nested `theme.typography` while preserving style_slots and pages.
|
|
49
|
+
*/
|
|
50
|
+
export function coercePersistedBuilderSettings(input) {
|
|
51
|
+
const extracted = extractPersistedBuilderSettings(input);
|
|
52
|
+
if (extracted) {
|
|
53
|
+
return extracted;
|
|
54
|
+
}
|
|
55
|
+
if (isRecord(input) && isRecord(input.builder_settings)) {
|
|
56
|
+
const nestedExtracted = extractPersistedBuilderSettings(input.builder_settings);
|
|
57
|
+
if (nestedExtracted) {
|
|
58
|
+
return nestedExtracted;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const blob = unwrapBuilderSettingsRecord(input);
|
|
62
|
+
if (!blob) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const theme = isRecord(blob.theme) ? blob.theme : {};
|
|
66
|
+
const tokensOverride = isRecord(theme.tokens_override) ? theme.tokens_override : {};
|
|
67
|
+
const styleSlots = mapLegacyNestedThemeTypographyToStyleSlots(theme, {
|
|
68
|
+
...mapLegacyTokenOverridesToStyleSlots(tokensOverride),
|
|
69
|
+
...readStyleSlotsRecord(theme),
|
|
70
|
+
});
|
|
71
|
+
const migrated = migrateLegacyBuilderSettings({
|
|
72
|
+
theme: {
|
|
73
|
+
content: isRecord(theme.content) ? theme.content : {},
|
|
74
|
+
layout: isRecord(theme.layout) ? theme.layout : {},
|
|
75
|
+
tokens_override: tokensOverride,
|
|
76
|
+
style_slots: styleSlots,
|
|
77
|
+
},
|
|
78
|
+
}, parseBuilderSettingsRevision(blob.revision));
|
|
79
|
+
const merged = BuilderSettingsSchema.safeParse({
|
|
80
|
+
...migrated,
|
|
81
|
+
theme: {
|
|
82
|
+
...migrated.theme,
|
|
83
|
+
pages: Array.isArray(theme.pages) ? theme.pages : migrated.theme.pages,
|
|
84
|
+
terms: isRecord(theme.terms) ? theme.terms : migrated.theme.terms,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
return merged.success ? sanitizeBuilderSettingsState(merged.data) : migrated;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Coerces builder v2 fields for storefront export while preserving non-v2 siblings (seo, appearance, …).
|
|
91
|
+
*/
|
|
92
|
+
export function exportCoercedBuilderSettingsBlob(builderSettingsBlob) {
|
|
93
|
+
if (!isRecord(builderSettingsBlob)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const coerced = coercePersistedBuilderSettings(builderSettingsBlob);
|
|
97
|
+
if (!coerced) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
...builderSettingsBlob,
|
|
102
|
+
version: coerced.version,
|
|
103
|
+
revision: coerced.revision,
|
|
104
|
+
theme: coerced.theme,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
27
107
|
export function sanitizeBuilderSettingsState(settings) {
|
|
28
108
|
const content = sanitizeThemeContent(settings.theme.content);
|
|
29
109
|
return BuilderSettingsSchema.parse({
|
|
@@ -66,6 +66,24 @@ export declare const PreviewApplyStateMessageSchema: z.ZodObject<{
|
|
|
66
66
|
}, z.core.$strict>;
|
|
67
67
|
}, z.core.$strict>;
|
|
68
68
|
}, z.core.$strict>;
|
|
69
|
+
export declare const EdgeBlockRenderModeSchema: z.ZodLiteral<"edge-block-engine">;
|
|
70
|
+
export type EdgeBlockRenderMode = z.infer<typeof EdgeBlockRenderModeSchema>;
|
|
71
|
+
export declare const PreviewBlockHtmlPatchSchema: z.ZodObject<{
|
|
72
|
+
blockId: z.ZodString;
|
|
73
|
+
html: z.ZodString;
|
|
74
|
+
}, z.core.$strict>;
|
|
75
|
+
export type PreviewBlockHtmlPatch = z.infer<typeof PreviewBlockHtmlPatchSchema>;
|
|
76
|
+
export declare const PreviewApplyBlockHtmlMessageSchema: z.ZodObject<{
|
|
77
|
+
type: z.ZodLiteral<"APPLY_BLOCK_HTML">;
|
|
78
|
+
revision: z.ZodNumber;
|
|
79
|
+
pageId: z.ZodString;
|
|
80
|
+
sourceRevision: z.ZodString;
|
|
81
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
82
|
+
blocks: z.ZodArray<z.ZodObject<{
|
|
83
|
+
blockId: z.ZodString;
|
|
84
|
+
html: z.ZodString;
|
|
85
|
+
}, z.core.$strict>>;
|
|
86
|
+
}, z.core.$strict>;
|
|
69
87
|
export declare const PreviewReloadMessageSchema: z.ZodObject<{
|
|
70
88
|
type: z.ZodLiteral<"RELOAD">;
|
|
71
89
|
revision: z.ZodNumber;
|
|
@@ -164,6 +182,16 @@ export declare const PreviewMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
164
182
|
}, z.core.$strict>>;
|
|
165
183
|
}, z.core.$strict>;
|
|
166
184
|
}, z.core.$strict>;
|
|
185
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
186
|
+
type: z.ZodLiteral<"APPLY_BLOCK_HTML">;
|
|
187
|
+
revision: z.ZodNumber;
|
|
188
|
+
pageId: z.ZodString;
|
|
189
|
+
sourceRevision: z.ZodString;
|
|
190
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
191
|
+
blocks: z.ZodArray<z.ZodObject<{
|
|
192
|
+
blockId: z.ZodString;
|
|
193
|
+
html: z.ZodString;
|
|
194
|
+
}, z.core.$strict>>;
|
|
167
195
|
}, z.core.$strict>, z.ZodObject<{
|
|
168
196
|
type: z.ZodLiteral<"RELOAD">;
|
|
169
197
|
revision: z.ZodNumber;
|
|
@@ -209,14 +237,28 @@ export declare const PreviewBootstrapOkResponseSchema: z.ZodObject<{
|
|
|
209
237
|
shopId: z.ZodString;
|
|
210
238
|
artifactStale: z.ZodOptional<z.ZodBoolean>;
|
|
211
239
|
}, z.core.$strict>;
|
|
240
|
+
export declare const PreviewReadyHealthSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
241
|
+
reactMounted: z.ZodLiteral<true>;
|
|
242
|
+
builderRuntimeProvider: z.ZodLiteral<true>;
|
|
243
|
+
protocolVersion: z.ZodLiteral<2>;
|
|
244
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
245
|
+
edgeBlockEngine: z.ZodLiteral<true>;
|
|
246
|
+
blockHtmlReconcile: z.ZodLiteral<true>;
|
|
247
|
+
protocolVersion: z.ZodLiteral<3>;
|
|
248
|
+
}, z.core.$strict>], "protocolVersion">;
|
|
249
|
+
export type PreviewReadyHealth = z.infer<typeof PreviewReadyHealthSchema>;
|
|
212
250
|
export declare const PreviewReadyResponseSchema: z.ZodObject<{
|
|
213
251
|
type: z.ZodLiteral<"READY">;
|
|
214
252
|
revision: z.ZodNumber;
|
|
215
|
-
health: z.ZodOptional<z.ZodObject<{
|
|
253
|
+
health: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
216
254
|
reactMounted: z.ZodLiteral<true>;
|
|
217
255
|
builderRuntimeProvider: z.ZodLiteral<true>;
|
|
218
256
|
protocolVersion: z.ZodLiteral<2>;
|
|
219
|
-
}, z.core.$strict
|
|
257
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
258
|
+
edgeBlockEngine: z.ZodLiteral<true>;
|
|
259
|
+
blockHtmlReconcile: z.ZodLiteral<true>;
|
|
260
|
+
protocolVersion: z.ZodLiteral<3>;
|
|
261
|
+
}, z.core.$strict>], "protocolVersion">>;
|
|
220
262
|
}, z.core.$strict>;
|
|
221
263
|
export declare const PreviewAppliedResponseSchema: z.ZodObject<{
|
|
222
264
|
type: z.ZodLiteral<"APPLIED">;
|
|
@@ -227,6 +269,26 @@ export declare const PreviewApplyFailedResponseSchema: z.ZodObject<{
|
|
|
227
269
|
revision: z.ZodNumber;
|
|
228
270
|
error: z.ZodString;
|
|
229
271
|
}, z.core.$strict>;
|
|
272
|
+
export declare const PreviewBlockHtmlAppliedResponseSchema: z.ZodObject<{
|
|
273
|
+
type: z.ZodLiteral<"BLOCK_HTML_APPLIED">;
|
|
274
|
+
revision: z.ZodNumber;
|
|
275
|
+
pageId: z.ZodString;
|
|
276
|
+
sourceRevision: z.ZodString;
|
|
277
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
278
|
+
blocks: z.ZodArray<z.ZodObject<{
|
|
279
|
+
blockId: z.ZodString;
|
|
280
|
+
html: z.ZodString;
|
|
281
|
+
}, z.core.$strict>>;
|
|
282
|
+
}, z.core.$strict>;
|
|
283
|
+
export declare const PreviewBlockHtmlFailedResponseSchema: z.ZodObject<{
|
|
284
|
+
type: z.ZodLiteral<"BLOCK_HTML_FAILED">;
|
|
285
|
+
revision: z.ZodNumber;
|
|
286
|
+
pageId: z.ZodString;
|
|
287
|
+
sourceRevision: z.ZodOptional<z.ZodString>;
|
|
288
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
289
|
+
blockIds: z.ZodArray<z.ZodString>;
|
|
290
|
+
error: z.ZodString;
|
|
291
|
+
}, z.core.$strict>;
|
|
230
292
|
export declare const PreviewElementClickedResponseSchema: z.ZodObject<{
|
|
231
293
|
type: z.ZodLiteral<"ELEMENT_CLICKED">;
|
|
232
294
|
revision: z.ZodOptional<z.ZodNumber>;
|
|
@@ -351,11 +413,15 @@ export declare const PreviewResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
351
413
|
}, z.core.$strict>, z.ZodObject<{
|
|
352
414
|
type: z.ZodLiteral<"READY">;
|
|
353
415
|
revision: z.ZodNumber;
|
|
354
|
-
health: z.ZodOptional<z.ZodObject<{
|
|
416
|
+
health: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
355
417
|
reactMounted: z.ZodLiteral<true>;
|
|
356
418
|
builderRuntimeProvider: z.ZodLiteral<true>;
|
|
357
419
|
protocolVersion: z.ZodLiteral<2>;
|
|
358
|
-
}, z.core.$strict
|
|
420
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
421
|
+
edgeBlockEngine: z.ZodLiteral<true>;
|
|
422
|
+
blockHtmlReconcile: z.ZodLiteral<true>;
|
|
423
|
+
protocolVersion: z.ZodLiteral<3>;
|
|
424
|
+
}, z.core.$strict>], "protocolVersion">>;
|
|
359
425
|
}, z.core.$strict>, z.ZodObject<{
|
|
360
426
|
type: z.ZodLiteral<"APPLIED">;
|
|
361
427
|
revision: z.ZodNumber;
|
|
@@ -363,6 +429,24 @@ export declare const PreviewResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
363
429
|
type: z.ZodLiteral<"APPLY_FAILED">;
|
|
364
430
|
revision: z.ZodNumber;
|
|
365
431
|
error: z.ZodString;
|
|
432
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
433
|
+
type: z.ZodLiteral<"BLOCK_HTML_APPLIED">;
|
|
434
|
+
revision: z.ZodNumber;
|
|
435
|
+
pageId: z.ZodString;
|
|
436
|
+
sourceRevision: z.ZodString;
|
|
437
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
438
|
+
blocks: z.ZodArray<z.ZodObject<{
|
|
439
|
+
blockId: z.ZodString;
|
|
440
|
+
html: z.ZodString;
|
|
441
|
+
}, z.core.$strict>>;
|
|
442
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
443
|
+
type: z.ZodLiteral<"BLOCK_HTML_FAILED">;
|
|
444
|
+
revision: z.ZodNumber;
|
|
445
|
+
pageId: z.ZodString;
|
|
446
|
+
sourceRevision: z.ZodOptional<z.ZodString>;
|
|
447
|
+
renderMode: z.ZodLiteral<"edge-block-engine">;
|
|
448
|
+
blockIds: z.ZodArray<z.ZodString>;
|
|
449
|
+
error: z.ZodString;
|
|
366
450
|
}, z.core.$strict>, z.ZodObject<{
|
|
367
451
|
type: z.ZodLiteral<"ELEMENT_CLICKED">;
|
|
368
452
|
revision: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-protocol.d.ts","sourceRoot":"","sources":["../src/preview-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAG5B,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;kBAYxB,CAAC;AACZ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAMhC,CAAC;AAEZ,eAAO,MAAM,0BAA0B;;;;;;;kBAM5B,CAAC;AAEZ,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;kBAMnC,CAAC;AAEZ,eAAO,MAAM,gCAAgC;;kBAIlC,CAAC;AAEZ,eAAO,MAAM,qBAAqB;;;EAA8B,CAAC;AACjE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC;;;;;;kBAKxC,CAAC;AAEZ,eAAO,MAAM,oBAAoB
|
|
1
|
+
{"version":3,"file":"preview-protocol.d.ts","sourceRoot":"","sources":["../src/preview-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAG5B,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;kBAYxB,CAAC;AACZ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAMhC,CAAC;AAEZ,eAAO,MAAM,yBAAyB,mCAAiC,CAAC;AACxE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,2BAA2B;;;kBAK7B,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,kCAAkC;;;;;;;;;;kBASpC,CAAC;AAEZ,eAAO,MAAM,0BAA0B;;;;;;;kBAM5B,CAAC;AAEZ,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;kBAMnC,CAAC;AAEZ,eAAO,MAAM,gCAAgC;;kBAIlC,CAAC;AAEZ,eAAO,MAAM,qBAAqB;;;EAA8B,CAAC;AACjE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC;;;;;;kBAKxC,CAAC;AAEZ,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAO/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,gCAAgC;;;;;;kBAQlC,CAAC;AAEZ,eAAO,MAAM,wBAAwB;;;;;;;;uCAenC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;kBAM5B,CAAC;AAEZ,eAAO,MAAM,4BAA4B;;;kBAK9B,CAAC;AAEZ,eAAO,MAAM,gCAAgC;;;;kBAMlC,CAAC;AAEZ,eAAO,MAAM,qCAAqC;;;;;;;;;;kBASvC,CAAC;AAEZ,eAAO,MAAM,oCAAoC;;;;;;;;kBAUtC,CAAC;AAEZ,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;kBAMrC,CAAC;AAEZ,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0B5B,CAAC;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;kBAOnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,8BAA8B;;;;;;;;;;kBAOhC,CAAC;AAEZ;;;;GAIG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;kBAOpC,CAAC;AAEZ;;;;GAIG;AACH,eAAO,MAAM,qCAAqC;;;;;;kBAQvC,CAAC;AAEZ,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAYhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
package/dist/preview-protocol.js
CHANGED
|
@@ -20,6 +20,23 @@ export const PreviewApplyStateMessageSchema = z
|
|
|
20
20
|
state: BuilderSettingsSchema,
|
|
21
21
|
})
|
|
22
22
|
.strict();
|
|
23
|
+
export const EdgeBlockRenderModeSchema = z.literal('edge-block-engine');
|
|
24
|
+
export const PreviewBlockHtmlPatchSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
blockId: z.string().min(1),
|
|
27
|
+
html: z.string().min(1),
|
|
28
|
+
})
|
|
29
|
+
.strict();
|
|
30
|
+
export const PreviewApplyBlockHtmlMessageSchema = z
|
|
31
|
+
.object({
|
|
32
|
+
type: z.literal('APPLY_BLOCK_HTML'),
|
|
33
|
+
revision: z.number().int().nonnegative(),
|
|
34
|
+
pageId: z.string().min(1),
|
|
35
|
+
sourceRevision: z.string().min(1),
|
|
36
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
37
|
+
blocks: z.array(PreviewBlockHtmlPatchSchema).min(1),
|
|
38
|
+
})
|
|
39
|
+
.strict();
|
|
23
40
|
export const PreviewReloadMessageSchema = z
|
|
24
41
|
.object({
|
|
25
42
|
type: z.literal('RELOAD'),
|
|
@@ -54,6 +71,7 @@ export const PreviewSetInteractionModeMessageSchema = z
|
|
|
54
71
|
.strict();
|
|
55
72
|
export const PreviewMessageSchema = z.discriminatedUnion('type', [
|
|
56
73
|
PreviewApplyStateMessageSchema,
|
|
74
|
+
PreviewApplyBlockHtmlMessageSchema,
|
|
57
75
|
PreviewReloadMessageSchema,
|
|
58
76
|
PreviewSelectElementMessageSchema,
|
|
59
77
|
PreviewRequestReadyMessageSchema,
|
|
@@ -68,18 +86,27 @@ export const PreviewBootstrapOkResponseSchema = z
|
|
|
68
86
|
artifactStale: z.boolean().optional(),
|
|
69
87
|
})
|
|
70
88
|
.strict();
|
|
71
|
-
export const
|
|
72
|
-
|
|
73
|
-
type: z.literal('READY'),
|
|
74
|
-
revision: z.number().int().nonnegative(),
|
|
75
|
-
health: z
|
|
89
|
+
export const PreviewReadyHealthSchema = z.discriminatedUnion('protocolVersion', [
|
|
90
|
+
z
|
|
76
91
|
.object({
|
|
77
92
|
reactMounted: z.literal(true),
|
|
78
93
|
builderRuntimeProvider: z.literal(true),
|
|
79
94
|
protocolVersion: z.literal(2),
|
|
80
95
|
})
|
|
81
|
-
.strict()
|
|
82
|
-
|
|
96
|
+
.strict(),
|
|
97
|
+
z
|
|
98
|
+
.object({
|
|
99
|
+
edgeBlockEngine: z.literal(true),
|
|
100
|
+
blockHtmlReconcile: z.literal(true),
|
|
101
|
+
protocolVersion: z.literal(3),
|
|
102
|
+
})
|
|
103
|
+
.strict(),
|
|
104
|
+
]);
|
|
105
|
+
export const PreviewReadyResponseSchema = z
|
|
106
|
+
.object({
|
|
107
|
+
type: z.literal('READY'),
|
|
108
|
+
revision: z.number().int().nonnegative(),
|
|
109
|
+
health: PreviewReadyHealthSchema.optional(),
|
|
83
110
|
})
|
|
84
111
|
.strict();
|
|
85
112
|
export const PreviewAppliedResponseSchema = z
|
|
@@ -95,6 +122,27 @@ export const PreviewApplyFailedResponseSchema = z
|
|
|
95
122
|
error: z.string().min(1),
|
|
96
123
|
})
|
|
97
124
|
.strict();
|
|
125
|
+
export const PreviewBlockHtmlAppliedResponseSchema = z
|
|
126
|
+
.object({
|
|
127
|
+
type: z.literal('BLOCK_HTML_APPLIED'),
|
|
128
|
+
revision: z.number().int().nonnegative(),
|
|
129
|
+
pageId: z.string().min(1),
|
|
130
|
+
sourceRevision: z.string().min(1),
|
|
131
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
132
|
+
blocks: z.array(PreviewBlockHtmlPatchSchema).min(1),
|
|
133
|
+
})
|
|
134
|
+
.strict();
|
|
135
|
+
export const PreviewBlockHtmlFailedResponseSchema = z
|
|
136
|
+
.object({
|
|
137
|
+
type: z.literal('BLOCK_HTML_FAILED'),
|
|
138
|
+
revision: z.number().int().nonnegative(),
|
|
139
|
+
pageId: z.string().min(1),
|
|
140
|
+
sourceRevision: z.string().min(1).optional(),
|
|
141
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
142
|
+
blockIds: z.array(z.string().min(1)).min(1),
|
|
143
|
+
error: z.string().min(1),
|
|
144
|
+
})
|
|
145
|
+
.strict();
|
|
98
146
|
export const PreviewElementClickedResponseSchema = z
|
|
99
147
|
.object({
|
|
100
148
|
type: z.literal('ELEMENT_CLICKED'),
|
|
@@ -183,6 +231,8 @@ export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
|
183
231
|
PreviewReadyResponseSchema,
|
|
184
232
|
PreviewAppliedResponseSchema,
|
|
185
233
|
PreviewApplyFailedResponseSchema,
|
|
234
|
+
PreviewBlockHtmlAppliedResponseSchema,
|
|
235
|
+
PreviewBlockHtmlFailedResponseSchema,
|
|
186
236
|
PreviewElementClickedResponseSchema,
|
|
187
237
|
PreviewErrorResponseSchema,
|
|
188
238
|
PreviewBlockRectResponseSchema,
|
|
@@ -44,7 +44,7 @@ export function buildPlainInitialDataScript(initialData) {
|
|
|
44
44
|
export function buildWrappedStorefrontInitialDataScript(serialized, deployedThemeEntryPathPattern) {
|
|
45
45
|
return [
|
|
46
46
|
'<!--shoppex-initial-data:start--><script>(function(){',
|
|
47
|
-
'if(typeof window!=="undefined"){var path=window.location.pathname||"";',
|
|
47
|
+
'if(typeof window!=="undefined"){window.__SHOPPEX_DEPLOYED_THEME_ARTIFACT__=true;var path=window.location.pathname||"";',
|
|
48
48
|
`if(${deployedThemeEntryPathPattern}.test(path)){window.__SHOPPEX_DEPLOYED_THEME_ARTIFACT_PATH__=path;window.history.replaceState(window.history.state,"","/"+window.location.search+window.location.hash);}}`,
|
|
49
49
|
`window.__SHOPPEX_INITIAL__=${serialized};})();</script><!--shoppex-initial-data:end-->`,
|
|
50
50
|
].join('');
|
package/dist/theme-manifest.d.ts
CHANGED
|
@@ -252,13 +252,13 @@ export declare const ManifestBlockSchema: z.ZodObject<{
|
|
|
252
252
|
number: "number";
|
|
253
253
|
boolean: "boolean";
|
|
254
254
|
link: "link";
|
|
255
|
+
product: "product";
|
|
255
256
|
text: "text";
|
|
256
257
|
richtext: "richtext";
|
|
257
258
|
image: "image";
|
|
258
259
|
range: "range";
|
|
259
260
|
select: "select";
|
|
260
261
|
color: "color";
|
|
261
|
-
product: "product";
|
|
262
262
|
}>;
|
|
263
263
|
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
264
264
|
label: z.ZodString;
|
|
@@ -585,13 +585,13 @@ export declare const ThemeManifestSchema: z.ZodObject<{
|
|
|
585
585
|
number: "number";
|
|
586
586
|
boolean: "boolean";
|
|
587
587
|
link: "link";
|
|
588
|
+
product: "product";
|
|
588
589
|
text: "text";
|
|
589
590
|
richtext: "richtext";
|
|
590
591
|
image: "image";
|
|
591
592
|
range: "range";
|
|
592
593
|
select: "select";
|
|
593
594
|
color: "color";
|
|
594
|
-
product: "product";
|
|
595
595
|
}>;
|
|
596
596
|
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
597
597
|
label: z.ZodString;
|
package/dist/theme-schemes.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export declare const PUBLIC_BUILDER_THEME_SCHEMES: readonly ["default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "clean-minimal"];
|
|
1
|
+
export declare const PUBLIC_BUILDER_THEME_SCHEMES: readonly ["default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "vortex", "clean-minimal"];
|
|
2
2
|
export declare const STARTER_BUILDER_THEME_SCHEMES: readonly ["blank"];
|
|
3
|
-
export declare const BUILDER_READY_THEME_SCHEMES: readonly ["blank", "default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "clean-minimal"];
|
|
3
|
+
export declare const BUILDER_READY_THEME_SCHEMES: readonly ["blank", "default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "vortex", "clean-minimal"];
|
|
4
4
|
export type PublicBuilderThemeScheme = (typeof PUBLIC_BUILDER_THEME_SCHEMES)[number];
|
|
5
5
|
export type StarterBuilderThemeScheme = (typeof STARTER_BUILDER_THEME_SCHEMES)[number];
|
|
6
6
|
export type BuilderReadyThemeScheme = (typeof BUILDER_READY_THEME_SCHEMES)[number];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-schemes.d.ts","sourceRoot":"","sources":["../src/theme-schemes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,
|
|
1
|
+
{"version":3,"file":"theme-schemes.d.ts","sourceRoot":"","sources":["../src/theme-schemes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,wHAW/B,CAAC;AAEX,eAAO,MAAM,6BAA6B,oBAAqB,CAAC;AAEhE,eAAO,MAAM,2BAA2B,iIAG9B,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AACrF,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;AACvF,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,wBAAwB,CAE3F;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,yBAAyB,CAE7F;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,uBAAuB,CAEzF"}
|
package/dist/theme-schemes.js
CHANGED
package/package.json
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
createBlockInstance,
|
|
14
14
|
createEmptyBuilderSettings,
|
|
15
15
|
convertLegacyThemeManifest,
|
|
16
|
+
coercePersistedBuilderSettings,
|
|
17
|
+
exportCoercedBuilderSettingsBlob,
|
|
16
18
|
extractPersistedBuilderSettings,
|
|
17
19
|
canonicalizeBuilderSettingsForManifestWithReport,
|
|
18
20
|
mergeBuilderSettingsIntoThemeSettings,
|
|
@@ -220,6 +222,52 @@ describe('@shoppex/builder-contracts', () => {
|
|
|
220
222
|
expect(extractPersistedBuilderSettings(persisted)).toEqual(settings);
|
|
221
223
|
});
|
|
222
224
|
|
|
225
|
+
test('coerces polluted v2 theme.typography into style_slots and strips invalid keys', () => {
|
|
226
|
+
const coerced = coercePersistedBuilderSettings({
|
|
227
|
+
version: 2,
|
|
228
|
+
revision: 9,
|
|
229
|
+
theme: {
|
|
230
|
+
content: {},
|
|
231
|
+
layout: {},
|
|
232
|
+
style_slots: {
|
|
233
|
+
'theme.typography.font.family': 'Manrope, sans-serif',
|
|
234
|
+
},
|
|
235
|
+
typography: {
|
|
236
|
+
font_family: 'Legacy Body',
|
|
237
|
+
heading_font: 'Legacy Heading',
|
|
238
|
+
},
|
|
239
|
+
pages: [],
|
|
240
|
+
terms: {},
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
expect(coerced).not.toBeNull();
|
|
245
|
+
expect(coerced?.theme.style_slots['theme.typography.font.family']).toBe('Manrope, sans-serif');
|
|
246
|
+
expect(coerced?.theme.style_slots['theme.typography.heading.font']).toBe('Legacy Heading');
|
|
247
|
+
expect(coerced?.theme).not.toHaveProperty('typography');
|
|
248
|
+
expect(() => BuilderSettingsSchema.parse(coerced)).not.toThrow();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('exportCoercedBuilderSettingsBlob preserves non-v2 siblings', () => {
|
|
252
|
+
const exported = exportCoercedBuilderSettingsBlob({
|
|
253
|
+
seo: { default_title: 'Keep this title' },
|
|
254
|
+
version: 2,
|
|
255
|
+
revision: 4,
|
|
256
|
+
theme: {
|
|
257
|
+
content: {},
|
|
258
|
+
layout: {},
|
|
259
|
+
style_slots: {},
|
|
260
|
+
typography: { font_family: 'Inter' },
|
|
261
|
+
pages: [],
|
|
262
|
+
terms: {},
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
expect(exported?.seo).toEqual({ default_title: 'Keep this title' });
|
|
267
|
+
expect(exported?.theme).not.toHaveProperty('typography');
|
|
268
|
+
expect(exported?.theme.style_slots['theme.typography.font.family']).toBe('Inter');
|
|
269
|
+
});
|
|
270
|
+
|
|
223
271
|
test('removes reserved content keys from persisted builder v2 state', () => {
|
|
224
272
|
const settings = BuilderSettingsSchema.parse({
|
|
225
273
|
...createEmptyBuilderSettings(5),
|
|
@@ -809,7 +857,7 @@ describe('@shoppex/builder-contracts', () => {
|
|
|
809
857
|
|
|
810
858
|
test('parses official theme manifests with transparent contact-form backgrounds', () => {
|
|
811
859
|
const repoRoot = join(import.meta.dir, '../../..');
|
|
812
|
-
for (const theme of ['default', 'nebula', 'classic', 'pulse', 'starlight', 'vault', 'phantom', 'apex']) {
|
|
860
|
+
for (const theme of ['default', 'nebula', 'classic', 'pulse', 'starlight', 'vault', 'phantom', 'apex', 'vortex']) {
|
|
813
861
|
const manifestPath = join(repoRoot, 'themes', theme, 'theme.manifest.json');
|
|
814
862
|
const raw = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
815
863
|
expect(ThemeManifestSchema.safeParse(raw).success, `${theme} manifest should validate`).toBe(true);
|
package/src/migrations.ts
CHANGED
|
@@ -110,6 +110,42 @@ export function applyManifestDefaultLayout(settings: BuilderSettings, manifest:
|
|
|
110
110
|
return BuilderSettingsSchema.parse(next);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
export function mapLegacyNestedThemeTypographyToStyleSlots(
|
|
114
|
+
theme: Record<string, unknown>,
|
|
115
|
+
baseSlots: StyleSlots = {},
|
|
116
|
+
): StyleSlots {
|
|
117
|
+
const slots: StyleSlots = { ...baseSlots };
|
|
118
|
+
const typography = theme.typography;
|
|
119
|
+
if (!isRecord(typography)) {
|
|
120
|
+
return slots;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const bodyFont = readLegacyTypographyString(typography, 'font_family', 'fontFamily');
|
|
124
|
+
const headingFont = readLegacyTypographyString(typography, 'heading_font', 'headingFont');
|
|
125
|
+
|
|
126
|
+
if (bodyFont && slots['theme.typography.font.family'] === undefined) {
|
|
127
|
+
slots['theme.typography.font.family'] = bodyFont;
|
|
128
|
+
}
|
|
129
|
+
if (headingFont && slots['theme.typography.heading.font'] === undefined) {
|
|
130
|
+
slots['theme.typography.heading.font'] = headingFont;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return slots;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function readLegacyTypographyString(
|
|
137
|
+
typography: Record<string, unknown>,
|
|
138
|
+
...keys: string[]
|
|
139
|
+
): string | null {
|
|
140
|
+
for (const key of keys) {
|
|
141
|
+
const value = typography[key];
|
|
142
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
143
|
+
return value.trim();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
113
149
|
export function mapLegacyTokenOverridesToStyleSlots(tokens: Record<string, unknown>): StyleSlots {
|
|
114
150
|
const slots: StyleSlots = {};
|
|
115
151
|
|
package/src/persistence.ts
CHANGED
|
@@ -2,6 +2,12 @@ import {
|
|
|
2
2
|
type BuilderSettings,
|
|
3
3
|
BuilderSettingsSchema,
|
|
4
4
|
} from './builder-settings.ts';
|
|
5
|
+
import {
|
|
6
|
+
mapLegacyNestedThemeTypographyToStyleSlots,
|
|
7
|
+
mapLegacyTokenOverridesToStyleSlots,
|
|
8
|
+
migrateLegacyBuilderSettings,
|
|
9
|
+
} from './migrations.ts';
|
|
10
|
+
import type { StyleSlots } from './style-slots.ts';
|
|
5
11
|
|
|
6
12
|
type JsonRecord = Record<string, unknown>;
|
|
7
13
|
const RESERVED_THEME_CONTENT_KEYS = new Set(['layout']);
|
|
@@ -36,6 +42,107 @@ export function extractPersistedBuilderSettings(input: unknown): BuilderSettings
|
|
|
36
42
|
return parsedNested.success ? sanitizeBuilderSettingsState(parsedNested.data) : null;
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
function parseBuilderSettingsRevision(input: unknown): number {
|
|
46
|
+
return typeof input === 'number' && Number.isInteger(input) && input >= 0 ? input : 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function unwrapBuilderSettingsRecord(input: unknown): JsonRecord | null {
|
|
50
|
+
if (!isRecord(input)) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (isRecord(input.builder_settings)) {
|
|
55
|
+
return input.builder_settings;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if ('version' in input || 'revision' in input || 'theme' in input) {
|
|
59
|
+
return input;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readStyleSlotsRecord(theme: JsonRecord): StyleSlots {
|
|
66
|
+
return isRecord(theme.style_slots) ? theme.style_slots as StyleSlots : {};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Single read boundary for builder v2 state: strict extract first, then legacy migration.
|
|
71
|
+
* Strips invalid keys such as nested `theme.typography` while preserving style_slots and pages.
|
|
72
|
+
*/
|
|
73
|
+
export function coercePersistedBuilderSettings(input: unknown): BuilderSettings | null {
|
|
74
|
+
const extracted = extractPersistedBuilderSettings(input);
|
|
75
|
+
if (extracted) {
|
|
76
|
+
return extracted;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isRecord(input) && isRecord(input.builder_settings)) {
|
|
80
|
+
const nestedExtracted = extractPersistedBuilderSettings(input.builder_settings);
|
|
81
|
+
if (nestedExtracted) {
|
|
82
|
+
return nestedExtracted;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const blob = unwrapBuilderSettingsRecord(input);
|
|
87
|
+
if (!blob) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const theme = isRecord(blob.theme) ? blob.theme : {};
|
|
92
|
+
const tokensOverride = isRecord(theme.tokens_override) ? theme.tokens_override : {};
|
|
93
|
+
const styleSlots = mapLegacyNestedThemeTypographyToStyleSlots(
|
|
94
|
+
theme,
|
|
95
|
+
{
|
|
96
|
+
...mapLegacyTokenOverridesToStyleSlots(tokensOverride),
|
|
97
|
+
...readStyleSlotsRecord(theme),
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const migrated = migrateLegacyBuilderSettings(
|
|
102
|
+
{
|
|
103
|
+
theme: {
|
|
104
|
+
content: isRecord(theme.content) ? theme.content : {},
|
|
105
|
+
layout: isRecord(theme.layout) ? theme.layout : {},
|
|
106
|
+
tokens_override: tokensOverride,
|
|
107
|
+
style_slots: styleSlots,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
parseBuilderSettingsRevision(blob.revision),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const merged = BuilderSettingsSchema.safeParse({
|
|
114
|
+
...migrated,
|
|
115
|
+
theme: {
|
|
116
|
+
...migrated.theme,
|
|
117
|
+
pages: Array.isArray(theme.pages) ? theme.pages : migrated.theme.pages,
|
|
118
|
+
terms: isRecord(theme.terms) ? theme.terms : migrated.theme.terms,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return merged.success ? sanitizeBuilderSettingsState(merged.data) : migrated;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Coerces builder v2 fields for storefront export while preserving non-v2 siblings (seo, appearance, …).
|
|
127
|
+
*/
|
|
128
|
+
export function exportCoercedBuilderSettingsBlob(builderSettingsBlob: unknown): JsonRecord | null {
|
|
129
|
+
if (!isRecord(builderSettingsBlob)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const coerced = coercePersistedBuilderSettings(builderSettingsBlob);
|
|
134
|
+
if (!coerced) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
...builderSettingsBlob,
|
|
140
|
+
version: coerced.version,
|
|
141
|
+
revision: coerced.revision,
|
|
142
|
+
theme: coerced.theme,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
39
146
|
export function sanitizeBuilderSettingsState(settings: BuilderSettings): BuilderSettings {
|
|
40
147
|
const content = sanitizeThemeContent(settings.theme.content);
|
|
41
148
|
return BuilderSettingsSchema.parse({
|
|
@@ -5,6 +5,44 @@ import {
|
|
|
5
5
|
} from './preview-protocol.ts';
|
|
6
6
|
|
|
7
7
|
describe('PreviewMessageSchema', () => {
|
|
8
|
+
it('accepts v3 block HTML apply messages', () => {
|
|
9
|
+
const parsed = PreviewMessageSchema.parse({
|
|
10
|
+
type: 'APPLY_BLOCK_HTML',
|
|
11
|
+
revision: 12,
|
|
12
|
+
pageId: 'product',
|
|
13
|
+
sourceRevision: 'theme-source-12',
|
|
14
|
+
renderMode: 'edge-block-engine',
|
|
15
|
+
blocks: [
|
|
16
|
+
{
|
|
17
|
+
blockId: 'product-form-1',
|
|
18
|
+
html: '<section data-builder-block="product-form-1">Updated</section>',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(parsed.type).toBe('APPLY_BLOCK_HTML');
|
|
24
|
+
if (parsed.type === 'APPLY_BLOCK_HTML') {
|
|
25
|
+
expect(parsed.blocks[0]?.blockId).toBe('product-form-1');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('rejects v3 block HTML apply messages without sourceRevision', () => {
|
|
30
|
+
const result = PreviewMessageSchema.safeParse({
|
|
31
|
+
type: 'APPLY_BLOCK_HTML',
|
|
32
|
+
revision: 12,
|
|
33
|
+
pageId: 'product',
|
|
34
|
+
renderMode: 'edge-block-engine',
|
|
35
|
+
blocks: [
|
|
36
|
+
{
|
|
37
|
+
blockId: 'product-form-1',
|
|
38
|
+
html: '<section data-builder-block="product-form-1">Updated</section>',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(result.success).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
8
46
|
it('accepts SET_INTERACTION_MODE with edit/preview', () => {
|
|
9
47
|
for (const mode of ['edit', 'preview'] as const) {
|
|
10
48
|
const parsed = PreviewMessageSchema.parse({
|
|
@@ -25,6 +63,58 @@ describe('PreviewMessageSchema', () => {
|
|
|
25
63
|
});
|
|
26
64
|
|
|
27
65
|
describe('PreviewResponseSchema', () => {
|
|
66
|
+
it('accepts READY health for edge block protocol v3', () => {
|
|
67
|
+
const parsed = PreviewResponseSchema.parse({
|
|
68
|
+
type: 'READY',
|
|
69
|
+
revision: 12,
|
|
70
|
+
health: {
|
|
71
|
+
edgeBlockEngine: true,
|
|
72
|
+
blockHtmlReconcile: true,
|
|
73
|
+
protocolVersion: 3,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(parsed.type).toBe('READY');
|
|
78
|
+
if (parsed.type === 'READY') {
|
|
79
|
+
expect(parsed.health?.protocolVersion).toBe(3);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('accepts v3 block HTML applied responses', () => {
|
|
84
|
+
const parsed = PreviewResponseSchema.parse({
|
|
85
|
+
type: 'BLOCK_HTML_APPLIED',
|
|
86
|
+
revision: 12,
|
|
87
|
+
pageId: 'product',
|
|
88
|
+
sourceRevision: 'theme-source-12',
|
|
89
|
+
renderMode: 'edge-block-engine',
|
|
90
|
+
blocks: [
|
|
91
|
+
{
|
|
92
|
+
blockId: 'footer-1',
|
|
93
|
+
html: '<footer data-builder-block="footer-1">Secure delivery</footer>',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(parsed.type).toBe('BLOCK_HTML_APPLIED');
|
|
99
|
+
if (parsed.type === 'BLOCK_HTML_APPLIED') {
|
|
100
|
+
expect(parsed.renderMode).toBe('edge-block-engine');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('accepts v3 block HTML failed responses', () => {
|
|
105
|
+
const parsed = PreviewResponseSchema.parse({
|
|
106
|
+
type: 'BLOCK_HTML_FAILED',
|
|
107
|
+
revision: 12,
|
|
108
|
+
pageId: 'product',
|
|
109
|
+
sourceRevision: 'theme-source-12',
|
|
110
|
+
renderMode: 'edge-block-engine',
|
|
111
|
+
blockIds: ['footer-1'],
|
|
112
|
+
error: 'Rendered block root does not match block id.',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(parsed.type).toBe('BLOCK_HTML_FAILED');
|
|
116
|
+
});
|
|
117
|
+
|
|
28
118
|
it('accepts BLOCK_RECT with rect', () => {
|
|
29
119
|
const parsed = PreviewResponseSchema.parse({
|
|
30
120
|
type: 'BLOCK_RECT',
|
package/src/preview-protocol.ts
CHANGED
|
@@ -24,6 +24,28 @@ export const PreviewApplyStateMessageSchema = z
|
|
|
24
24
|
})
|
|
25
25
|
.strict();
|
|
26
26
|
|
|
27
|
+
export const EdgeBlockRenderModeSchema = z.literal('edge-block-engine');
|
|
28
|
+
export type EdgeBlockRenderMode = z.infer<typeof EdgeBlockRenderModeSchema>;
|
|
29
|
+
|
|
30
|
+
export const PreviewBlockHtmlPatchSchema = z
|
|
31
|
+
.object({
|
|
32
|
+
blockId: z.string().min(1),
|
|
33
|
+
html: z.string().min(1),
|
|
34
|
+
})
|
|
35
|
+
.strict();
|
|
36
|
+
export type PreviewBlockHtmlPatch = z.infer<typeof PreviewBlockHtmlPatchSchema>;
|
|
37
|
+
|
|
38
|
+
export const PreviewApplyBlockHtmlMessageSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
type: z.literal('APPLY_BLOCK_HTML'),
|
|
41
|
+
revision: z.number().int().nonnegative(),
|
|
42
|
+
pageId: z.string().min(1),
|
|
43
|
+
sourceRevision: z.string().min(1),
|
|
44
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
45
|
+
blocks: z.array(PreviewBlockHtmlPatchSchema).min(1),
|
|
46
|
+
})
|
|
47
|
+
.strict();
|
|
48
|
+
|
|
27
49
|
export const PreviewReloadMessageSchema = z
|
|
28
50
|
.object({
|
|
29
51
|
type: z.literal('RELOAD'),
|
|
@@ -64,6 +86,7 @@ export const PreviewSetInteractionModeMessageSchema = z
|
|
|
64
86
|
|
|
65
87
|
export const PreviewMessageSchema = z.discriminatedUnion('type', [
|
|
66
88
|
PreviewApplyStateMessageSchema,
|
|
89
|
+
PreviewApplyBlockHtmlMessageSchema,
|
|
67
90
|
PreviewReloadMessageSchema,
|
|
68
91
|
PreviewSelectElementMessageSchema,
|
|
69
92
|
PreviewRequestReadyMessageSchema,
|
|
@@ -81,18 +104,29 @@ export const PreviewBootstrapOkResponseSchema = z
|
|
|
81
104
|
})
|
|
82
105
|
.strict();
|
|
83
106
|
|
|
107
|
+
export const PreviewReadyHealthSchema = z.discriminatedUnion('protocolVersion', [
|
|
108
|
+
z
|
|
109
|
+
.object({
|
|
110
|
+
reactMounted: z.literal(true),
|
|
111
|
+
builderRuntimeProvider: z.literal(true),
|
|
112
|
+
protocolVersion: z.literal(2),
|
|
113
|
+
})
|
|
114
|
+
.strict(),
|
|
115
|
+
z
|
|
116
|
+
.object({
|
|
117
|
+
edgeBlockEngine: z.literal(true),
|
|
118
|
+
blockHtmlReconcile: z.literal(true),
|
|
119
|
+
protocolVersion: z.literal(3),
|
|
120
|
+
})
|
|
121
|
+
.strict(),
|
|
122
|
+
]);
|
|
123
|
+
export type PreviewReadyHealth = z.infer<typeof PreviewReadyHealthSchema>;
|
|
124
|
+
|
|
84
125
|
export const PreviewReadyResponseSchema = z
|
|
85
126
|
.object({
|
|
86
127
|
type: z.literal('READY'),
|
|
87
128
|
revision: z.number().int().nonnegative(),
|
|
88
|
-
health:
|
|
89
|
-
.object({
|
|
90
|
-
reactMounted: z.literal(true),
|
|
91
|
-
builderRuntimeProvider: z.literal(true),
|
|
92
|
-
protocolVersion: z.literal(2),
|
|
93
|
-
})
|
|
94
|
-
.strict()
|
|
95
|
-
.optional(),
|
|
129
|
+
health: PreviewReadyHealthSchema.optional(),
|
|
96
130
|
})
|
|
97
131
|
.strict();
|
|
98
132
|
|
|
@@ -111,6 +145,29 @@ export const PreviewApplyFailedResponseSchema = z
|
|
|
111
145
|
})
|
|
112
146
|
.strict();
|
|
113
147
|
|
|
148
|
+
export const PreviewBlockHtmlAppliedResponseSchema = z
|
|
149
|
+
.object({
|
|
150
|
+
type: z.literal('BLOCK_HTML_APPLIED'),
|
|
151
|
+
revision: z.number().int().nonnegative(),
|
|
152
|
+
pageId: z.string().min(1),
|
|
153
|
+
sourceRevision: z.string().min(1),
|
|
154
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
155
|
+
blocks: z.array(PreviewBlockHtmlPatchSchema).min(1),
|
|
156
|
+
})
|
|
157
|
+
.strict();
|
|
158
|
+
|
|
159
|
+
export const PreviewBlockHtmlFailedResponseSchema = z
|
|
160
|
+
.object({
|
|
161
|
+
type: z.literal('BLOCK_HTML_FAILED'),
|
|
162
|
+
revision: z.number().int().nonnegative(),
|
|
163
|
+
pageId: z.string().min(1),
|
|
164
|
+
sourceRevision: z.string().min(1).optional(),
|
|
165
|
+
renderMode: EdgeBlockRenderModeSchema,
|
|
166
|
+
blockIds: z.array(z.string().min(1)).min(1),
|
|
167
|
+
error: z.string().min(1),
|
|
168
|
+
})
|
|
169
|
+
.strict();
|
|
170
|
+
|
|
114
171
|
export const PreviewElementClickedResponseSchema = z
|
|
115
172
|
.object({
|
|
116
173
|
type: z.literal('ELEMENT_CLICKED'),
|
|
@@ -206,6 +263,8 @@ export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
|
206
263
|
PreviewReadyResponseSchema,
|
|
207
264
|
PreviewAppliedResponseSchema,
|
|
208
265
|
PreviewApplyFailedResponseSchema,
|
|
266
|
+
PreviewBlockHtmlAppliedResponseSchema,
|
|
267
|
+
PreviewBlockHtmlFailedResponseSchema,
|
|
209
268
|
PreviewElementClickedResponseSchema,
|
|
210
269
|
PreviewErrorResponseSchema,
|
|
211
270
|
PreviewBlockRectResponseSchema,
|
|
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'bun:test';
|
|
|
2
2
|
import {
|
|
3
3
|
assertSingleInitialDataScript,
|
|
4
4
|
buildPlainInitialDataScript,
|
|
5
|
+
buildWrappedStorefrontInitialDataScript,
|
|
5
6
|
countInitialDataScripts,
|
|
6
7
|
findInitialDataPayload,
|
|
7
8
|
injectPreviewInitialData,
|
|
@@ -70,4 +71,11 @@ describe('storefront-initial-data-html', () => {
|
|
|
70
71
|
const stripped = stripAllInitialDataScripts(`${wrapped}${legacy}`);
|
|
71
72
|
expect(stripped).not.toContain('__SHOPPEX_INITIAL__');
|
|
72
73
|
});
|
|
74
|
+
|
|
75
|
+
it('marks wrapped initial data as a deployed theme artifact on friendly storefront paths', () => {
|
|
76
|
+
const script = buildWrappedStorefrontInitialDataScript('{"store":{"slug":"demo-shop"}}', /^\/themes-live\//);
|
|
77
|
+
|
|
78
|
+
expect(script).toContain('window.__SHOPPEX_DEPLOYED_THEME_ARTIFACT__=true');
|
|
79
|
+
expect(script).toContain('window.__SHOPPEX_INITIAL__={"store":{"slug":"demo-shop"}}');
|
|
80
|
+
});
|
|
73
81
|
});
|
|
@@ -66,7 +66,7 @@ export function buildWrappedStorefrontInitialDataScript(
|
|
|
66
66
|
): string {
|
|
67
67
|
return [
|
|
68
68
|
'<!--shoppex-initial-data:start--><script>(function(){',
|
|
69
|
-
'if(typeof window!=="undefined"){var path=window.location.pathname||"";',
|
|
69
|
+
'if(typeof window!=="undefined"){window.__SHOPPEX_DEPLOYED_THEME_ARTIFACT__=true;var path=window.location.pathname||"";',
|
|
70
70
|
`if(${deployedThemeEntryPathPattern}.test(path)){window.__SHOPPEX_DEPLOYED_THEME_ARTIFACT_PATH__=path;window.history.replaceState(window.history.state,"","/"+window.location.search+window.location.hash);}}`,
|
|
71
71
|
`window.__SHOPPEX_INITIAL__=${serialized};})();</script><!--shoppex-initial-data:end-->`,
|
|
72
72
|
].join('');
|