@shoppexio/builder-contracts 0.1.0 → 0.1.1
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/builder-contracts.test.js +71 -1
- package/dist/builder-settings.d.ts +9 -666
- package/dist/builder-settings.d.ts.map +1 -1
- package/dist/canonical-settings.d.ts +18 -0
- package/dist/canonical-settings.d.ts.map +1 -0
- package/dist/canonical-settings.js +106 -0
- package/dist/events.d.ts +35 -240
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +7 -0
- package/dist/fields.d.ts +169 -8
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +27 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/legacy-manifest.d.ts +11 -0
- package/dist/legacy-manifest.d.ts.map +1 -1
- package/dist/legacy-manifest.js +106 -16
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +50 -4
- package/dist/persistence.d.ts +7 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +58 -0
- package/dist/preview-boot.d.ts +68 -0
- package/dist/preview-boot.d.ts.map +1 -0
- package/dist/preview-boot.js +36 -0
- package/dist/preview-protocol.d.ts +227 -459
- package/dist/preview-protocol.d.ts.map +1 -1
- package/dist/preview-protocol.js +112 -0
- package/dist/preview-session-resolve.d.ts +115 -0
- package/dist/preview-session-resolve.d.ts.map +1 -0
- package/dist/preview-session-resolve.js +25 -0
- package/dist/preview-trusted-origins.d.ts +4 -0
- package/dist/preview-trusted-origins.d.ts.map +1 -0
- package/dist/preview-trusted-origins.js +26 -0
- package/dist/storefront-initial-data-html.d.ts +17 -0
- package/dist/storefront-initial-data-html.d.ts.map +1 -0
- package/dist/storefront-initial-data-html.js +83 -0
- package/dist/style-slots.d.ts +49 -151
- package/dist/style-slots.d.ts.map +1 -1
- package/dist/style-slots.js +75 -29
- package/dist/theme-manifest.d.ts +229 -454
- package/dist/theme-manifest.d.ts.map +1 -1
- package/dist/theme-manifest.js +92 -0
- package/dist/theme-schemes.d.ts +10 -0
- package/dist/theme-schemes.d.ts.map +1 -0
- package/dist/theme-schemes.js +24 -0
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +18 -9
- package/package.json +43 -1
- package/src/builder-contracts.test.ts +398 -3
- package/src/canonical-settings.ts +156 -0
- package/src/events.ts +8 -0
- package/src/fields.ts +30 -0
- package/src/index.ts +7 -0
- package/src/legacy-manifest.ts +107 -16
- package/src/migrations.ts +65 -4
- package/src/persistence.ts +77 -0
- package/src/preview-boot.ts +47 -0
- package/src/preview-protocol.test.ts +132 -0
- package/src/preview-protocol.ts +122 -0
- package/src/preview-session-resolve.ts +34 -0
- package/src/preview-trusted-origins.test.ts +24 -0
- package/src/preview-trusted-origins.ts +35 -0
- package/src/storefront-initial-data-html.test.ts +63 -0
- package/src/storefront-initial-data-html.ts +112 -0
- package/src/style-slots.ts +96 -31
- package/src/theme-manifest.ts +118 -1
- package/src/theme-schemes.ts +33 -0
- package/src/validation.ts +27 -10
package/dist/legacy-manifest.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from 'zod/v4';
|
|
2
2
|
import { BuilderFieldSchema } from "./fields.js";
|
|
3
3
|
import { ThemeManifestSchema } from "./theme-manifest.js";
|
|
4
|
+
import { StyleSlotDefaultsSchema } from "./style-slots.js";
|
|
4
5
|
const LegacyFieldOptionSchema = z
|
|
5
6
|
.object({
|
|
6
7
|
label: z.string().min(1),
|
|
@@ -71,6 +72,17 @@ export const LegacyThemeManifestSchema = z
|
|
|
71
72
|
id: z.string().min(1),
|
|
72
73
|
name: z.string().min(1),
|
|
73
74
|
version: z.string().min(1),
|
|
75
|
+
author: z.string().min(1).optional(),
|
|
76
|
+
description: z.string().min(1).optional(),
|
|
77
|
+
preview: z.string().min(1).optional(),
|
|
78
|
+
features: z.array(z.string().min(1)).optional(),
|
|
79
|
+
techStack: z.array(z.string().min(1)).optional(),
|
|
80
|
+
templates: z.array(z.string().min(1)).optional(),
|
|
81
|
+
createdAt: z.string().min(1).optional(),
|
|
82
|
+
demoUrl: z.string().min(1).optional(),
|
|
83
|
+
audience: z.string().min(1).optional(),
|
|
84
|
+
tags: z.array(z.string().min(1)).optional(),
|
|
85
|
+
hotfixPaths: z.array(z.string().min(1)).optional(),
|
|
74
86
|
presets: z.array(LegacyThemePresetSchema).optional(),
|
|
75
87
|
builder: z
|
|
76
88
|
.object({
|
|
@@ -82,6 +94,10 @@ export const LegacyThemeManifestSchema = z
|
|
|
82
94
|
})
|
|
83
95
|
.passthrough();
|
|
84
96
|
export function convertLegacyThemeManifest(input) {
|
|
97
|
+
const canonical = ThemeManifestSchema.safeParse(input);
|
|
98
|
+
if (canonical.success) {
|
|
99
|
+
return canonical.data;
|
|
100
|
+
}
|
|
85
101
|
const legacy = LegacyThemeManifestSchema.parse(input);
|
|
86
102
|
const blocks = Object.fromEntries(Object.entries(legacy.builder.blocks).map(([blockType, block]) => [
|
|
87
103
|
blockType,
|
|
@@ -112,6 +128,17 @@ export function convertLegacyThemeManifest(input) {
|
|
|
112
128
|
id: normalizeLegacyThemeId(legacy.id),
|
|
113
129
|
name: legacy.name,
|
|
114
130
|
version: legacy.version,
|
|
131
|
+
author: legacy.author,
|
|
132
|
+
description: legacy.description,
|
|
133
|
+
preview: legacy.preview,
|
|
134
|
+
features: legacy.features,
|
|
135
|
+
techStack: legacy.techStack,
|
|
136
|
+
templates: legacy.templates,
|
|
137
|
+
createdAt: legacy.createdAt,
|
|
138
|
+
demoUrl: legacy.demoUrl,
|
|
139
|
+
audience: legacy.audience,
|
|
140
|
+
tags: legacy.tags,
|
|
141
|
+
hotfixPaths: legacy.hotfixPaths,
|
|
115
142
|
pages: Object.fromEntries(legacy.builder.pages.map((page) => {
|
|
116
143
|
const syntheticBlockType = createSyntheticPageBlockType(page.id);
|
|
117
144
|
const hasSyntheticBlock = blocks[syntheticBlockType] !== undefined;
|
|
@@ -137,6 +164,8 @@ export function convertLegacyThemeManifest(input) {
|
|
|
137
164
|
blocks,
|
|
138
165
|
styleSlots: {},
|
|
139
166
|
presets: convertLegacyThemePresets(legacy.presets ?? []),
|
|
167
|
+
linkGroups: Array.isArray(legacy.builder.linkGroups) ? legacy.builder.linkGroups : [],
|
|
168
|
+
defaultLinkItems: isPlainObject(legacy.builder.defaultLinkItems) ? legacy.builder.defaultLinkItems : {},
|
|
140
169
|
};
|
|
141
170
|
return ThemeManifestSchema.parse(converted);
|
|
142
171
|
}
|
|
@@ -152,16 +181,20 @@ function createSyntheticPageBlockType(pageId) {
|
|
|
152
181
|
return `page-${normalizedPageId || 'custom'}`;
|
|
153
182
|
}
|
|
154
183
|
function convertLegacyThemePresets(presets) {
|
|
155
|
-
return Object.fromEntries(presets.map((preset) =>
|
|
156
|
-
preset.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
return Object.fromEntries(presets.map((preset) => {
|
|
185
|
+
const styleSlots = StyleSlotDefaultsSchema.parse(preset.overrides?.style_slots ?? preset.overrides?.styleSlots ?? {});
|
|
186
|
+
return [
|
|
187
|
+
preset.id,
|
|
188
|
+
{
|
|
189
|
+
label: preset.name ?? preset.label ?? preset.id,
|
|
190
|
+
description: preset.description,
|
|
191
|
+
preview: typeof preset.preview === 'string' ? preset.preview : undefined,
|
|
192
|
+
content: flattenContentRecord(preset.overrides?.content ?? {}),
|
|
193
|
+
layout: preset.overrides?.layout ?? {},
|
|
194
|
+
style_slots: styleSlots,
|
|
195
|
+
},
|
|
196
|
+
];
|
|
197
|
+
}));
|
|
165
198
|
}
|
|
166
199
|
function flattenContentRecord(content, prefix = '') {
|
|
167
200
|
const flattened = {};
|
|
@@ -180,21 +213,59 @@ function isPlainObject(value) {
|
|
|
180
213
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
181
214
|
}
|
|
182
215
|
function convertLegacyFields(fields, lists) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
216
|
+
// Auto-promote inline `type: 'list'` fields to first-class list entries so
|
|
217
|
+
// the migrator can emit list-shaped data without separately maintaining a
|
|
218
|
+
// `lists: []` block-level entry. The promoted list inherits its kind from
|
|
219
|
+
// the field path (e.g. `header.left_links` → kind `navLinks`).
|
|
220
|
+
const inlineLists = [];
|
|
221
|
+
const remainingFields = [];
|
|
222
|
+
for (const field of fields) {
|
|
223
|
+
if (field.type === 'list') {
|
|
224
|
+
inlineLists.push({
|
|
225
|
+
path: field.path,
|
|
226
|
+
label: field.label,
|
|
227
|
+
kind: inferListKindFromPath(field.path),
|
|
228
|
+
description: field.description,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
remainingFields.push(field);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const convertedFields = Object.fromEntries(remainingFields.map((field) => [field.path, convertLegacyField(field)]));
|
|
236
|
+
const allLists = [...inlineLists, ...lists];
|
|
237
|
+
const convertedLists = Object.fromEntries(allLists.map((list) => {
|
|
238
|
+
const inlineField = fields.find((f) => f.type === 'list' && f.path === list.path);
|
|
239
|
+
const candidate = {
|
|
187
240
|
type: 'list',
|
|
188
241
|
label: list.label,
|
|
189
242
|
description: list.description,
|
|
190
243
|
itemShape: createListItemShape(list.kind),
|
|
191
|
-
|
|
192
|
-
|
|
244
|
+
...(inlineField?.defaultValue !== undefined ? { defaultValue: inlineField.defaultValue } : {}),
|
|
245
|
+
};
|
|
246
|
+
return [list.path, candidate];
|
|
247
|
+
}));
|
|
193
248
|
return {
|
|
194
249
|
...convertedFields,
|
|
195
250
|
...convertedLists,
|
|
196
251
|
};
|
|
197
252
|
}
|
|
253
|
+
function inferListKindFromPath(path) {
|
|
254
|
+
const suffix = path.split('.').at(-1) ?? '';
|
|
255
|
+
if (/items$/i.test(suffix))
|
|
256
|
+
return 'faqItems';
|
|
257
|
+
if (/links$/i.test(suffix))
|
|
258
|
+
return 'navLinks';
|
|
259
|
+
if (/images$/i.test(suffix) || /gallery$/i.test(suffix))
|
|
260
|
+
return 'galleryItems';
|
|
261
|
+
if (/features$/i.test(suffix))
|
|
262
|
+
return 'featureItems';
|
|
263
|
+
if (/reviews$/i.test(suffix) || /testimonials$/i.test(suffix))
|
|
264
|
+
return 'reviewItems';
|
|
265
|
+
if (/announcements$/i.test(suffix))
|
|
266
|
+
return 'announcementItems';
|
|
267
|
+
return 'genericItems';
|
|
268
|
+
}
|
|
198
269
|
function convertLegacyField(field) {
|
|
199
270
|
const type = normalizeLegacyFieldType(field.type);
|
|
200
271
|
const base = {
|
|
@@ -265,6 +336,25 @@ function createListItemShape(kind) {
|
|
|
265
336
|
author: { type: 'text', label: 'Author' },
|
|
266
337
|
};
|
|
267
338
|
}
|
|
339
|
+
if (kind === 'navLinks') {
|
|
340
|
+
return {
|
|
341
|
+
text: { type: 'text', label: 'Text' },
|
|
342
|
+
link: { type: 'link', label: 'Link' },
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (kind === 'featureItems') {
|
|
346
|
+
return {
|
|
347
|
+
title: { type: 'text', label: 'Title' },
|
|
348
|
+
description: { type: 'richtext', label: 'Description' },
|
|
349
|
+
icon: { type: 'text', label: 'Icon' },
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
if (kind === 'announcementItems') {
|
|
353
|
+
return {
|
|
354
|
+
text: { type: 'text', label: 'Text' },
|
|
355
|
+
link: { type: 'link', label: 'Link' },
|
|
356
|
+
};
|
|
357
|
+
}
|
|
268
358
|
return {
|
|
269
359
|
title: { type: 'text', label: 'Title' },
|
|
270
360
|
body: { type: 'richtext', label: 'Body' },
|
package/dist/migrations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,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,CAkB7G;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"}
|
package/dist/migrations.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BUILDER_SETTINGS_VERSION, BuilderSettingsSchema, } from "./builder-settings.js";
|
|
2
|
+
import { sanitizeBuilderSettingsState } from "./persistence.js";
|
|
2
3
|
export function createEmptyBuilderSettings(revision = 0) {
|
|
3
4
|
return {
|
|
4
5
|
version: BUILDER_SETTINGS_VERSION,
|
|
@@ -31,7 +32,7 @@ export function migrateLegacyBuilderSettings(input, revision = 0) {
|
|
|
31
32
|
...mapLegacyTokenOverridesToStyleSlots(tokensOverride),
|
|
32
33
|
...(input.theme?.style_slots ?? {}),
|
|
33
34
|
};
|
|
34
|
-
return BuilderSettingsSchema.parse({
|
|
35
|
+
return sanitizeBuilderSettingsState(BuilderSettingsSchema.parse({
|
|
35
36
|
version: BUILDER_SETTINGS_VERSION,
|
|
36
37
|
revision,
|
|
37
38
|
theme: {
|
|
@@ -41,7 +42,7 @@ export function migrateLegacyBuilderSettings(input, revision = 0) {
|
|
|
41
42
|
pages: [],
|
|
42
43
|
terms: {},
|
|
43
44
|
},
|
|
44
|
-
});
|
|
45
|
+
}));
|
|
45
46
|
}
|
|
46
47
|
export function applyManifestDefaultLayout(settings, manifest) {
|
|
47
48
|
const next = cloneBuilderSettings(settings);
|
|
@@ -68,13 +69,33 @@ export function applyManifestDefaultLayout(settings, manifest) {
|
|
|
68
69
|
export function mapLegacyTokenOverridesToStyleSlots(tokens) {
|
|
69
70
|
const slots = {};
|
|
70
71
|
assignResponsiveNumber(tokens, slots, 'buttons.borderRadius', 'button.radius');
|
|
72
|
+
assignColor(tokens, slots, 'buttons.background', 'button.background');
|
|
73
|
+
assignColor(tokens, slots, 'buttons.foreground', 'button.foreground');
|
|
74
|
+
assignColor(tokens, slots, 'buttons.border', 'button.border');
|
|
75
|
+
assignFontWeight(tokens, slots, 'buttons.fontWeight', 'button.font.weight');
|
|
71
76
|
assignResponsiveNumber(tokens, slots, 'inputs.borderRadius', 'input.radius');
|
|
72
77
|
assignResponsiveNumber(tokens, slots, 'inputs.height', 'input.height');
|
|
78
|
+
assignColor(tokens, slots, 'inputs.border', 'input.border');
|
|
79
|
+
assignColor(tokens, slots, 'inputs.background', 'input.background');
|
|
80
|
+
assignColor(tokens, slots, 'inputs.foreground', 'input.foreground');
|
|
81
|
+
assignResponsiveNumber(tokens, slots, 'cards.borderRadius', 'card.radius');
|
|
82
|
+
assignColor(tokens, slots, 'cards.background', 'card.background');
|
|
83
|
+
assignColor(tokens, slots, 'cards.border', 'card.border');
|
|
84
|
+
assignResponsiveNumber(tokens, slots, 'sections.paddingY', 'section.padding.y');
|
|
85
|
+
assignResponsiveNumber(tokens, slots, 'sections.paddingX', 'section.padding.x');
|
|
86
|
+
assignResponsiveNumber(tokens, slots, 'container.width', 'container.width');
|
|
73
87
|
assignColor(tokens, slots, 'colors.primary', 'color.primary');
|
|
74
88
|
assignColor(tokens, slots, 'colors.accent', 'color.accent');
|
|
75
89
|
assignColor(tokens, slots, 'colors.background', 'color.background');
|
|
76
90
|
assignColor(tokens, slots, 'colors.foreground', 'color.foreground');
|
|
77
91
|
assignColor(tokens, slots, 'colors.muted', 'color.muted');
|
|
92
|
+
assignColor(tokens, slots, 'links.color', 'link.color');
|
|
93
|
+
assignFontWeight(tokens, slots, 'typography.headingWeight', 'typography.heading.weight');
|
|
94
|
+
assignResponsiveNumber(tokens, slots, 'typography.fontSize', 'typography.body.size');
|
|
95
|
+
assignResponsiveNumber(tokens, slots, 'typography.bodySize', 'typography.body.size');
|
|
96
|
+
assignString(tokens, slots, 'typography.fontFamily', 'theme.typography.font.family');
|
|
97
|
+
assignString(tokens, slots, 'typography.headingFont', 'theme.typography.heading.font');
|
|
98
|
+
assignResponsiveNumber(tokens, slots, 'header.height', 'theme.header.height');
|
|
78
99
|
return slots;
|
|
79
100
|
}
|
|
80
101
|
function normalizeLegacyLayout(layout) {
|
|
@@ -128,7 +149,7 @@ function isRecord(value) {
|
|
|
128
149
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
129
150
|
}
|
|
130
151
|
function assignResponsiveNumber(tokens, slots, tokenPath, slotId) {
|
|
131
|
-
const value = tokens
|
|
152
|
+
const value = readLegacyTokenPath(tokens, tokenPath);
|
|
132
153
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
133
154
|
slots[slotId] = { base: value };
|
|
134
155
|
return;
|
|
@@ -138,11 +159,36 @@ function assignResponsiveNumber(tokens, slots, tokenPath, slotId) {
|
|
|
138
159
|
}
|
|
139
160
|
}
|
|
140
161
|
function assignColor(tokens, slots, tokenPath, slotId) {
|
|
141
|
-
const value = tokens
|
|
162
|
+
const value = readLegacyTokenPath(tokens, tokenPath);
|
|
142
163
|
if (typeof value === 'string') {
|
|
143
164
|
slots[slotId] = value;
|
|
144
165
|
}
|
|
145
166
|
}
|
|
167
|
+
function assignString(tokens, slots, tokenPath, slotId) {
|
|
168
|
+
const value = readLegacyTokenPath(tokens, tokenPath);
|
|
169
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
170
|
+
slots[slotId] = value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function assignFontWeight(tokens, slots, tokenPath, slotId) {
|
|
174
|
+
const value = readLegacyTokenPath(tokens, tokenPath);
|
|
175
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
176
|
+
slots[slotId] = value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function readLegacyTokenPath(tokens, tokenPath) {
|
|
180
|
+
if (Object.prototype.hasOwnProperty.call(tokens, tokenPath)) {
|
|
181
|
+
return tokens[tokenPath];
|
|
182
|
+
}
|
|
183
|
+
let current = tokens;
|
|
184
|
+
for (const segment of tokenPath.split('.')) {
|
|
185
|
+
if (!isRecord(current)) {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
current = current[segment];
|
|
189
|
+
}
|
|
190
|
+
return current;
|
|
191
|
+
}
|
|
146
192
|
function isResponsiveNumber(value) {
|
|
147
193
|
if (!value || typeof value !== 'object') {
|
|
148
194
|
return false;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type BuilderSettings } from './builder-settings.ts';
|
|
2
|
+
type JsonRecord = Record<string, unknown>;
|
|
3
|
+
export declare function extractPersistedBuilderSettings(input: unknown): BuilderSettings | null;
|
|
4
|
+
export declare function sanitizeBuilderSettingsState(settings: BuilderSettings): BuilderSettings;
|
|
5
|
+
export declare function mergeBuilderSettingsIntoThemeSettings(currentSettings: unknown, builderSettings: BuilderSettings): JsonRecord;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAmB1C,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAYtF;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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { BuilderSettingsSchema, } from "./builder-settings.js";
|
|
2
|
+
const RESERVED_THEME_CONTENT_KEYS = new Set(['layout']);
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function pickBuilderSettingsFields(value) {
|
|
7
|
+
if (!isRecord(value)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
version: value.version,
|
|
12
|
+
revision: value.revision,
|
|
13
|
+
theme: value.theme,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function extractPersistedBuilderSettings(input) {
|
|
17
|
+
const parsedDirect = BuilderSettingsSchema.safeParse(pickBuilderSettingsFields(input));
|
|
18
|
+
if (parsedDirect.success) {
|
|
19
|
+
return sanitizeBuilderSettingsState(parsedDirect.data);
|
|
20
|
+
}
|
|
21
|
+
if (!isRecord(input)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const parsedNested = BuilderSettingsSchema.safeParse(pickBuilderSettingsFields(input.builder_settings));
|
|
25
|
+
return parsedNested.success ? sanitizeBuilderSettingsState(parsedNested.data) : null;
|
|
26
|
+
}
|
|
27
|
+
export function sanitizeBuilderSettingsState(settings) {
|
|
28
|
+
const content = sanitizeThemeContent(settings.theme.content);
|
|
29
|
+
return BuilderSettingsSchema.parse({
|
|
30
|
+
...settings,
|
|
31
|
+
theme: {
|
|
32
|
+
...settings.theme,
|
|
33
|
+
content,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function sanitizeThemeContent(content) {
|
|
38
|
+
const next = {};
|
|
39
|
+
for (const [key, value] of Object.entries(content)) {
|
|
40
|
+
if (RESERVED_THEME_CONTENT_KEYS.has(key)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
next[key] = value;
|
|
44
|
+
}
|
|
45
|
+
return next;
|
|
46
|
+
}
|
|
47
|
+
export function mergeBuilderSettingsIntoThemeSettings(currentSettings, builderSettings) {
|
|
48
|
+
const root = isRecord(currentSettings) ? { ...currentSettings } : {};
|
|
49
|
+
const currentBuilderSettings = isRecord(root.builder_settings) ? root.builder_settings : {};
|
|
50
|
+
const sanitizedBuilderSettings = sanitizeBuilderSettingsState(builderSettings);
|
|
51
|
+
root.builder_settings = {
|
|
52
|
+
...currentBuilderSettings,
|
|
53
|
+
version: sanitizedBuilderSettings.version,
|
|
54
|
+
revision: sanitizedBuilderSettings.revision,
|
|
55
|
+
theme: sanitizedBuilderSettings.theme,
|
|
56
|
+
};
|
|
57
|
+
return root;
|
|
58
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
export declare const PREVIEW_BOOT_SIDECAR_PATH = "__shoppex/preview-boot.json";
|
|
3
|
+
export declare const StorefrontSeedSchema: z.ZodObject<{
|
|
4
|
+
store: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
5
|
+
products: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
6
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
7
|
+
pages: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
export type StorefrontSeed = z.infer<typeof StorefrontSeedSchema>;
|
|
10
|
+
export declare const PreviewBootPayloadSchema: z.ZodObject<{
|
|
11
|
+
shopId: z.ZodString;
|
|
12
|
+
shopSlug: z.ZodString;
|
|
13
|
+
builderSettings: z.ZodObject<{
|
|
14
|
+
version: z.ZodLiteral<2>;
|
|
15
|
+
revision: z.ZodNumber;
|
|
16
|
+
theme: z.ZodObject<{
|
|
17
|
+
content: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
18
|
+
layout: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
19
|
+
blocks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
20
|
+
id: z.ZodString;
|
|
21
|
+
type: z.ZodString;
|
|
22
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
23
|
+
visible: z.ZodDefault<z.ZodBoolean>;
|
|
24
|
+
settings: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
25
|
+
style_overrides: z.ZodOptional<z.ZodType<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown, z.core.$ZodTypeInternals<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown>>>;
|
|
26
|
+
}, z.core.$strict>>>;
|
|
27
|
+
}, z.core.$strict>>>;
|
|
28
|
+
style_slots: z.ZodDefault<z.ZodType<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown, z.core.$ZodTypeInternals<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown>>>;
|
|
29
|
+
pages: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
30
|
+
id: z.ZodString;
|
|
31
|
+
title: z.ZodString;
|
|
32
|
+
slug: z.ZodString;
|
|
33
|
+
visible: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
layout: z.ZodDefault<z.ZodObject<{
|
|
35
|
+
blocks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
36
|
+
id: z.ZodString;
|
|
37
|
+
type: z.ZodString;
|
|
38
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
39
|
+
visible: z.ZodDefault<z.ZodBoolean>;
|
|
40
|
+
settings: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
41
|
+
style_overrides: z.ZodOptional<z.ZodType<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown, z.core.$ZodTypeInternals<Partial<Record<import("./style-slots.ts").StyleSlotId, import("./style-slots.ts").StyleSlotValue>>, unknown>>>;
|
|
42
|
+
}, z.core.$strict>>>;
|
|
43
|
+
}, z.core.$strict>>;
|
|
44
|
+
seo: z.ZodOptional<z.ZodObject<{
|
|
45
|
+
title: z.ZodOptional<z.ZodString>;
|
|
46
|
+
description: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
}, z.core.$strict>>>;
|
|
49
|
+
terms: z.ZodDefault<z.ZodObject<{
|
|
50
|
+
termsOfService: z.ZodOptional<z.ZodString>;
|
|
51
|
+
privacyPolicy: z.ZodOptional<z.ZodString>;
|
|
52
|
+
refundPolicy: z.ZodOptional<z.ZodString>;
|
|
53
|
+
imprint: z.ZodOptional<z.ZodString>;
|
|
54
|
+
}, z.core.$strict>>;
|
|
55
|
+
}, z.core.$strict>;
|
|
56
|
+
}, z.core.$strict>;
|
|
57
|
+
storefrontSeed: z.ZodObject<{
|
|
58
|
+
store: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
59
|
+
products: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
60
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
61
|
+
pages: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
62
|
+
}, z.core.$strict>;
|
|
63
|
+
artifactRevision: z.ZodOptional<z.ZodString>;
|
|
64
|
+
artifactStale: z.ZodOptional<z.ZodBoolean>;
|
|
65
|
+
}, z.core.$strict>;
|
|
66
|
+
export type PreviewBootPayload = z.infer<typeof PreviewBootPayloadSchema>;
|
|
67
|
+
export declare function mergePreviewBootIntoInitialData(payload: PreviewBootPayload): Record<string, unknown>;
|
|
68
|
+
//# sourceMappingURL=preview-boot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-boot.d.ts","sourceRoot":"","sources":["../src/preview-boot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAG5B,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAEvE,eAAO,MAAM,oBAAoB;;;;;kBAOtB,CAAC;AAEZ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAS1B,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,kBAAkB,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { BuilderSettingsSchema } from "./builder-settings.js";
|
|
3
|
+
export const PREVIEW_BOOT_SIDECAR_PATH = '__shoppex/preview-boot.json';
|
|
4
|
+
export const StorefrontSeedSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
store: z.record(z.string(), z.unknown()),
|
|
7
|
+
products: z.array(z.unknown()).optional(),
|
|
8
|
+
groups: z.array(z.unknown()).optional(),
|
|
9
|
+
pages: z.array(z.unknown()).optional(),
|
|
10
|
+
})
|
|
11
|
+
.strict();
|
|
12
|
+
export const PreviewBootPayloadSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
shopId: z.string().min(1),
|
|
15
|
+
shopSlug: z.string().min(1),
|
|
16
|
+
builderSettings: BuilderSettingsSchema,
|
|
17
|
+
storefrontSeed: StorefrontSeedSchema,
|
|
18
|
+
artifactRevision: z.string().optional(),
|
|
19
|
+
artifactStale: z.boolean().optional(),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
export function mergePreviewBootIntoInitialData(payload) {
|
|
23
|
+
const existingStore = isRecord(payload.storefrontSeed.store) ? payload.storefrontSeed.store : {};
|
|
24
|
+
return {
|
|
25
|
+
...payload.storefrontSeed,
|
|
26
|
+
store: {
|
|
27
|
+
...existingStore,
|
|
28
|
+
id: payload.shopId,
|
|
29
|
+
slug: payload.shopSlug,
|
|
30
|
+
builder_settings: payload.builderSettings,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function isRecord(value) {
|
|
35
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
36
|
+
}
|