@webiny/website-builder-nextjs 6.4.11 → 6.6.0-alpha.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.
@@ -1,18 +1,10 @@
1
1
  import React from "react";
2
- import type { ComponentProps } from "@webiny/website-builder-react";
2
+ import type { ComponentProps, Asset } from "@webiny/website-builder-react";
3
3
  type ImageProps = ComponentProps<{
4
4
  title: string;
5
5
  altText: string;
6
6
  highPriority: boolean;
7
- image: {
8
- id: string;
9
- name: string;
10
- size: number;
11
- mimeType: string;
12
- src: string;
13
- width: number;
14
- height: number;
15
- };
7
+ image: Asset;
16
8
  }>;
17
9
  export declare const ImageComponent: (props: ImageProps) => React.JSX.Element;
18
10
  export {};
@@ -1,32 +1,57 @@
1
1
  import react from "react";
2
2
  import next_image from "next/image";
3
+ import { getAssetUrl, getImageDimensions, getImageSrcSet, normalizeToAsset } from "@webiny/website-builder-react";
3
4
  const ImageComponent = (props)=>{
4
- const image = useImage(props);
5
- if (!image.src) return /*#__PURE__*/ react.createElement(ImagePlaceholder, {
5
+ const { title = "", altText, image, highPriority } = props.inputs;
6
+ const asset = normalizeToAsset(image);
7
+ if (!asset?.src) return /*#__PURE__*/ react.createElement(ImagePlaceholder, {
6
8
  style: props.styles
7
9
  });
8
- if ("object" === image.tag) return /*#__PURE__*/ react.createElement("object", {
9
- style: image.styles,
10
- title: image.title,
11
- data: image.src
12
- });
13
- return /*#__PURE__*/ react.createElement("div", {
10
+ const alt = altText || asset.image?.alt || "";
11
+ if (asset.src.endsWith(".svg")) return /*#__PURE__*/ react.createElement("object", {
14
12
  style: {
15
- position: "relative",
13
+ maxWidth: "100%",
16
14
  ...props.styles
17
- }
18
- }, /*#__PURE__*/ react.createElement(next_image, {
19
- alt: image.altText,
20
- title: image.title,
21
- src: image.src,
22
- width: props.inputs.image.width,
23
- height: props.inputs.image.height,
24
- style: image.styles,
25
- priority: props.inputs.highPriority,
26
- loading: props.inputs.highPriority ? "eager" : "lazy",
15
+ },
16
+ title: title,
17
+ data: asset.src
18
+ });
19
+ const loader = ({ width })=>getAssetUrl(asset, {
20
+ width,
21
+ format: "auto"
22
+ });
23
+ const { width, height } = getImageDimensions(asset);
24
+ const style = {
25
+ maxWidth: "100%",
26
+ height: "auto",
27
+ ...props.styles
28
+ };
29
+ if (!width || !height) {
30
+ const { src, srcSet } = getImageSrcSet(asset, {
31
+ format: "auto",
32
+ cssWidth: props.styles?.width
33
+ });
34
+ return /*#__PURE__*/ react.createElement("img", {
35
+ src: src,
36
+ srcSet: srcSet,
37
+ sizes: "100vw",
38
+ alt: alt,
39
+ title: title || void 0,
40
+ loading: highPriority ? "eager" : "lazy",
41
+ style: style
42
+ });
43
+ }
44
+ return /*#__PURE__*/ react.createElement(next_image, {
45
+ src: asset.src,
46
+ loader: loader,
47
+ alt: alt,
48
+ title: title || void 0,
49
+ width: width,
50
+ height: height,
27
51
  sizes: "100vw",
28
- loader: ({ src, width })=>`${src}?width=${width}`
29
- }));
52
+ priority: highPriority,
53
+ style: style
54
+ });
30
55
  };
31
56
  const ImagePlaceholder = ({ style })=>/*#__PURE__*/ react.createElement("div", {
32
57
  style: {
@@ -51,22 +76,6 @@ const ImagePlaceholder = ({ style })=>/*#__PURE__*/ react.createElement("div", {
51
76
  }, /*#__PURE__*/ react.createElement("path", {
52
77
  d: "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"
53
78
  })));
54
- const useImage = ({ inputs, styles })=>{
55
- const { title = "", altText, image } = inputs;
56
- const src = image?.src;
57
- const tag = src && src.endsWith(".svg") ? "object" : "img";
58
- const imageStyles = {
59
- maxWidth: "100%",
60
- ...styles
61
- };
62
- return {
63
- altText,
64
- src: inputs.image?.src,
65
- styles: imageStyles,
66
- tag,
67
- title
68
- };
69
- };
70
79
  export { ImageComponent };
71
80
 
72
81
  //# sourceMappingURL=Image.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editorComponents/Image.js","sources":["../../src/editorComponents/Image.tsx"],"sourcesContent":["import React from \"react\";\nimport Image from \"next/image\";\nimport type { CssProperties } from \"@webiny/website-builder-react\";\nimport type { ComponentProps } from \"@webiny/website-builder-react\";\n\ntype ImageProps = ComponentProps<{\n title: string;\n altText: string;\n highPriority: boolean;\n image: {\n id: string;\n name: string;\n size: number;\n mimeType: string;\n src: string;\n width: number;\n height: number;\n };\n}>;\n\nexport const ImageComponent = (props: ImageProps) => {\n const image = useImage(props);\n\n if (!image.src) {\n return <ImagePlaceholder style={props.styles} />;\n }\n\n if (image.tag === \"object\") {\n return <object style={image.styles} title={image.title} data={image.src} />;\n }\n\n return (\n <div\n style={{\n position: \"relative\",\n ...props.styles\n }}\n >\n {/* <ImagePlaceholder style={image.styles} /> */}\n <Image\n alt={image.altText}\n title={image.title}\n src={image.src}\n width={props.inputs.image.width}\n height={props.inputs.image.height}\n style={image.styles}\n priority={props.inputs.highPriority}\n loading={props.inputs.highPriority ? \"eager\" : \"lazy\"}\n sizes={\"100vw\"}\n loader={({ src, width }) => `${src}?width=${width}`}\n />\n </div>\n );\n};\n\nconst ImagePlaceholder = ({ style }: { style: CssProperties }) => {\n return (\n <div\n style={{\n display: \"flex\",\n height: \"200px\",\n backgroundColor: \"#f4f4f4\",\n justifyContent: \"center\",\n alignItems: \"center\",\n fill: \"#ffffff\",\n ...style\n }}\n >\n <svg\n style={{\n width: \"70px\",\n height: \"70px\",\n filter: \"drop-shadow(rgba(0, 0, 0, 0.16) 0px 1px 0px)\"\n }}\n xmlns=\"http://www.w3.org/2000/svg\"\n height=\"24px\"\n viewBox=\"0 -960 960 960\"\n width=\"24px\"\n >\n <path d=\"M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z\" />\n </svg>\n </div>\n );\n};\n\nconst useImage = ({ inputs, styles }: ImageProps) => {\n const { title = \"\", altText, image } = inputs;\n const src = image?.src;\n\n const tag = src && src.endsWith(\".svg\") ? \"object\" : \"img\";\n\n const imageStyles = {\n maxWidth: \"100%\",\n ...styles\n };\n\n return {\n altText,\n src: inputs.image?.src,\n styles: imageStyles,\n tag,\n title\n };\n};\n"],"names":["ImageComponent","props","image","useImage","ImagePlaceholder","Image","src","width","style","inputs","styles","title","altText","tag","imageStyles"],"mappings":";;AAoBO,MAAMA,iBAAiB,CAACC;IAC3B,MAAMC,QAAQC,SAASF;IAEvB,IAAI,CAACC,MAAM,GAAG,EACV,OAAO,WAAP,GAAO,oBAACE,kBAAgBA;QAAC,OAAOH,MAAM,MAAM;;IAGhD,IAAIC,AAAc,aAAdA,MAAM,GAAG,EACT,OAAO,WAAP,GAAO,oBAAC;QAAO,OAAOA,MAAM,MAAM;QAAE,OAAOA,MAAM,KAAK;QAAE,MAAMA,MAAM,GAAG;;IAG3E,OAAO,WAAP,GACI,oBAAC;QACG,OAAO;YACH,UAAU;YACV,GAAGD,MAAM,MAAM;QACnB;qBAGA,oBAACI,YAAKA;QACF,KAAKH,MAAM,OAAO;QAClB,OAAOA,MAAM,KAAK;QAClB,KAAKA,MAAM,GAAG;QACd,OAAOD,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK;QAC/B,QAAQA,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM;QACjC,OAAOC,MAAM,MAAM;QACnB,UAAUD,MAAM,MAAM,CAAC,YAAY;QACnC,SAASA,MAAM,MAAM,CAAC,YAAY,GAAG,UAAU;QAC/C,OAAO;QACP,QAAQ,CAAC,EAAEK,GAAG,EAAEC,KAAK,EAAE,GAAK,GAAGD,IAAI,OAAO,EAAEC,OAAO;;AAInE;AAEA,MAAMH,mBAAmB,CAAC,EAAEI,KAAK,EAA4B,GAClD,WAAP,GACI,oBAAC;QACG,OAAO;YACH,SAAS;YACT,QAAQ;YACR,iBAAiB;YACjB,gBAAgB;YAChB,YAAY;YACZ,MAAM;YACN,GAAGA,KAAK;QACZ;qBAEA,oBAAC;QACG,OAAO;YACH,OAAO;YACP,QAAQ;YACR,QAAQ;QACZ;QACA,OAAM;QACN,QAAO;QACP,SAAQ;QACR,OAAM;qBAEN,oBAAC;QAAK,GAAE;;AAMxB,MAAML,WAAW,CAAC,EAAEM,MAAM,EAAEC,MAAM,EAAc;IAC5C,MAAM,EAAEC,QAAQ,EAAE,EAAEC,OAAO,EAAEV,KAAK,EAAE,GAAGO;IACvC,MAAMH,MAAMJ,OAAO;IAEnB,MAAMW,MAAMP,OAAOA,IAAI,QAAQ,CAAC,UAAU,WAAW;IAErD,MAAMQ,cAAc;QAChB,UAAU;QACV,GAAGJ,MAAM;IACb;IAEA,OAAO;QACHE;QACA,KAAKH,OAAO,KAAK,EAAE;QACnB,QAAQK;QACRD;QACAF;IACJ;AACJ"}
1
+ {"version":3,"file":"editorComponents/Image.js","sources":["../../src/editorComponents/Image.tsx"],"sourcesContent":["import React from \"react\";\nimport NextImage from \"next/image\";\nimport type { ComponentProps, CssProperties, Asset } from \"@webiny/website-builder-react\";\nimport {\n getAssetUrl,\n getImageDimensions,\n getImageSrcSet,\n normalizeToAsset\n} from \"@webiny/website-builder-react\";\n\ntype ImageProps = ComponentProps<{\n title: string;\n altText: string;\n highPriority: boolean;\n // Accepts the unified asset shape or a legacy value (existing pages).\n image: Asset;\n}>;\n\nexport const ImageComponent = (props: ImageProps) => {\n const { title = \"\", altText, image, highPriority } = props.inputs;\n const asset = normalizeToAsset(image);\n\n if (!asset?.src) {\n return <ImagePlaceholder style={props.styles} />;\n }\n\n const alt = altText || asset.image?.alt || \"\";\n\n // SVGs are vector — nothing to crop, resize, or re-encode.\n if (asset.src.endsWith(\".svg\")) {\n return (\n <object style={{ maxWidth: \"100%\", ...props.styles }} title={title} data={asset.src} />\n );\n }\n\n // The delivery bakes the per-usage crop (`?crop`), resizes (`?width`), and serves\n // a modern format negotiated from Accept (`?format=auto`). We hand `next/image` a\n // loader that builds that URL, and it drives the responsive `srcSet`.\n const loader = ({ width }: { width: number }) => getAssetUrl(asset, { width, format: \"auto\" });\n\n // Intrinsic size of the *delivered* (cropped) image, so next/image lays out at\n // the correct aspect ratio. Falls back to a plain <img> when dimensions are\n // unknown (next/image requires width + height unless `fill`).\n const { width, height } = getImageDimensions(asset);\n\n const style: CssProperties = { maxWidth: \"100%\", height: \"auto\", ...props.styles };\n\n if (!width || !height) {\n // No intrinsic size to lay out with — fall back to a plain <img>, still\n // responsive via the SDK's framework-agnostic srcSet (crop/format baked in).\n const { src, srcSet } = getImageSrcSet(asset, {\n format: \"auto\",\n cssWidth: props.styles?.width\n });\n // eslint-disable-next-line @next/next/no-img-element\n return (\n <img\n src={src}\n srcSet={srcSet}\n sizes=\"100vw\"\n alt={alt}\n title={title || undefined}\n loading={highPriority ? \"eager\" : \"lazy\"}\n style={style}\n />\n );\n }\n\n return (\n <NextImage\n src={asset.src}\n loader={loader}\n alt={alt}\n title={title || undefined}\n width={width}\n height={height}\n sizes={\"100vw\"}\n priority={highPriority}\n style={style}\n />\n );\n};\n\nconst ImagePlaceholder = ({ style }: { style: CssProperties }) => {\n return (\n <div\n style={{\n display: \"flex\",\n height: \"200px\",\n backgroundColor: \"#f4f4f4\",\n justifyContent: \"center\",\n alignItems: \"center\",\n fill: \"#ffffff\",\n ...style\n }}\n >\n <svg\n style={{\n width: \"70px\",\n height: \"70px\",\n filter: \"drop-shadow(rgba(0, 0, 0, 0.16) 0px 1px 0px)\"\n }}\n xmlns=\"http://www.w3.org/2000/svg\"\n height=\"24px\"\n viewBox=\"0 -960 960 960\"\n width=\"24px\"\n >\n <path d=\"M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z\" />\n </svg>\n </div>\n );\n};\n"],"names":["ImageComponent","props","title","altText","image","highPriority","asset","normalizeToAsset","ImagePlaceholder","alt","loader","width","getAssetUrl","height","getImageDimensions","style","src","srcSet","getImageSrcSet","undefined","NextImage"],"mappings":";;;AAkBO,MAAMA,iBAAiB,CAACC;IAC3B,MAAM,EAAEC,QAAQ,EAAE,EAAEC,OAAO,EAAEC,KAAK,EAAEC,YAAY,EAAE,GAAGJ,MAAM,MAAM;IACjE,MAAMK,QAAQC,iBAAiBH;IAE/B,IAAI,CAACE,OAAO,KACR,OAAO,WAAP,GAAO,oBAACE,kBAAgBA;QAAC,OAAOP,MAAM,MAAM;;IAGhD,MAAMQ,MAAMN,WAAWG,MAAM,KAAK,EAAE,OAAO;IAG3C,IAAIA,MAAM,GAAG,CAAC,QAAQ,CAAC,SACnB,OAAO,WAAP,GACI,oBAAC;QAAO,OAAO;YAAE,UAAU;YAAQ,GAAGL,MAAM,MAAM;QAAC;QAAG,OAAOC;QAAO,MAAMI,MAAM,GAAG;;IAO3F,MAAMI,SAAS,CAAC,EAAEC,KAAK,EAAqB,GAAKC,YAAYN,OAAO;YAAEK;YAAO,QAAQ;QAAO;IAK5F,MAAM,EAAEA,KAAK,EAAEE,MAAM,EAAE,GAAGC,mBAAmBR;IAE7C,MAAMS,QAAuB;QAAE,UAAU;QAAQ,QAAQ;QAAQ,GAAGd,MAAM,MAAM;IAAC;IAEjF,IAAI,CAACU,SAAS,CAACE,QAAQ;QAGnB,MAAM,EAAEG,GAAG,EAAEC,MAAM,EAAE,GAAGC,eAAeZ,OAAO;YAC1C,QAAQ;YACR,UAAUL,MAAM,MAAM,EAAE;QAC5B;QAEA,OAAO,WAAP,GACI,oBAAC;YACG,KAAKe;YACL,QAAQC;YACR,OAAM;YACN,KAAKR;YACL,OAAOP,SAASiB;YAChB,SAASd,eAAe,UAAU;YAClC,OAAOU;;IAGnB;IAEA,OAAO,WAAP,GACI,oBAACK,YAASA;QACN,KAAKd,MAAM,GAAG;QACd,QAAQI;QACR,KAAKD;QACL,OAAOP,SAASiB;QAChB,OAAOR;QACP,QAAQE;QACR,OAAO;QACP,UAAUR;QACV,OAAOU;;AAGnB;AAEA,MAAMP,mBAAmB,CAAC,EAAEO,KAAK,EAA4B,GAClD,WAAP,GACI,oBAAC;QACG,OAAO;YACH,SAAS;YACT,QAAQ;YACR,iBAAiB;YACjB,gBAAgB;YAChB,YAAY;YACZ,MAAM;YACN,GAAGA,KAAK;QACZ;qBAEA,oBAAC;QACG,OAAO;YACH,OAAO;YACP,QAAQ;YACR,QAAQ;QACZ;QACA,OAAM;QACN,QAAO;QACP,SAAQ;QACR,OAAM;qBAEN,oBAAC;QAAK,GAAE"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Next.js middleware for Website Builder.
3
+ *
4
+ * Handles the two request-time concerns an app would otherwise hand-write:
5
+ * - **Preview / draft mode** — routes `?wb.preview`/`?wb.editing` requests through the draft-mode
6
+ * route and disables caching while previewing; exits preview when the flag is gone.
7
+ * - **A/B visitor cookie** — sets a stable, PII-free `wb_ab_vid` cookie so variant bucketing is
8
+ * deterministic across visits.
9
+ *
10
+ * `next` is a peer dependency and is imported dynamically so building this package never requires
11
+ * it. Drop into a project as:
12
+ *
13
+ * // middleware.ts
14
+ * export { middleware, config } from "@webiny/website-builder-nextjs/middleware";
15
+ */
16
+ interface MiddlewareRequest {
17
+ url: string;
18
+ nextUrl: {
19
+ searchParams: URLSearchParams;
20
+ pathname: string;
21
+ };
22
+ headers: Headers;
23
+ cookies: {
24
+ get(name: string): {
25
+ value: string;
26
+ } | undefined;
27
+ };
28
+ }
29
+ export interface WebsiteBuilderMiddlewareOptions {
30
+ /** Route that enables Next.js draft mode for preview. Defaults to `/api/preview`. */
31
+ previewRoute?: string;
32
+ /** A/B bucketing cookie name. Defaults to `wb_ab_vid`. */
33
+ visitorCookieName?: string;
34
+ /** A/B bucketing cookie max-age in seconds. Defaults to one year. */
35
+ visitorCookieMaxAge?: number;
36
+ }
37
+ export declare function createWebsiteBuilderMiddleware(options?: WebsiteBuilderMiddlewareOptions): (request: MiddlewareRequest) => Promise<import("next/server").NextResponse<unknown>>;
38
+ /** Turnkey middleware with default options. */
39
+ export declare const middleware: (request: MiddlewareRequest) => Promise<import("next/server").NextResponse<unknown>>;
40
+ /** Default matcher: everything except Next internals, API routes, and static assets. */
41
+ export declare const config: {
42
+ matcher: string[];
43
+ };
44
+ export {};
package/middleware.js ADDED
@@ -0,0 +1,58 @@
1
+ const DEFAULT_PREVIEW_ROUTE = "/api/preview";
2
+ const DEFAULT_VISITOR_COOKIE = "wb_ab_vid";
3
+ const ONE_YEAR_SECONDS = 31536000;
4
+ function createWebsiteBuilderMiddleware(options = {}) {
5
+ const previewRoute = options.previewRoute ?? DEFAULT_PREVIEW_ROUTE;
6
+ const cookieName = options.visitorCookieName ?? DEFAULT_VISITOR_COOKIE;
7
+ const cookieMaxAge = options.visitorCookieMaxAge ?? ONE_YEAR_SECONDS;
8
+ return async function(request) {
9
+ const { NextResponse } = await import("next/server");
10
+ const { draftMode } = await import("next/headers");
11
+ const { searchParams } = request.nextUrl;
12
+ const previewRequested = "true" === searchParams.get("wb.preview") || "true" === searchParams.get("wb.editing");
13
+ const requestHeaders = new Headers(request.headers);
14
+ requestHeaders.set("X-Tenant", searchParams.get("wb.tenant") ?? "root");
15
+ const previewMode = await draftMode();
16
+ if (previewRequested) {
17
+ if (previewMode.isEnabled) {
18
+ const response = NextResponse.next({
19
+ request: {
20
+ headers: requestHeaders
21
+ }
22
+ });
23
+ response.headers.set("X-Preview-Params", searchParams.toString());
24
+ response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
25
+ response.headers.set("Pragma", "no-cache");
26
+ response.headers.set("Expires", "0");
27
+ return response;
28
+ }
29
+ const url = new URL(request.url);
30
+ url.pathname = previewRoute;
31
+ return NextResponse.redirect(url);
32
+ }
33
+ if (previewMode.isEnabled) {
34
+ previewMode.disable();
35
+ return NextResponse.redirect(request.url);
36
+ }
37
+ const response = NextResponse.next({
38
+ request: {
39
+ headers: requestHeaders
40
+ }
41
+ });
42
+ if (!request.cookies.get(cookieName)) response.cookies.set(cookieName, crypto.randomUUID(), {
43
+ maxAge: cookieMaxAge,
44
+ path: "/",
45
+ sameSite: "lax"
46
+ });
47
+ return response;
48
+ };
49
+ }
50
+ const middleware_middleware = createWebsiteBuilderMiddleware();
51
+ const config = {
52
+ matcher: [
53
+ "/((?!_next|api|static|favicon.ico|.well-known).*)"
54
+ ]
55
+ };
56
+ export { config, createWebsiteBuilderMiddleware, middleware_middleware as middleware };
57
+
58
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sources":["../src/middleware.ts"],"sourcesContent":["/**\n * Next.js middleware for Website Builder.\n *\n * Handles the two request-time concerns an app would otherwise hand-write:\n * - **Preview / draft mode** — routes `?wb.preview`/`?wb.editing` requests through the draft-mode\n * route and disables caching while previewing; exits preview when the flag is gone.\n * - **A/B visitor cookie** — sets a stable, PII-free `wb_ab_vid` cookie so variant bucketing is\n * deterministic across visits.\n *\n * `next` is a peer dependency and is imported dynamically so building this package never requires\n * it. Drop into a project as:\n *\n * // middleware.ts\n * export { middleware, config } from \"@webiny/website-builder-nextjs/middleware\";\n */\n\nconst DEFAULT_PREVIEW_ROUTE = \"/api/preview\";\nconst DEFAULT_VISITOR_COOKIE = \"wb_ab_vid\";\nconst ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;\n\n// Minimal structural view of NextRequest — avoids a static `next` type import.\ninterface MiddlewareRequest {\n url: string;\n nextUrl: { searchParams: URLSearchParams; pathname: string };\n headers: Headers;\n cookies: { get(name: string): { value: string } | undefined };\n}\n\nexport interface WebsiteBuilderMiddlewareOptions {\n /** Route that enables Next.js draft mode for preview. Defaults to `/api/preview`. */\n previewRoute?: string;\n /** A/B bucketing cookie name. Defaults to `wb_ab_vid`. */\n visitorCookieName?: string;\n /** A/B bucketing cookie max-age in seconds. Defaults to one year. */\n visitorCookieMaxAge?: number;\n}\n\nexport function createWebsiteBuilderMiddleware(options: WebsiteBuilderMiddlewareOptions = {}) {\n const previewRoute = options.previewRoute ?? DEFAULT_PREVIEW_ROUTE;\n const cookieName = options.visitorCookieName ?? DEFAULT_VISITOR_COOKIE;\n const cookieMaxAge = options.visitorCookieMaxAge ?? ONE_YEAR_SECONDS;\n\n return async function middleware(request: MiddlewareRequest) {\n // @ts-ignore Peer dependency, resolved from the host app.\n const { NextResponse } = await import(\"next/server\");\n // @ts-ignore Peer dependency, resolved from the host app.\n const { draftMode } = await import(\"next/headers\");\n\n const { searchParams } = request.nextUrl;\n const previewRequested =\n searchParams.get(\"wb.preview\") === \"true\" || searchParams.get(\"wb.editing\") === \"true\";\n\n // Forward the tenant so downstream reads resolve against the right tenant.\n const requestHeaders = new Headers(request.headers);\n requestHeaders.set(\"X-Tenant\", searchParams.get(\"wb.tenant\") ?? \"root\");\n\n const previewMode = await draftMode();\n\n if (previewRequested) {\n if (previewMode.isEnabled) {\n // Already in draft mode — pass the preview params through and disable caching.\n const response = NextResponse.next({ request: { headers: requestHeaders } });\n response.headers.set(\"X-Preview-Params\", searchParams.toString());\n response.headers.set(\n \"Cache-Control\",\n \"no-store, no-cache, must-revalidate, proxy-revalidate\"\n );\n response.headers.set(\"Pragma\", \"no-cache\");\n response.headers.set(\"Expires\", \"0\");\n return response;\n }\n // Not in draft mode yet — hand off to the route that enables it, keeping all params.\n const url = new URL(request.url);\n url.pathname = previewRoute;\n return NextResponse.redirect(url);\n }\n\n if (previewMode.isEnabled) {\n // Preview flag gone but draft mode still on — exit preview.\n previewMode.disable();\n return NextResponse.redirect(request.url);\n }\n\n const response = NextResponse.next({ request: { headers: requestHeaders } });\n\n // Stable visitor id for deterministic A/B bucketing (functional cookie, no PII). Remove or\n // gate this if your consent policy requires opt-in — bucketing still works per-request\n // without it, just not stably across visits.\n if (!request.cookies.get(cookieName)) {\n response.cookies.set(cookieName, crypto.randomUUID(), {\n maxAge: cookieMaxAge,\n path: \"/\",\n sameSite: \"lax\"\n });\n }\n\n return response;\n };\n}\n\n/** Turnkey middleware with default options. */\nexport const middleware = createWebsiteBuilderMiddleware();\n\n/** Default matcher: everything except Next internals, API routes, and static assets. */\nexport const config = {\n matcher: [\"/((?!_next|api|static|favicon.ico|.well-known).*)\"]\n};\n"],"names":["DEFAULT_PREVIEW_ROUTE","DEFAULT_VISITOR_COOKIE","ONE_YEAR_SECONDS","createWebsiteBuilderMiddleware","options","previewRoute","cookieName","cookieMaxAge","request","NextResponse","draftMode","searchParams","previewRequested","requestHeaders","Headers","previewMode","response","url","URL","crypto","middleware","config"],"mappings":"AAgBA,MAAMA,wBAAwB;AAC9B,MAAMC,yBAAyB;AAC/B,MAAMC,mBAAmB;AAmBlB,SAASC,+BAA+BC,UAA2C,CAAC,CAAC;IACxF,MAAMC,eAAeD,QAAQ,YAAY,IAAIJ;IAC7C,MAAMM,aAAaF,QAAQ,iBAAiB,IAAIH;IAChD,MAAMM,eAAeH,QAAQ,mBAAmB,IAAIF;IAEpD,OAAO,eAA0BM,OAA0B;QAEvD,MAAM,EAAEC,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC;QAEtC,MAAM,EAAEC,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC;QAEnC,MAAM,EAAEC,YAAY,EAAE,GAAGH,QAAQ,OAAO;QACxC,MAAMI,mBACFD,AAAmC,WAAnCA,aAAa,GAAG,CAAC,iBAA4BA,AAAmC,WAAnCA,aAAa,GAAG,CAAC;QAGlE,MAAME,iBAAiB,IAAIC,QAAQN,QAAQ,OAAO;QAClDK,eAAe,GAAG,CAAC,YAAYF,aAAa,GAAG,CAAC,gBAAgB;QAEhE,MAAMI,cAAc,MAAML;QAE1B,IAAIE,kBAAkB;YAClB,IAAIG,YAAY,SAAS,EAAE;gBAEvB,MAAMC,WAAWP,aAAa,IAAI,CAAC;oBAAE,SAAS;wBAAE,SAASI;oBAAe;gBAAE;gBAC1EG,SAAS,OAAO,CAAC,GAAG,CAAC,oBAAoBL,aAAa,QAAQ;gBAC9DK,SAAS,OAAO,CAAC,GAAG,CAChB,iBACA;gBAEJA,SAAS,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC/BA,SAAS,OAAO,CAAC,GAAG,CAAC,WAAW;gBAChC,OAAOA;YACX;YAEA,MAAMC,MAAM,IAAIC,IAAIV,QAAQ,GAAG;YAC/BS,IAAI,QAAQ,GAAGZ;YACf,OAAOI,aAAa,QAAQ,CAACQ;QACjC;QAEA,IAAIF,YAAY,SAAS,EAAE;YAEvBA,YAAY,OAAO;YACnB,OAAON,aAAa,QAAQ,CAACD,QAAQ,GAAG;QAC5C;QAEA,MAAMQ,WAAWP,aAAa,IAAI,CAAC;YAAE,SAAS;gBAAE,SAASI;YAAe;QAAE;QAK1E,IAAI,CAACL,QAAQ,OAAO,CAAC,GAAG,CAACF,aACrBU,SAAS,OAAO,CAAC,GAAG,CAACV,YAAYa,OAAO,UAAU,IAAI;YAClD,QAAQZ;YACR,MAAM;YACN,UAAU;QACd;QAGJ,OAAOS;IACX;AACJ;AAGO,MAAMI,wBAAajB;AAGnB,MAAMkB,SAAS;IAClB,SAAS;QAAC;KAAoD;AAClE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/website-builder-nextjs",
3
- "version": "6.4.11",
3
+ "version": "6.6.0-alpha.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,6 +8,7 @@
8
8
  },
9
9
  "exports": {
10
10
  ".": "./index.js",
11
+ "./middleware": "./middleware.js",
11
12
  "./webpack": "./webpack.js"
12
13
  },
13
14
  "description": "A Next.js integration SDK for Webiny Website Builder.",
@@ -18,19 +19,19 @@
18
19
  ],
19
20
  "license": "MIT",
20
21
  "dependencies": {
21
- "@webiny/website-builder-react": "6.4.11",
22
- "postcss": "8.5.16",
23
- "postcss-import": "16.1.1"
22
+ "@webiny/website-builder-react": "6.6.0-alpha.1",
23
+ "postcss": "8.5.26",
24
+ "postcss-import": "17.0.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@types/postcss-import": "14.0.3",
27
- "@webiny/build-tools": "6.4.11",
28
- "typescript": "6.0.3",
29
- "vitest": "4.1.10",
30
- "webpack": "5.108.4"
28
+ "@webiny/build-tools": "6.6.0-alpha.1",
29
+ "typescript": "7.0.2",
30
+ "vitest": "4.1.11",
31
+ "webpack": "5.109.2"
31
32
  },
32
33
  "peerDependencies": {
33
- "next": "16.2.10"
34
+ "next": "16.3.1"
34
35
  },
35
36
  "publishConfig": {
36
37
  "access": "public"