@shoppexio/builder-contracts 0.1.11 → 0.1.12
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/preview-boot.d.ts +2 -0
- package/dist/preview-boot.d.ts.map +1 -1
- package/dist/preview-boot.js +7 -3
- package/dist/preview-protocol.d.ts +8 -0
- package/dist/preview-protocol.d.ts.map +1 -1
- package/dist/preview-protocol.js +8 -0
- package/dist/preview-route.d.ts +6 -0
- package/dist/preview-route.d.ts.map +1 -0
- package/dist/preview-route.js +16 -0
- package/dist/storefront-initial-data-html.d.ts +7 -0
- package/dist/storefront-initial-data-html.d.ts.map +1 -1
- package/dist/storefront-initial-data-html.js +20 -1
- package/dist/theme-schemes.d.ts +3 -3
- package/dist/theme-schemes.d.ts.map +1 -1
- package/dist/theme-schemes.js +2 -0
- package/package.json +7 -1
- package/src/builder-contracts.test.ts +1 -1
- package/src/preview-boot.test.ts +38 -1
- package/src/preview-boot.ts +14 -3
- package/src/preview-protocol.test.ts +11 -0
- package/src/preview-protocol.ts +9 -0
- package/src/preview-route.test.ts +22 -0
- package/src/preview-route.ts +22 -0
- package/src/storefront-initial-data-html.test.ts +26 -0
- package/src/storefront-initial-data-html.ts +25 -1
- package/src/theme-schemes.ts +2 -0
package/dist/preview-boot.d.ts
CHANGED
|
@@ -64,5 +64,7 @@ export declare const PreviewBootPayloadSchema: z.ZodObject<{
|
|
|
64
64
|
artifactStale: z.ZodOptional<z.ZodBoolean>;
|
|
65
65
|
}, z.core.$strict>;
|
|
66
66
|
export type PreviewBootPayload = z.infer<typeof PreviewBootPayloadSchema>;
|
|
67
|
+
/** Merge preview session identity + draft builder settings into an existing initial-data blob. */
|
|
68
|
+
export declare function mergePreviewBootFieldsIntoInitialData(initialData: Record<string, unknown>, payload: PreviewBootPayload): Record<string, unknown>;
|
|
67
69
|
export declare function mergePreviewBootIntoInitialData(payload: PreviewBootPayload): Record<string, unknown>;
|
|
68
70
|
//# sourceMappingURL=preview-boot.d.ts.map
|
|
@@ -1 +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;AAIvE,eAAO,MAAM,oBAAoB;;;;;iBAOjB,CAAC;AAEjB,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,
|
|
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;AAIvE,eAAO,MAAM,oBAAoB;;;;;iBAOjB,CAAC;AAEjB,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,kGAAkG;AAClG,wBAAgB,qCAAqC,CACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,EAAE,kBAAkB,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,kBAAkB,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB"}
|
package/dist/preview-boot.js
CHANGED
|
@@ -21,10 +21,11 @@ export const PreviewBootPayloadSchema = z
|
|
|
21
21
|
artifactStale: z.boolean().optional(),
|
|
22
22
|
})
|
|
23
23
|
.strict();
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/** Merge preview session identity + draft builder settings into an existing initial-data blob. */
|
|
25
|
+
export function mergePreviewBootFieldsIntoInitialData(initialData, payload) {
|
|
26
|
+
const existingStore = isRecord(initialData.store) ? initialData.store : {};
|
|
26
27
|
return {
|
|
27
|
-
...
|
|
28
|
+
...initialData,
|
|
28
29
|
store: {
|
|
29
30
|
...existingStore,
|
|
30
31
|
id: payload.shopId,
|
|
@@ -33,6 +34,9 @@ export function mergePreviewBootIntoInitialData(payload) {
|
|
|
33
34
|
},
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
export function mergePreviewBootIntoInitialData(payload) {
|
|
38
|
+
return mergePreviewBootFieldsIntoInitialData(payload.storefrontSeed, payload);
|
|
39
|
+
}
|
|
36
40
|
function isRecord(value) {
|
|
37
41
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
38
42
|
}
|
|
@@ -432,6 +432,11 @@ export declare const PreviewInlineEditCommitResponseSchema: z.ZodObject<{
|
|
|
432
432
|
contentPath: z.ZodString;
|
|
433
433
|
value: z.ZodString;
|
|
434
434
|
}, z.core.$strict>;
|
|
435
|
+
/** Iframe reports in-preview navigation (pathname + search) for server-liquid block renders. */
|
|
436
|
+
export declare const PreviewRouteChangedResponseSchema: z.ZodObject<{
|
|
437
|
+
type: z.ZodLiteral<"PREVIEW_ROUTE_CHANGED">;
|
|
438
|
+
path: z.ZodString;
|
|
439
|
+
}, z.core.$strict>;
|
|
435
440
|
export declare const PreviewResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
436
441
|
type: z.ZodLiteral<"BOOTSTRAP_OK">;
|
|
437
442
|
revision: z.ZodNumber;
|
|
@@ -566,6 +571,9 @@ export declare const PreviewResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
566
571
|
blockId: z.ZodString;
|
|
567
572
|
contentPath: z.ZodString;
|
|
568
573
|
value: z.ZodString;
|
|
574
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
575
|
+
type: z.ZodLiteral<"PREVIEW_ROUTE_CHANGED">;
|
|
576
|
+
path: z.ZodString;
|
|
569
577
|
}, z.core.$strict>], "type">;
|
|
570
578
|
export type PreviewResponse = z.infer<typeof PreviewResponseSchema>;
|
|
571
579
|
//# sourceMappingURL=preview-protocol.d.ts.map
|
|
@@ -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,4BAA4B,+BAA6B,CAAC;AACvE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF,eAAO,MAAM,2BAA2B;;;kBAK7B,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,kCAAkC;;;;;;;;;;kBASpC,CAAC;AACZ,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,iCAAiC;;;;;;;kBASnC,CAAC;AACZ,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAE5F,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAQ/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,gCAAgC;;;;;;kBAQlC,CAAC;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B;;;;kBAMjC,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
|
|
1
|
+
{"version":3,"file":"preview-protocol.d.ts","sourceRoot":"","sources":["../src/preview-protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/preview-protocol.js
CHANGED
|
@@ -250,6 +250,13 @@ export const PreviewInlineEditCommitResponseSchema = z
|
|
|
250
250
|
value: z.string(),
|
|
251
251
|
})
|
|
252
252
|
.strict();
|
|
253
|
+
/** Iframe reports in-preview navigation (pathname + search) for server-liquid block renders. */
|
|
254
|
+
export const PreviewRouteChangedResponseSchema = z
|
|
255
|
+
.object({
|
|
256
|
+
type: z.literal('PREVIEW_ROUTE_CHANGED'),
|
|
257
|
+
path: z.string().min(1),
|
|
258
|
+
})
|
|
259
|
+
.strict();
|
|
253
260
|
export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
254
261
|
PreviewBootstrapOkResponseSchema,
|
|
255
262
|
PreviewBootFailedResponseSchema,
|
|
@@ -263,4 +270,5 @@ export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
|
263
270
|
PreviewBlockRectResponseSchema,
|
|
264
271
|
PreviewInserterHoverResponseSchema,
|
|
265
272
|
PreviewInlineEditCommitResponseSchema,
|
|
273
|
+
PreviewRouteChangedResponseSchema,
|
|
266
274
|
]);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes the storefront route visible inside a theme-preview iframe after the
|
|
3
|
+
* worker strips the `/s/:sessionId/:draftToken` prefix via history.replaceState.
|
|
4
|
+
*/
|
|
5
|
+
export declare function readPreviewStorefrontRoutePath(pathname: string, search?: string, hash?: string): string | null;
|
|
6
|
+
//# sourceMappingURL=preview-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-route.d.ts","sourceRoot":"","sources":["../src/preview-route.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,MAAM,SAAK,EACX,IAAI,SAAK,GACR,MAAM,GAAG,IAAI,CAaf"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes the storefront route visible inside a theme-preview iframe after the
|
|
3
|
+
* worker strips the `/s/:sessionId/:draftToken` prefix via history.replaceState.
|
|
4
|
+
*/
|
|
5
|
+
export function readPreviewStorefrontRoutePath(pathname, search = '', hash = '') {
|
|
6
|
+
const path = pathname.trim() || '/';
|
|
7
|
+
if (path.includes('/__shoppex/')) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const lastSegment = path.split('/').pop() ?? '';
|
|
11
|
+
if (lastSegment.includes('.')) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const normalizedPath = path.replace(/\/+$/, '') || '/';
|
|
15
|
+
return `${normalizedPath}${search}${hash}`;
|
|
16
|
+
}
|
|
@@ -12,6 +12,13 @@ export declare function buildPlainInitialDataScript(initialData: Record<string,
|
|
|
12
12
|
export declare function buildWrappedStorefrontInitialDataScript(serialized: string, deployedThemeEntryPathPattern: RegExp): string;
|
|
13
13
|
export declare function injectPlainInitialDataBeforeHeadClose(html: string, script: string): string;
|
|
14
14
|
export declare function injectPreviewInitialData(html: string, payload: PreviewBootPayload): string;
|
|
15
|
+
/**
|
|
16
|
+
* Server-liquid preview pages are SSR'd with live storefront slices (storeStats, catalog, …).
|
|
17
|
+
* Replacing their initial-data scripts with the build-time artifact seed drops live sales counts
|
|
18
|
+
* and the bootstrap hydration pass overwrites hero stats back to 0. Keep the SSR snapshot and
|
|
19
|
+
* only merge preview-session fields (shop id/slug + draft builder settings).
|
|
20
|
+
*/
|
|
21
|
+
export declare function injectServerLiquidPreviewBoot(html: string, payload: PreviewBootPayload): string;
|
|
15
22
|
export declare function assertSingleInitialDataScript(html: string, expectedSlug: string): void;
|
|
16
23
|
export declare function safeJson(value: unknown): string;
|
|
17
24
|
//# sourceMappingURL=storefront-initial-data-html.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storefront-initial-data-html.d.ts","sourceRoot":"","sources":["../src/storefront-initial-data-html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"storefront-initial-data-html.d.ts","sourceRoot":"","sources":["../src/storefront-initial-data-html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAM5D,eAAO,MAAM,0BAA0B,QAC8K,CAAC;AAEtN,eAAO,MAAM,2BAA2B,QACuB,CAAC;AAOhE,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAYrF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAWnF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAExF;AAED,wBAAgB,uCAAuC,CACrD,UAAU,EAAE,MAAM,EAClB,6BAA6B,EAAE,MAAM,GACpC,MAAM,CAOR;AAED,wBAAgB,qCAAqC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAK1F;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAa/F;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAmBtF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE/C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mergePreviewBootIntoInitialData } from "./preview-boot.js";
|
|
1
|
+
import { mergePreviewBootFieldsIntoInitialData, mergePreviewBootIntoInitialData, } from "./preview-boot.js";
|
|
2
2
|
export const HTML_INITIAL_BLOCK_PATTERN = /<!--shoppex-initial-data:start--><script>\(function\(\)\{[\s\S]*?window\.__SHOPPEX_INITIAL__=([\s\S]*?)(?=;\}\)\(\);<\/script><!--shoppex-initial-data:end-->);\}\)\(\);<\/script><!--shoppex-initial-data:end-->/;
|
|
3
3
|
export const LEGACY_HTML_INITIAL_PATTERN = /<script>\s*window\.__SHOPPEX_INITIAL__=([\s\S]*?)<\/script>/;
|
|
4
4
|
const HTML_INITIAL_BLOCK_GLOBAL_PATTERN = new RegExp(HTML_INITIAL_BLOCK_PATTERN.source, 'g');
|
|
@@ -61,6 +61,25 @@ export function injectPreviewInitialData(html, payload) {
|
|
|
61
61
|
const script = buildPlainInitialDataScript(initialData);
|
|
62
62
|
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Server-liquid preview pages are SSR'd with live storefront slices (storeStats, catalog, …).
|
|
66
|
+
* Replacing their initial-data scripts with the build-time artifact seed drops live sales counts
|
|
67
|
+
* and the bootstrap hydration pass overwrites hero stats back to 0. Keep the SSR snapshot and
|
|
68
|
+
* only merge preview-session fields (shop id/slug + draft builder settings).
|
|
69
|
+
*/
|
|
70
|
+
export function injectServerLiquidPreviewBoot(html, payload) {
|
|
71
|
+
const existing = findInitialDataPayload(html);
|
|
72
|
+
if (!existing) {
|
|
73
|
+
const merged = mergePreviewBootFieldsIntoInitialData({ store: {} }, payload);
|
|
74
|
+
const withoutScripts = stripAllInitialDataScripts(html);
|
|
75
|
+
const script = buildPlainInitialDataScript(merged);
|
|
76
|
+
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
77
|
+
}
|
|
78
|
+
const merged = mergePreviewBootFieldsIntoInitialData(existing, payload);
|
|
79
|
+
const withoutScripts = stripAllInitialDataScripts(html);
|
|
80
|
+
const script = buildPlainInitialDataScript(merged);
|
|
81
|
+
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
82
|
+
}
|
|
64
83
|
export function assertSingleInitialDataScript(html, expectedSlug) {
|
|
65
84
|
const count = countInitialDataScripts(html);
|
|
66
85
|
if (count !== 1) {
|
package/dist/theme-schemes.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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", "clean-minimal", "shadow"];
|
|
2
2
|
export type PublicBuilderThemeScheme = (typeof PUBLIC_BUILDER_THEME_SCHEMES)[number];
|
|
3
3
|
export declare const STARTER_BUILDER_THEME_SCHEMES: readonly ["blank"];
|
|
4
4
|
export declare const THEME_STORE_DISABLED_SCHEMES: readonly [];
|
|
5
|
-
export declare const THEME_STORE_INSTALLABLE_SCHEMES: readonly ["default", "starlight", "pulse", "vault", "clean-minimal", "classic", "phantom", "nebula", "apex"];
|
|
6
|
-
export declare const BUILDER_READY_THEME_SCHEMES: readonly ["blank", "default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "clean-minimal"];
|
|
5
|
+
export declare const THEME_STORE_INSTALLABLE_SCHEMES: readonly ["default", "starlight", "pulse", "vault", "clean-minimal", "classic", "phantom", "nebula", "apex", "shadow"];
|
|
6
|
+
export declare const BUILDER_READY_THEME_SCHEMES: readonly ["blank", "default", "classic", "nebula", "pulse", "phantom", "starlight", "apex", "vault", "clean-minimal", "shadow"];
|
|
7
7
|
export type ThemeStoreInstallableScheme = (typeof THEME_STORE_INSTALLABLE_SCHEMES)[number];
|
|
8
8
|
export type StarterBuilderThemeScheme = (typeof STARTER_BUILDER_THEME_SCHEMES)[number];
|
|
9
9
|
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,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAErF,eAAO,MAAM,6BAA6B,oBAAqB,CAAC;AAEhE,eAAO,MAAM,4BAA4B,aAA4D,CAAC;AAItG,eAAO,MAAM,+BAA+B,wHAWY,CAAC;AAEzD,eAAO,MAAM,2BAA2B,iIAG9B,CAAC;AAEX,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,CAAC,CAAC;AAC3F,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,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,MAAM,GACZ,KAAK,IAAI,2BAA2B,CAEtC;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
|
@@ -8,6 +8,7 @@ export const PUBLIC_BUILDER_THEME_SCHEMES = [
|
|
|
8
8
|
'apex',
|
|
9
9
|
'vault',
|
|
10
10
|
'clean-minimal',
|
|
11
|
+
'shadow',
|
|
11
12
|
];
|
|
12
13
|
export const STARTER_BUILDER_THEME_SCHEMES = ['blank'];
|
|
13
14
|
export const THEME_STORE_DISABLED_SCHEMES = [];
|
|
@@ -22,6 +23,7 @@ export const THEME_STORE_INSTALLABLE_SCHEMES = [
|
|
|
22
23
|
'phantom',
|
|
23
24
|
'nebula',
|
|
24
25
|
'apex',
|
|
26
|
+
'shadow',
|
|
25
27
|
];
|
|
26
28
|
export const BUILDER_READY_THEME_SCHEMES = [
|
|
27
29
|
...STARTER_BUILDER_THEME_SCHEMES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoppexio/builder-contracts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Shared Builder v2 contracts for Shoppex dashboard, backend, preview runtime, and themes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -91,6 +91,12 @@
|
|
|
91
91
|
"import": "./dist/preview-protocol.js",
|
|
92
92
|
"default": "./dist/preview-protocol.js"
|
|
93
93
|
},
|
|
94
|
+
"./preview-route": {
|
|
95
|
+
"bun": "./src/preview-route.ts",
|
|
96
|
+
"types": "./dist/preview-route.d.ts",
|
|
97
|
+
"import": "./dist/preview-route.js",
|
|
98
|
+
"default": "./dist/preview-route.js"
|
|
99
|
+
},
|
|
94
100
|
"./preview-boot": {
|
|
95
101
|
"bun": "./src/preview-boot.ts",
|
|
96
102
|
"types": "./dist/preview-boot.d.ts",
|
|
@@ -857,7 +857,7 @@ describe('@shoppex/builder-contracts', () => {
|
|
|
857
857
|
|
|
858
858
|
test('parses official theme manifests with transparent contact-form backgrounds', () => {
|
|
859
859
|
const repoRoot = join(import.meta.dir, '../../..');
|
|
860
|
-
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', 'shadow']) {
|
|
861
861
|
const manifestPath = join(repoRoot, 'themes', theme, 'theme.manifest.json');
|
|
862
862
|
const raw = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
863
863
|
expect(ThemeManifestSchema.safeParse(raw).success, `${theme} manifest should validate`).toBe(true);
|
package/src/preview-boot.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
|
-
import { mergePreviewBootIntoInitialData, PreviewBootPayloadSchema } from './preview-boot.ts';
|
|
2
|
+
import { mergePreviewBootFieldsIntoInitialData, mergePreviewBootIntoInitialData, PreviewBootPayloadSchema } from './preview-boot.ts';
|
|
3
3
|
|
|
4
4
|
describe('PreviewBootPayloadSchema', () => {
|
|
5
5
|
it('accepts storefront seeds with catalog fields from built theme artifacts', () => {
|
|
@@ -69,4 +69,41 @@ describe('PreviewBootPayloadSchema', () => {
|
|
|
69
69
|
expect(initialData.addons).toEqual([{ id: 'addon_1' }]);
|
|
70
70
|
expect(initialData.menus).toEqual([{ id: 'menu_1' }]);
|
|
71
71
|
});
|
|
72
|
+
|
|
73
|
+
it('mergePreviewBootFieldsIntoInitialData preserves live storeStats from SSR snapshots', () => {
|
|
74
|
+
const initialData = mergePreviewBootFieldsIntoInitialData(
|
|
75
|
+
{
|
|
76
|
+
store: { slug: 'florain', name: 'Florain' },
|
|
77
|
+
storeStats: { sales: '29', products: '13+', rating: '0.0' },
|
|
78
|
+
products: [{ uniqid: 'p1' }],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
shopId: 'shop_1',
|
|
82
|
+
shopSlug: 'florain',
|
|
83
|
+
builderSettings: {
|
|
84
|
+
version: 2,
|
|
85
|
+
revision: 2,
|
|
86
|
+
theme: {
|
|
87
|
+
content: {},
|
|
88
|
+
layout: {},
|
|
89
|
+
style_slots: {},
|
|
90
|
+
pages: [],
|
|
91
|
+
terms: {},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
storefrontSeed: {
|
|
95
|
+
store: { slug: 'stale-artifact', products_sold_count: 0 },
|
|
96
|
+
storeStats: { sales: '0' },
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
expect(initialData.storeStats).toEqual({ sales: '29', products: '13+', rating: '0.0' });
|
|
102
|
+
expect(initialData.products).toEqual([{ uniqid: 'p1' }]);
|
|
103
|
+
expect(initialData.store).toMatchObject({
|
|
104
|
+
id: 'shop_1',
|
|
105
|
+
slug: 'florain',
|
|
106
|
+
name: 'Florain',
|
|
107
|
+
});
|
|
108
|
+
});
|
|
72
109
|
});
|
package/src/preview-boot.ts
CHANGED
|
@@ -29,12 +29,14 @@ export const PreviewBootPayloadSchema = z
|
|
|
29
29
|
|
|
30
30
|
export type PreviewBootPayload = z.infer<typeof PreviewBootPayloadSchema>;
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/** Merge preview session identity + draft builder settings into an existing initial-data blob. */
|
|
33
|
+
export function mergePreviewBootFieldsIntoInitialData(
|
|
34
|
+
initialData: Record<string, unknown>,
|
|
33
35
|
payload: PreviewBootPayload,
|
|
34
36
|
): Record<string, unknown> {
|
|
35
|
-
const existingStore = isRecord(
|
|
37
|
+
const existingStore = isRecord(initialData.store) ? initialData.store : {};
|
|
36
38
|
return {
|
|
37
|
-
...
|
|
39
|
+
...initialData,
|
|
38
40
|
store: {
|
|
39
41
|
...existingStore,
|
|
40
42
|
id: payload.shopId,
|
|
@@ -44,6 +46,15 @@ export function mergePreviewBootIntoInitialData(
|
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
export function mergePreviewBootIntoInitialData(
|
|
50
|
+
payload: PreviewBootPayload,
|
|
51
|
+
): Record<string, unknown> {
|
|
52
|
+
return mergePreviewBootFieldsIntoInitialData(
|
|
53
|
+
payload.storefrontSeed as Record<string, unknown>,
|
|
54
|
+
payload,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
47
58
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
48
59
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
49
60
|
}
|
|
@@ -259,6 +259,17 @@ describe('PreviewResponseSchema', () => {
|
|
|
259
259
|
}
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
+
it('accepts PREVIEW_ROUTE_CHANGED with storefront path', () => {
|
|
263
|
+
const parsed = PreviewResponseSchema.parse({
|
|
264
|
+
type: 'PREVIEW_ROUTE_CHANGED',
|
|
265
|
+
path: '/products?category=fivem&sort=price-asc',
|
|
266
|
+
});
|
|
267
|
+
expect(parsed.type).toBe('PREVIEW_ROUTE_CHANGED');
|
|
268
|
+
if (parsed.type === 'PREVIEW_ROUTE_CHANGED') {
|
|
269
|
+
expect(parsed.path).toBe('/products?category=fivem&sort=price-asc');
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
262
273
|
it('rejects INLINE_EDIT_COMMIT without contentPath', () => {
|
|
263
274
|
const result = PreviewResponseSchema.safeParse({
|
|
264
275
|
type: 'INLINE_EDIT_COMMIT',
|
package/src/preview-protocol.ts
CHANGED
|
@@ -286,6 +286,14 @@ export const PreviewInlineEditCommitResponseSchema = z
|
|
|
286
286
|
})
|
|
287
287
|
.strict();
|
|
288
288
|
|
|
289
|
+
/** Iframe reports in-preview navigation (pathname + search) for server-liquid block renders. */
|
|
290
|
+
export const PreviewRouteChangedResponseSchema = z
|
|
291
|
+
.object({
|
|
292
|
+
type: z.literal('PREVIEW_ROUTE_CHANGED'),
|
|
293
|
+
path: z.string().min(1),
|
|
294
|
+
})
|
|
295
|
+
.strict();
|
|
296
|
+
|
|
289
297
|
export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
290
298
|
PreviewBootstrapOkResponseSchema,
|
|
291
299
|
PreviewBootFailedResponseSchema,
|
|
@@ -299,5 +307,6 @@ export const PreviewResponseSchema = z.discriminatedUnion('type', [
|
|
|
299
307
|
PreviewBlockRectResponseSchema,
|
|
300
308
|
PreviewInserterHoverResponseSchema,
|
|
301
309
|
PreviewInlineEditCommitResponseSchema,
|
|
310
|
+
PreviewRouteChangedResponseSchema,
|
|
302
311
|
]);
|
|
303
312
|
export type PreviewResponse = z.infer<typeof PreviewResponseSchema>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { readPreviewStorefrontRoutePath } from './preview-route';
|
|
3
|
+
|
|
4
|
+
describe('readPreviewStorefrontRoutePath', () => {
|
|
5
|
+
test('returns pathname and search for storefront routes', () => {
|
|
6
|
+
expect(readPreviewStorefrontRoutePath('/products', '?category=fivem&sort=price-asc'))
|
|
7
|
+
.toBe('/products?category=fivem&sort=price-asc');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('normalizes trailing slashes on non-root paths', () => {
|
|
11
|
+
expect(readPreviewStorefrontRoutePath('/products/', '?page=2')).toBe('/products?page=2');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('preserves root path', () => {
|
|
15
|
+
expect(readPreviewStorefrontRoutePath('/', '?currency=EUR')).toBe('/?currency=EUR');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('rejects asset and sidecar paths', () => {
|
|
19
|
+
expect(readPreviewStorefrontRoutePath('/assets/built.css')).toBeNull();
|
|
20
|
+
expect(readPreviewStorefrontRoutePath('/s/session/token/__shoppex/preview-boot.json')).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes the storefront route visible inside a theme-preview iframe after the
|
|
3
|
+
* worker strips the `/s/:sessionId/:draftToken` prefix via history.replaceState.
|
|
4
|
+
*/
|
|
5
|
+
export function readPreviewStorefrontRoutePath(
|
|
6
|
+
pathname: string,
|
|
7
|
+
search = '',
|
|
8
|
+
hash = '',
|
|
9
|
+
): string | null {
|
|
10
|
+
const path = pathname.trim() || '/';
|
|
11
|
+
if (path.includes('/__shoppex/')) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const lastSegment = path.split('/').pop() ?? '';
|
|
16
|
+
if (lastSegment.includes('.')) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const normalizedPath = path.replace(/\/+$/, '') || '/';
|
|
21
|
+
return `${normalizedPath}${search}${hash}`;
|
|
22
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
countInitialDataScripts,
|
|
7
7
|
findInitialDataPayload,
|
|
8
8
|
injectPreviewInitialData,
|
|
9
|
+
injectServerLiquidPreviewBoot,
|
|
9
10
|
stripAllInitialDataScripts,
|
|
10
11
|
} from './storefront-initial-data-html.ts';
|
|
11
12
|
|
|
@@ -56,6 +57,31 @@ describe('storefront-initial-data-html', () => {
|
|
|
56
57
|
slug: 'demo-shop',
|
|
57
58
|
});
|
|
58
59
|
});
|
|
60
|
+
|
|
61
|
+
it('preserves live storeStats when merging preview boot into server-liquid SSR initial data', () => {
|
|
62
|
+
const html = [
|
|
63
|
+
'<html><head>',
|
|
64
|
+
'<script>window.__SHOPPEX_INITIAL__={"store":{"slug":"florain","name":"Florain"},"storeStats":{"sales":"29","products":"13+","rating":"0.0"}};</script>',
|
|
65
|
+
'<script data-shoppex-bootstrap="v2">window.shopId="shop_1";</script>',
|
|
66
|
+
'</head><body><span data-shoppex-runtime-stat="sales">29</span></body></html>',
|
|
67
|
+
].join('');
|
|
68
|
+
|
|
69
|
+
const next = injectServerLiquidPreviewBoot(html, samplePayload);
|
|
70
|
+
expect(countInitialDataScripts(next)).toBe(1);
|
|
71
|
+
assertSingleInitialDataScript(next, 'demo-shop');
|
|
72
|
+
expect(findInitialDataPayload(next)).toMatchObject({
|
|
73
|
+
storeStats: {
|
|
74
|
+
sales: '29',
|
|
75
|
+
products: '13+',
|
|
76
|
+
rating: '0.0',
|
|
77
|
+
},
|
|
78
|
+
store: {
|
|
79
|
+
id: 'shop_1',
|
|
80
|
+
slug: 'demo-shop',
|
|
81
|
+
name: 'Florain',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
});
|
|
59
85
|
it('throws when assert sees zero or multiple scripts', () => {
|
|
60
86
|
expect(() => assertSingleInitialDataScript('<html></html>', 'demo-shop')).toThrow();
|
|
61
87
|
const html = [
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { PreviewBootPayload } from './preview-boot.ts';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
mergePreviewBootFieldsIntoInitialData,
|
|
4
|
+
mergePreviewBootIntoInitialData,
|
|
5
|
+
} from './preview-boot.ts';
|
|
3
6
|
|
|
4
7
|
export const HTML_INITIAL_BLOCK_PATTERN =
|
|
5
8
|
/<!--shoppex-initial-data:start--><script>\(function\(\)\{[\s\S]*?window\.__SHOPPEX_INITIAL__=([\s\S]*?)(?=;\}\)\(\);<\/script><!--shoppex-initial-data:end-->);\}\)\(\);<\/script><!--shoppex-initial-data:end-->/;
|
|
@@ -86,6 +89,27 @@ export function injectPreviewInitialData(html: string, payload: PreviewBootPaylo
|
|
|
86
89
|
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Server-liquid preview pages are SSR'd with live storefront slices (storeStats, catalog, …).
|
|
94
|
+
* Replacing their initial-data scripts with the build-time artifact seed drops live sales counts
|
|
95
|
+
* and the bootstrap hydration pass overwrites hero stats back to 0. Keep the SSR snapshot and
|
|
96
|
+
* only merge preview-session fields (shop id/slug + draft builder settings).
|
|
97
|
+
*/
|
|
98
|
+
export function injectServerLiquidPreviewBoot(html: string, payload: PreviewBootPayload): string {
|
|
99
|
+
const existing = findInitialDataPayload(html);
|
|
100
|
+
if (!existing) {
|
|
101
|
+
const merged = mergePreviewBootFieldsIntoInitialData({ store: {} }, payload);
|
|
102
|
+
const withoutScripts = stripAllInitialDataScripts(html);
|
|
103
|
+
const script = buildPlainInitialDataScript(merged);
|
|
104
|
+
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const merged = mergePreviewBootFieldsIntoInitialData(existing, payload);
|
|
108
|
+
const withoutScripts = stripAllInitialDataScripts(html);
|
|
109
|
+
const script = buildPlainInitialDataScript(merged);
|
|
110
|
+
return injectPlainInitialDataBeforeHeadClose(withoutScripts, script);
|
|
111
|
+
}
|
|
112
|
+
|
|
89
113
|
export function assertSingleInitialDataScript(html: string, expectedSlug: string): void {
|
|
90
114
|
const count = countInitialDataScripts(html);
|
|
91
115
|
if (count !== 1) {
|
package/src/theme-schemes.ts
CHANGED
|
@@ -8,6 +8,7 @@ export const PUBLIC_BUILDER_THEME_SCHEMES = [
|
|
|
8
8
|
'apex',
|
|
9
9
|
'vault',
|
|
10
10
|
'clean-minimal',
|
|
11
|
+
'shadow',
|
|
11
12
|
] as const;
|
|
12
13
|
|
|
13
14
|
export type PublicBuilderThemeScheme = (typeof PUBLIC_BUILDER_THEME_SCHEMES)[number];
|
|
@@ -28,6 +29,7 @@ export const THEME_STORE_INSTALLABLE_SCHEMES = [
|
|
|
28
29
|
'phantom',
|
|
29
30
|
'nebula',
|
|
30
31
|
'apex',
|
|
32
|
+
'shadow',
|
|
31
33
|
] as const satisfies readonly PublicBuilderThemeScheme[];
|
|
32
34
|
|
|
33
35
|
export const BUILDER_READY_THEME_SCHEMES = [
|