@preprio/toolkit 0.1.0-beta.3 → 0.1.0-beta.4

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.
@@ -30,7 +30,7 @@ __export(astro_exports, {
30
30
  module.exports = __toCommonJS(astro_exports);
31
31
 
32
32
  // src/version.ts
33
- var VERSION = "0.1.0-beta.3";
33
+ var VERSION = "0.1.0-beta.4";
34
34
 
35
35
  // src/core/server.ts
36
36
  var PreprError = class extends Error {
@@ -172,6 +172,20 @@ var UTM_PARAMS = [
172
172
  "utm_content",
173
173
  "utm_campaign"
174
174
  ];
175
+ function serializeCookie(cookie) {
176
+ const parts = [
177
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
178
+ `Max-Age=${cookie.maxAge}`,
179
+ `Path=${cookie.path}`
180
+ ];
181
+ if (cookie.sameSite) {
182
+ parts.push(`SameSite=${cookie.sameSite}`);
183
+ }
184
+ if (cookie.secure) {
185
+ parts.push("Secure");
186
+ }
187
+ return parts.join("; ");
188
+ }
175
189
  function parseCookies(request) {
176
190
  const cookies = /* @__PURE__ */ new Map();
177
191
  const header = request.headers.get("cookie");
@@ -190,7 +204,11 @@ function processPreprRequest(request, opts) {
190
204
  const requestHeaders = new Headers(request.headers);
191
205
  const responseCookies = [];
192
206
  const requestCookies = parseCookies(request);
193
- const searchParams = new URL(request.url).searchParams;
207
+ const url = new URL(request.url);
208
+ const searchParams = url.searchParams;
209
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
210
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
211
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
194
212
  for (const key of UTM_PARAMS) {
195
213
  const value = searchParams.get(key);
196
214
  if (value !== null) {
@@ -239,6 +257,15 @@ function processPreprRequest(request, opts) {
239
257
  }
240
258
  requestHeaders.set("Prepr-Preview-Bar", "true");
241
259
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
260
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
261
+ responseCookies.push({
262
+ name: COOKIE_PREVIEW_MODE,
263
+ value: "true",
264
+ maxAge: ONE_YEAR_SECONDS,
265
+ path: "/",
266
+ ...crossSite
267
+ });
268
+ }
242
269
  if (!isLivePreview) {
243
270
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
244
271
  if (segmentCookie) {
@@ -257,7 +284,8 @@ function processPreprRequest(request, opts) {
257
284
  name: COOKIE_VARIANT,
258
285
  value: previewAb,
259
286
  maxAge: ONE_YEAR_SECONDS,
260
- path: "/"
287
+ path: "/",
288
+ ...crossSite
261
289
  });
262
290
  }
263
291
  }
@@ -269,7 +297,8 @@ function processPreprRequest(request, opts) {
269
297
  name: COOKIE_SEGMENT,
270
298
  value: previewSegment,
271
299
  maxAge: ONE_YEAR_SECONDS,
272
- path: "/"
300
+ path: "/",
301
+ ...crossSite
273
302
  });
274
303
  }
275
304
  }
@@ -284,12 +313,7 @@ async function onPreprRequest(context, next, options) {
284
313
  });
285
314
  const response = await next();
286
315
  for (const cookie of responseCookies) {
287
- const parts = [
288
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
289
- `Max-Age=${cookie.maxAge}`,
290
- `Path=${cookie.path}`
291
- ];
292
- response.headers.append("Set-Cookie", parts.join("; "));
316
+ response.headers.append("Set-Cookie", serializeCookie(cookie));
293
317
  }
294
318
  return response;
295
319
  }
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.1.0-beta.3";
2
+ var VERSION = "0.1.0-beta.4";
3
3
 
4
4
  // src/core/server.ts
5
5
  var PreprError = class extends Error {
@@ -141,6 +141,20 @@ var UTM_PARAMS = [
141
141
  "utm_content",
142
142
  "utm_campaign"
143
143
  ];
144
+ function serializeCookie(cookie) {
145
+ const parts = [
146
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
147
+ `Max-Age=${cookie.maxAge}`,
148
+ `Path=${cookie.path}`
149
+ ];
150
+ if (cookie.sameSite) {
151
+ parts.push(`SameSite=${cookie.sameSite}`);
152
+ }
153
+ if (cookie.secure) {
154
+ parts.push("Secure");
155
+ }
156
+ return parts.join("; ");
157
+ }
144
158
  function parseCookies(request) {
145
159
  const cookies = /* @__PURE__ */ new Map();
146
160
  const header = request.headers.get("cookie");
@@ -159,7 +173,11 @@ function processPreprRequest(request, opts) {
159
173
  const requestHeaders = new Headers(request.headers);
160
174
  const responseCookies = [];
161
175
  const requestCookies = parseCookies(request);
162
- const searchParams = new URL(request.url).searchParams;
176
+ const url = new URL(request.url);
177
+ const searchParams = url.searchParams;
178
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
179
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
180
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
163
181
  for (const key of UTM_PARAMS) {
164
182
  const value = searchParams.get(key);
165
183
  if (value !== null) {
@@ -208,6 +226,15 @@ function processPreprRequest(request, opts) {
208
226
  }
209
227
  requestHeaders.set("Prepr-Preview-Bar", "true");
210
228
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
229
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
230
+ responseCookies.push({
231
+ name: COOKIE_PREVIEW_MODE,
232
+ value: "true",
233
+ maxAge: ONE_YEAR_SECONDS,
234
+ path: "/",
235
+ ...crossSite
236
+ });
237
+ }
211
238
  if (!isLivePreview) {
212
239
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
213
240
  if (segmentCookie) {
@@ -226,7 +253,8 @@ function processPreprRequest(request, opts) {
226
253
  name: COOKIE_VARIANT,
227
254
  value: previewAb,
228
255
  maxAge: ONE_YEAR_SECONDS,
229
- path: "/"
256
+ path: "/",
257
+ ...crossSite
230
258
  });
231
259
  }
232
260
  }
@@ -238,7 +266,8 @@ function processPreprRequest(request, opts) {
238
266
  name: COOKIE_SEGMENT,
239
267
  value: previewSegment,
240
268
  maxAge: ONE_YEAR_SECONDS,
241
- path: "/"
269
+ path: "/",
270
+ ...crossSite
242
271
  });
243
272
  }
244
273
  }
@@ -253,12 +282,7 @@ async function onPreprRequest(context, next, options) {
253
282
  });
254
283
  const response = await next();
255
284
  for (const cookie of responseCookies) {
256
- const parts = [
257
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
258
- `Max-Age=${cookie.maxAge}`,
259
- `Path=${cookie.path}`
260
- ];
261
- response.headers.append("Set-Cookie", parts.join("; "));
285
+ response.headers.append("Set-Cookie", serializeCookie(cookie));
262
286
  }
263
287
  return response;
264
288
  }
@@ -1704,16 +1704,34 @@ function getCookie(name) {
1704
1704
  }
1705
1705
  function setCookie(name, value, options = {}) {
1706
1706
  if (typeof document === "undefined") return;
1707
- const { maxAge, path = "/" } = options;
1707
+ const { maxAge, path = "/", sameSite, secure } = options;
1708
1708
  let cookie = `${name}=${encodeURIComponent(value)};path=${path}`;
1709
1709
  if (typeof maxAge === "number") {
1710
1710
  cookie += `;max-age=${maxAge}`;
1711
1711
  }
1712
+ if (sameSite) {
1713
+ cookie += `;samesite=${sameSite}`;
1714
+ }
1715
+ if (secure) {
1716
+ cookie += ";secure";
1717
+ }
1712
1718
  document.cookie = cookie;
1713
1719
  }
1714
- function removeCookie(name, path = "/") {
1720
+ function removeCookie(name, path = "/", options = {}) {
1715
1721
  if (typeof document === "undefined") return;
1716
- document.cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
1722
+ const { sameSite, secure } = options;
1723
+ let cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
1724
+ if (sameSite) {
1725
+ cookie += `;samesite=${sameSite}`;
1726
+ }
1727
+ if (secure) {
1728
+ cookie += ";secure";
1729
+ }
1730
+ document.cookie = cookie;
1731
+ }
1732
+ function crossSiteCookieOptions() {
1733
+ if (typeof window === "undefined" || !window.isSecureContext) return {};
1734
+ return { sameSite: "None", secure: true };
1717
1735
  }
1718
1736
 
1719
1737
  // src/core/locales/en.json
@@ -1844,7 +1862,13 @@ function createIframeBridge(store) {
1844
1862
  }
1845
1863
 
1846
1864
  // src/core/toolbar-change-handler.ts
1847
- var COOKIE_OPTS = { maxAge: ONE_YEAR_SECONDS, path: "/" };
1865
+ function cookieOpts() {
1866
+ return {
1867
+ maxAge: ONE_YEAR_SECONDS,
1868
+ path: "/",
1869
+ ...crossSiteCookieOptions()
1870
+ };
1871
+ }
1848
1872
  function createChangeHandler(deps) {
1849
1873
  const { store, stega, syncAutoClean } = deps;
1850
1874
  function updateParam(name, value) {
@@ -1861,9 +1885,9 @@ function createChangeHandler(deps) {
1861
1885
  return function handleChange(before, after) {
1862
1886
  if (before.selectedSegment !== after.selectedSegment) {
1863
1887
  if (after.selectedSegment === null) {
1864
- removeCookie(COOKIE_SEGMENT);
1888
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
1865
1889
  } else {
1866
- setCookie(COOKIE_SEGMENT, after.selectedSegment, COOKIE_OPTS);
1890
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
1867
1891
  }
1868
1892
  updateParam(PARAM_SEGMENT, after.selectedSegment);
1869
1893
  sendPreprEvent("segment_changed", {
@@ -1872,9 +1896,9 @@ function createChangeHandler(deps) {
1872
1896
  }
1873
1897
  if (before.selectedVariant !== after.selectedVariant) {
1874
1898
  if (after.selectedVariant === null) {
1875
- removeCookie(COOKIE_VARIANT);
1899
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
1876
1900
  } else {
1877
- setCookie(COOKIE_VARIANT, after.selectedVariant, COOKIE_OPTS);
1901
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
1878
1902
  }
1879
1903
  updateParam(PARAM_VARIANT, after.selectedVariant);
1880
1904
  sendPreprEvent("variant_changed", {
@@ -1900,8 +1924,8 @@ function createChangeHandler(deps) {
1900
1924
  if (Object.keys(coupled).length > 0) {
1901
1925
  store.set(coupled);
1902
1926
  }
1903
- setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), COOKIE_OPTS);
1904
- setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
1927
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1928
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
1905
1929
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
1906
1930
  syncAutoClean(after.previewMode);
1907
1931
  const [path, existing] = splitPath(deps.currentPath());
@@ -1916,7 +1940,7 @@ function createChangeHandler(deps) {
1916
1940
  }
1917
1941
  }
1918
1942
  if (before.toolbarOpen !== after.toolbarOpen) {
1919
- setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
1943
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
1920
1944
  }
1921
1945
  };
1922
1946
  }
package/dist/index.cjs CHANGED
@@ -43,7 +43,7 @@ __export(src_exports, {
43
43
  module.exports = __toCommonJS(src_exports);
44
44
 
45
45
  // src/version.ts
46
- var VERSION = "0.1.0-beta.3";
46
+ var VERSION = "0.1.0-beta.4";
47
47
 
48
48
  // src/core/constants.ts
49
49
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -67,16 +67,34 @@ function getCookie(name) {
67
67
  }
68
68
  function setCookie(name, value, options = {}) {
69
69
  if (typeof document === "undefined") return;
70
- const { maxAge, path = "/" } = options;
70
+ const { maxAge, path = "/", sameSite, secure } = options;
71
71
  let cookie = `${name}=${encodeURIComponent(value)};path=${path}`;
72
72
  if (typeof maxAge === "number") {
73
73
  cookie += `;max-age=${maxAge}`;
74
74
  }
75
+ if (sameSite) {
76
+ cookie += `;samesite=${sameSite}`;
77
+ }
78
+ if (secure) {
79
+ cookie += ";secure";
80
+ }
75
81
  document.cookie = cookie;
76
82
  }
77
- function removeCookie(name, path = "/") {
83
+ function removeCookie(name, path = "/", options = {}) {
78
84
  if (typeof document === "undefined") return;
79
- document.cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
85
+ const { sameSite, secure } = options;
86
+ let cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
87
+ if (sameSite) {
88
+ cookie += `;samesite=${sameSite}`;
89
+ }
90
+ if (secure) {
91
+ cookie += ";secure";
92
+ }
93
+ document.cookie = cookie;
94
+ }
95
+ function crossSiteCookieOptions() {
96
+ if (typeof window === "undefined" || !window.isSecureContext) return {};
97
+ return { sameSite: "None", secure: true };
80
98
  }
81
99
 
82
100
  // src/core/locales/en.json
@@ -933,7 +951,13 @@ function createToolbarStore(initial = {}) {
933
951
  }
934
952
 
935
953
  // src/core/toolbar-change-handler.ts
936
- var COOKIE_OPTS = { maxAge: ONE_YEAR_SECONDS, path: "/" };
954
+ function cookieOpts() {
955
+ return {
956
+ maxAge: ONE_YEAR_SECONDS,
957
+ path: "/",
958
+ ...crossSiteCookieOptions()
959
+ };
960
+ }
937
961
  function createChangeHandler(deps) {
938
962
  const { store, stega, syncAutoClean } = deps;
939
963
  function updateParam(name, value) {
@@ -950,9 +974,9 @@ function createChangeHandler(deps) {
950
974
  return function handleChange(before, after) {
951
975
  if (before.selectedSegment !== after.selectedSegment) {
952
976
  if (after.selectedSegment === null) {
953
- removeCookie(COOKIE_SEGMENT);
977
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
954
978
  } else {
955
- setCookie(COOKIE_SEGMENT, after.selectedSegment, COOKIE_OPTS);
979
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
956
980
  }
957
981
  updateParam(PARAM_SEGMENT, after.selectedSegment);
958
982
  sendPreprEvent("segment_changed", {
@@ -961,9 +985,9 @@ function createChangeHandler(deps) {
961
985
  }
962
986
  if (before.selectedVariant !== after.selectedVariant) {
963
987
  if (after.selectedVariant === null) {
964
- removeCookie(COOKIE_VARIANT);
988
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
965
989
  } else {
966
- setCookie(COOKIE_VARIANT, after.selectedVariant, COOKIE_OPTS);
990
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
967
991
  }
968
992
  updateParam(PARAM_VARIANT, after.selectedVariant);
969
993
  sendPreprEvent("variant_changed", {
@@ -989,8 +1013,8 @@ function createChangeHandler(deps) {
989
1013
  if (Object.keys(coupled).length > 0) {
990
1014
  store.set(coupled);
991
1015
  }
992
- setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), COOKIE_OPTS);
993
- setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
1016
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1017
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
994
1018
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
995
1019
  syncAutoClean(after.previewMode);
996
1020
  const [path, existing] = splitPath(deps.currentPath());
@@ -1005,7 +1029,7 @@ function createChangeHandler(deps) {
1005
1029
  }
1006
1030
  }
1007
1031
  if (before.toolbarOpen !== after.toolbarOpen) {
1008
- setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
1032
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
1009
1033
  }
1010
1034
  };
1011
1035
  }
@@ -2271,7 +2295,11 @@ function processPreprRequest(request, opts) {
2271
2295
  const requestHeaders = new Headers(request.headers);
2272
2296
  const responseCookies = [];
2273
2297
  const requestCookies = parseCookies(request);
2274
- const searchParams = new URL(request.url).searchParams;
2298
+ const url = new URL(request.url);
2299
+ const searchParams = url.searchParams;
2300
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
2301
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
2302
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
2275
2303
  for (const key of UTM_PARAMS) {
2276
2304
  const value = searchParams.get(key);
2277
2305
  if (value !== null) {
@@ -2320,6 +2348,15 @@ function processPreprRequest(request, opts) {
2320
2348
  }
2321
2349
  requestHeaders.set("Prepr-Preview-Bar", "true");
2322
2350
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
2351
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
2352
+ responseCookies.push({
2353
+ name: COOKIE_PREVIEW_MODE,
2354
+ value: "true",
2355
+ maxAge: ONE_YEAR_SECONDS,
2356
+ path: "/",
2357
+ ...crossSite
2358
+ });
2359
+ }
2323
2360
  if (!isLivePreview) {
2324
2361
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
2325
2362
  if (segmentCookie) {
@@ -2338,7 +2375,8 @@ function processPreprRequest(request, opts) {
2338
2375
  name: COOKIE_VARIANT,
2339
2376
  value: previewAb,
2340
2377
  maxAge: ONE_YEAR_SECONDS,
2341
- path: "/"
2378
+ path: "/",
2379
+ ...crossSite
2342
2380
  });
2343
2381
  }
2344
2382
  }
@@ -2350,7 +2388,8 @@ function processPreprRequest(request, opts) {
2350
2388
  name: COOKIE_SEGMENT,
2351
2389
  value: previewSegment,
2352
2390
  maxAge: ONE_YEAR_SECONDS,
2353
- path: "/"
2391
+ path: "/",
2392
+ ...crossSite
2354
2393
  });
2355
2394
  }
2356
2395
  }
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@ export { f as PreprEnvironment, g as PreprEventType, h as PreprHeaderName, i as
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.1.0-beta.3";
8
+ declare const VERSION = "0.1.0-beta.4";
9
9
 
10
10
  interface ToolbarState {
11
11
  locale: Locale;
@@ -160,6 +160,15 @@ interface CookieSpec {
160
160
  value: string;
161
161
  maxAge: number;
162
162
  path: string;
163
+ /**
164
+ * Set to `'None'` for cookies that must survive the Prepr editor's
165
+ * cross-site preview iframe — browsers drop the browser-default `Lax`
166
+ * cookies there. Always paired with `secure`, which browsers require for
167
+ * `SameSite=None`.
168
+ */
169
+ sameSite?: 'Strict' | 'Lax' | 'None';
170
+ /** Adds `Secure`. Required by browsers alongside `SameSite=None`. */
171
+ secure?: boolean;
163
172
  }
164
173
  interface PreprMiddlewareResult {
165
174
  requestHeaders: Headers;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { f as PreprEnvironment, g as PreprEventType, h as PreprHeaderName, i as
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.1.0-beta.3";
8
+ declare const VERSION = "0.1.0-beta.4";
9
9
 
10
10
  interface ToolbarState {
11
11
  locale: Locale;
@@ -160,6 +160,15 @@ interface CookieSpec {
160
160
  value: string;
161
161
  maxAge: number;
162
162
  path: string;
163
+ /**
164
+ * Set to `'None'` for cookies that must survive the Prepr editor's
165
+ * cross-site preview iframe — browsers drop the browser-default `Lax`
166
+ * cookies there. Always paired with `secure`, which browsers require for
167
+ * `SameSite=None`.
168
+ */
169
+ sameSite?: 'Strict' | 'Lax' | 'None';
170
+ /** Adds `Secure`. Required by browsers alongside `SameSite=None`. */
171
+ secure?: boolean;
163
172
  }
164
173
  interface PreprMiddlewareResult {
165
174
  requestHeaders: Headers;
package/dist/index.js CHANGED
@@ -16,10 +16,10 @@ import {
16
16
  setTrackingParam,
17
17
  stegaClean,
18
18
  trackEvent
19
- } from "./chunk-5JGPWQVA.js";
19
+ } from "./chunk-3FOY6KL4.js";
20
20
 
21
21
  // src/version.ts
22
- var VERSION = "0.1.0-beta.3";
22
+ var VERSION = "0.1.0-beta.4";
23
23
 
24
24
  // src/core/server.ts
25
25
  var PreprError = class extends Error {
@@ -198,7 +198,11 @@ function processPreprRequest(request, opts) {
198
198
  const requestHeaders = new Headers(request.headers);
199
199
  const responseCookies = [];
200
200
  const requestCookies = parseCookies(request);
201
- const searchParams = new URL(request.url).searchParams;
201
+ const url = new URL(request.url);
202
+ const searchParams = url.searchParams;
203
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
204
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
205
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
202
206
  for (const key of UTM_PARAMS) {
203
207
  const value = searchParams.get(key);
204
208
  if (value !== null) {
@@ -247,6 +251,15 @@ function processPreprRequest(request, opts) {
247
251
  }
248
252
  requestHeaders.set("Prepr-Preview-Bar", "true");
249
253
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
254
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
255
+ responseCookies.push({
256
+ name: COOKIE_PREVIEW_MODE,
257
+ value: "true",
258
+ maxAge: ONE_YEAR_SECONDS,
259
+ path: "/",
260
+ ...crossSite
261
+ });
262
+ }
250
263
  if (!isLivePreview) {
251
264
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
252
265
  if (segmentCookie) {
@@ -265,7 +278,8 @@ function processPreprRequest(request, opts) {
265
278
  name: COOKIE_VARIANT,
266
279
  value: previewAb,
267
280
  maxAge: ONE_YEAR_SECONDS,
268
- path: "/"
281
+ path: "/",
282
+ ...crossSite
269
283
  });
270
284
  }
271
285
  }
@@ -277,7 +291,8 @@ function processPreprRequest(request, opts) {
277
291
  name: COOKIE_SEGMENT,
278
292
  value: previewSegment,
279
293
  maxAge: ONE_YEAR_SECONDS,
280
- path: "/"
294
+ path: "/",
295
+ ...crossSite
281
296
  });
282
297
  }
283
298
  }
@@ -48,16 +48,34 @@ function getCookie(name) {
48
48
  }
49
49
  function setCookie(name, value, options = {}) {
50
50
  if (typeof document === "undefined") return;
51
- const { maxAge, path = "/" } = options;
51
+ const { maxAge, path = "/", sameSite, secure } = options;
52
52
  let cookie = `${name}=${encodeURIComponent(value)};path=${path}`;
53
53
  if (typeof maxAge === "number") {
54
54
  cookie += `;max-age=${maxAge}`;
55
55
  }
56
+ if (sameSite) {
57
+ cookie += `;samesite=${sameSite}`;
58
+ }
59
+ if (secure) {
60
+ cookie += ";secure";
61
+ }
56
62
  document.cookie = cookie;
57
63
  }
58
- function removeCookie(name, path = "/") {
64
+ function removeCookie(name, path = "/", options = {}) {
59
65
  if (typeof document === "undefined") return;
60
- document.cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
66
+ const { sameSite, secure } = options;
67
+ let cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
68
+ if (sameSite) {
69
+ cookie += `;samesite=${sameSite}`;
70
+ }
71
+ if (secure) {
72
+ cookie += ";secure";
73
+ }
74
+ document.cookie = cookie;
75
+ }
76
+ function crossSiteCookieOptions() {
77
+ if (typeof window === "undefined" || !window.isSecureContext) return {};
78
+ return { sameSite: "None", secure: true };
61
79
  }
62
80
 
63
81
  // src/core/locales/en.json
@@ -910,7 +928,13 @@ function createToolbarStore(initial = {}) {
910
928
  }
911
929
 
912
930
  // src/core/toolbar-change-handler.ts
913
- var COOKIE_OPTS = { maxAge: ONE_YEAR_SECONDS, path: "/" };
931
+ function cookieOpts() {
932
+ return {
933
+ maxAge: ONE_YEAR_SECONDS,
934
+ path: "/",
935
+ ...crossSiteCookieOptions()
936
+ };
937
+ }
914
938
  function createChangeHandler(deps) {
915
939
  const { store, stega, syncAutoClean } = deps;
916
940
  function updateParam(name, value) {
@@ -927,9 +951,9 @@ function createChangeHandler(deps) {
927
951
  return function handleChange(before, after) {
928
952
  if (before.selectedSegment !== after.selectedSegment) {
929
953
  if (after.selectedSegment === null) {
930
- removeCookie(COOKIE_SEGMENT);
954
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
931
955
  } else {
932
- setCookie(COOKIE_SEGMENT, after.selectedSegment, COOKIE_OPTS);
956
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
933
957
  }
934
958
  updateParam(PARAM_SEGMENT, after.selectedSegment);
935
959
  sendPreprEvent("segment_changed", {
@@ -938,9 +962,9 @@ function createChangeHandler(deps) {
938
962
  }
939
963
  if (before.selectedVariant !== after.selectedVariant) {
940
964
  if (after.selectedVariant === null) {
941
- removeCookie(COOKIE_VARIANT);
965
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
942
966
  } else {
943
- setCookie(COOKIE_VARIANT, after.selectedVariant, COOKIE_OPTS);
967
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
944
968
  }
945
969
  updateParam(PARAM_VARIANT, after.selectedVariant);
946
970
  sendPreprEvent("variant_changed", {
@@ -966,8 +990,8 @@ function createChangeHandler(deps) {
966
990
  if (Object.keys(coupled).length > 0) {
967
991
  store.set(coupled);
968
992
  }
969
- setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), COOKIE_OPTS);
970
- setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
993
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
994
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
971
995
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
972
996
  syncAutoClean(after.previewMode);
973
997
  const [path, existing] = splitPath(deps.currentPath());
@@ -982,7 +1006,7 @@ function createChangeHandler(deps) {
982
1006
  }
983
1007
  }
984
1008
  if (before.toolbarOpen !== after.toolbarOpen) {
985
- setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
1009
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
986
1010
  }
987
1011
  };
988
1012
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createPreprToolbar,
4
4
  loadTrackingPixel
5
- } from "../chunk-5JGPWQVA.js";
5
+ } from "../chunk-3FOY6KL4.js";
6
6
 
7
7
  // src/nextjs/components.ts
8
8
  import { usePathname, useRouter } from "next/navigation";
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(nextjs_exports);
38
38
  var import_server = require("next/server");
39
39
 
40
40
  // src/version.ts
41
- var VERSION = "0.1.0-beta.3";
41
+ var VERSION = "0.1.0-beta.4";
42
42
 
43
43
  // src/core/constants.ts
44
44
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -77,7 +77,11 @@ function processPreprRequest(request, opts) {
77
77
  const requestHeaders = new Headers(request.headers);
78
78
  const responseCookies = [];
79
79
  const requestCookies = parseCookies(request);
80
- const searchParams = new URL(request.url).searchParams;
80
+ const url = new URL(request.url);
81
+ const searchParams = url.searchParams;
82
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
83
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
84
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
81
85
  for (const key of UTM_PARAMS) {
82
86
  const value = searchParams.get(key);
83
87
  if (value !== null) {
@@ -126,6 +130,15 @@ function processPreprRequest(request, opts) {
126
130
  }
127
131
  requestHeaders.set("Prepr-Preview-Bar", "true");
128
132
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
133
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
134
+ responseCookies.push({
135
+ name: COOKIE_PREVIEW_MODE,
136
+ value: "true",
137
+ maxAge: ONE_YEAR_SECONDS,
138
+ path: "/",
139
+ ...crossSite
140
+ });
141
+ }
129
142
  if (!isLivePreview) {
130
143
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
131
144
  if (segmentCookie) {
@@ -144,7 +157,8 @@ function processPreprRequest(request, opts) {
144
157
  name: COOKIE_VARIANT,
145
158
  value: previewAb,
146
159
  maxAge: ONE_YEAR_SECONDS,
147
- path: "/"
160
+ path: "/",
161
+ ...crossSite
148
162
  });
149
163
  }
150
164
  }
@@ -156,7 +170,8 @@ function processPreprRequest(request, opts) {
156
170
  name: COOKIE_SEGMENT,
157
171
  value: previewSegment,
158
172
  maxAge: ONE_YEAR_SECONDS,
159
- path: "/"
173
+ path: "/",
174
+ ...crossSite
160
175
  });
161
176
  }
162
177
  }
@@ -183,7 +198,10 @@ function createPreprMiddleware(request, responseOrOptions, maybeOptions) {
183
198
  for (const cookie of responseCookies) {
184
199
  response.cookies.set(cookie.name, cookie.value, {
185
200
  maxAge: cookie.maxAge,
186
- path: cookie.path
201
+ path: cookie.path,
202
+ // Lower-cased: Next's cookie API expects 'none' | 'lax' | 'strict'.
203
+ ...cookie.sameSite ? { sameSite: cookie.sameSite.toLowerCase() } : {},
204
+ ...cookie.secure ? { secure: true } : {}
187
205
  });
188
206
  }
189
207
  return response;
@@ -2,7 +2,7 @@
2
2
  import { NextResponse } from "next/server";
3
3
 
4
4
  // src/version.ts
5
- var VERSION = "0.1.0-beta.3";
5
+ var VERSION = "0.1.0-beta.4";
6
6
 
7
7
  // src/core/constants.ts
8
8
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -41,7 +41,11 @@ function processPreprRequest(request, opts) {
41
41
  const requestHeaders = new Headers(request.headers);
42
42
  const responseCookies = [];
43
43
  const requestCookies = parseCookies(request);
44
- const searchParams = new URL(request.url).searchParams;
44
+ const url = new URL(request.url);
45
+ const searchParams = url.searchParams;
46
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
47
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
48
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
45
49
  for (const key of UTM_PARAMS) {
46
50
  const value = searchParams.get(key);
47
51
  if (value !== null) {
@@ -90,6 +94,15 @@ function processPreprRequest(request, opts) {
90
94
  }
91
95
  requestHeaders.set("Prepr-Preview-Bar", "true");
92
96
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
97
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
98
+ responseCookies.push({
99
+ name: COOKIE_PREVIEW_MODE,
100
+ value: "true",
101
+ maxAge: ONE_YEAR_SECONDS,
102
+ path: "/",
103
+ ...crossSite
104
+ });
105
+ }
93
106
  if (!isLivePreview) {
94
107
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
95
108
  if (segmentCookie) {
@@ -108,7 +121,8 @@ function processPreprRequest(request, opts) {
108
121
  name: COOKIE_VARIANT,
109
122
  value: previewAb,
110
123
  maxAge: ONE_YEAR_SECONDS,
111
- path: "/"
124
+ path: "/",
125
+ ...crossSite
112
126
  });
113
127
  }
114
128
  }
@@ -120,7 +134,8 @@ function processPreprRequest(request, opts) {
120
134
  name: COOKIE_SEGMENT,
121
135
  value: previewSegment,
122
136
  maxAge: ONE_YEAR_SECONDS,
123
- path: "/"
137
+ path: "/",
138
+ ...crossSite
124
139
  });
125
140
  }
126
141
  }
@@ -147,7 +162,10 @@ function createPreprMiddleware(request, responseOrOptions, maybeOptions) {
147
162
  for (const cookie of responseCookies) {
148
163
  response.cookies.set(cookie.name, cookie.value, {
149
164
  maxAge: cookie.maxAge,
150
- path: cookie.path
165
+ path: cookie.path,
166
+ // Lower-cased: Next's cookie API expects 'none' | 'lax' | 'strict'.
167
+ ...cookie.sameSite ? { sameSite: cookie.sameSite.toLowerCase() } : {},
168
+ ...cookie.secure ? { secure: true } : {}
151
169
  });
152
170
  }
153
171
  return response;
@@ -35,7 +35,7 @@ __export(nuxt_exports, {
35
35
  module.exports = __toCommonJS(nuxt_exports);
36
36
 
37
37
  // src/version.ts
38
- var VERSION = "0.1.0-beta.3";
38
+ var VERSION = "0.1.0-beta.4";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -56,6 +56,20 @@ var UTM_PARAMS = [
56
56
  "utm_content",
57
57
  "utm_campaign"
58
58
  ];
59
+ function serializeCookie(cookie) {
60
+ const parts = [
61
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
62
+ `Max-Age=${cookie.maxAge}`,
63
+ `Path=${cookie.path}`
64
+ ];
65
+ if (cookie.sameSite) {
66
+ parts.push(`SameSite=${cookie.sameSite}`);
67
+ }
68
+ if (cookie.secure) {
69
+ parts.push("Secure");
70
+ }
71
+ return parts.join("; ");
72
+ }
59
73
  function parseCookies(request) {
60
74
  const cookies = /* @__PURE__ */ new Map();
61
75
  const header = request.headers.get("cookie");
@@ -74,7 +88,11 @@ function processPreprRequest(request, opts) {
74
88
  const requestHeaders = new Headers(request.headers);
75
89
  const responseCookies = [];
76
90
  const requestCookies = parseCookies(request);
77
- const searchParams = new URL(request.url).searchParams;
91
+ const url = new URL(request.url);
92
+ const searchParams = url.searchParams;
93
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
94
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
95
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
78
96
  for (const key of UTM_PARAMS) {
79
97
  const value = searchParams.get(key);
80
98
  if (value !== null) {
@@ -123,6 +141,15 @@ function processPreprRequest(request, opts) {
123
141
  }
124
142
  requestHeaders.set("Prepr-Preview-Bar", "true");
125
143
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
144
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
145
+ responseCookies.push({
146
+ name: COOKIE_PREVIEW_MODE,
147
+ value: "true",
148
+ maxAge: ONE_YEAR_SECONDS,
149
+ path: "/",
150
+ ...crossSite
151
+ });
152
+ }
126
153
  if (!isLivePreview) {
127
154
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
128
155
  if (segmentCookie) {
@@ -141,7 +168,8 @@ function processPreprRequest(request, opts) {
141
168
  name: COOKIE_VARIANT,
142
169
  value: previewAb,
143
170
  maxAge: ONE_YEAR_SECONDS,
144
- path: "/"
171
+ path: "/",
172
+ ...crossSite
145
173
  });
146
174
  }
147
175
  }
@@ -153,7 +181,8 @@ function processPreprRequest(request, opts) {
153
181
  name: COOKIE_SEGMENT,
154
182
  value: previewSegment,
155
183
  maxAge: ONE_YEAR_SECONDS,
156
- path: "/"
184
+ path: "/",
185
+ ...crossSite
157
186
  });
158
187
  }
159
188
  }
@@ -179,12 +208,7 @@ function handlePreprRequest(event, options) {
179
208
  });
180
209
  event.context[PREPR_CONTEXT_KEY] = requestHeaders;
181
210
  for (const cookie of responseCookies) {
182
- const parts = [
183
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
184
- `Max-Age=${cookie.maxAge}`,
185
- `Path=${cookie.path}`
186
- ];
187
- event.node.res.appendHeader("Set-Cookie", parts.join("; "));
211
+ event.node.res.appendHeader("Set-Cookie", serializeCookie(cookie));
188
212
  }
189
213
  }
190
214
  function getPreprHeadersFromEvent(event) {
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.1.0-beta.3";
2
+ var VERSION = "0.1.0-beta.4";
3
3
 
4
4
  // src/core/constants.ts
5
5
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -20,6 +20,20 @@ var UTM_PARAMS = [
20
20
  "utm_content",
21
21
  "utm_campaign"
22
22
  ];
23
+ function serializeCookie(cookie) {
24
+ const parts = [
25
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
26
+ `Max-Age=${cookie.maxAge}`,
27
+ `Path=${cookie.path}`
28
+ ];
29
+ if (cookie.sameSite) {
30
+ parts.push(`SameSite=${cookie.sameSite}`);
31
+ }
32
+ if (cookie.secure) {
33
+ parts.push("Secure");
34
+ }
35
+ return parts.join("; ");
36
+ }
23
37
  function parseCookies(request) {
24
38
  const cookies = /* @__PURE__ */ new Map();
25
39
  const header = request.headers.get("cookie");
@@ -38,7 +52,11 @@ function processPreprRequest(request, opts) {
38
52
  const requestHeaders = new Headers(request.headers);
39
53
  const responseCookies = [];
40
54
  const requestCookies = parseCookies(request);
41
- const searchParams = new URL(request.url).searchParams;
55
+ const url = new URL(request.url);
56
+ const searchParams = url.searchParams;
57
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
58
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
59
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
42
60
  for (const key of UTM_PARAMS) {
43
61
  const value = searchParams.get(key);
44
62
  if (value !== null) {
@@ -87,6 +105,15 @@ function processPreprRequest(request, opts) {
87
105
  }
88
106
  requestHeaders.set("Prepr-Preview-Bar", "true");
89
107
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
108
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
109
+ responseCookies.push({
110
+ name: COOKIE_PREVIEW_MODE,
111
+ value: "true",
112
+ maxAge: ONE_YEAR_SECONDS,
113
+ path: "/",
114
+ ...crossSite
115
+ });
116
+ }
90
117
  if (!isLivePreview) {
91
118
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
92
119
  if (segmentCookie) {
@@ -105,7 +132,8 @@ function processPreprRequest(request, opts) {
105
132
  name: COOKIE_VARIANT,
106
133
  value: previewAb,
107
134
  maxAge: ONE_YEAR_SECONDS,
108
- path: "/"
135
+ path: "/",
136
+ ...crossSite
109
137
  });
110
138
  }
111
139
  }
@@ -117,7 +145,8 @@ function processPreprRequest(request, opts) {
117
145
  name: COOKIE_SEGMENT,
118
146
  value: previewSegment,
119
147
  maxAge: ONE_YEAR_SECONDS,
120
- path: "/"
148
+ path: "/",
149
+ ...crossSite
121
150
  });
122
151
  }
123
152
  }
@@ -143,12 +172,7 @@ function handlePreprRequest(event, options) {
143
172
  });
144
173
  event.context[PREPR_CONTEXT_KEY] = requestHeaders;
145
174
  for (const cookie of responseCookies) {
146
- const parts = [
147
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
148
- `Max-Age=${cookie.maxAge}`,
149
- `Path=${cookie.path}`
150
- ];
151
- event.node.res.appendHeader("Set-Cookie", parts.join("; "));
175
+ event.node.res.appendHeader("Set-Cookie", serializeCookie(cookie));
152
176
  }
153
177
  }
154
178
  function getPreprHeadersFromEvent(event) {
@@ -35,7 +35,7 @@ __export(sveltekit_exports, {
35
35
  module.exports = __toCommonJS(sveltekit_exports);
36
36
 
37
37
  // src/version.ts
38
- var VERSION = "0.1.0-beta.3";
38
+ var VERSION = "0.1.0-beta.4";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -56,6 +56,20 @@ var UTM_PARAMS = [
56
56
  "utm_content",
57
57
  "utm_campaign"
58
58
  ];
59
+ function serializeCookie(cookie) {
60
+ const parts = [
61
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
62
+ `Max-Age=${cookie.maxAge}`,
63
+ `Path=${cookie.path}`
64
+ ];
65
+ if (cookie.sameSite) {
66
+ parts.push(`SameSite=${cookie.sameSite}`);
67
+ }
68
+ if (cookie.secure) {
69
+ parts.push("Secure");
70
+ }
71
+ return parts.join("; ");
72
+ }
59
73
  function parseCookies(request) {
60
74
  const cookies = /* @__PURE__ */ new Map();
61
75
  const header = request.headers.get("cookie");
@@ -74,7 +88,11 @@ function processPreprRequest(request, opts) {
74
88
  const requestHeaders = new Headers(request.headers);
75
89
  const responseCookies = [];
76
90
  const requestCookies = parseCookies(request);
77
- const searchParams = new URL(request.url).searchParams;
91
+ const url = new URL(request.url);
92
+ const searchParams = url.searchParams;
93
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
94
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
95
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
78
96
  for (const key of UTM_PARAMS) {
79
97
  const value = searchParams.get(key);
80
98
  if (value !== null) {
@@ -123,6 +141,15 @@ function processPreprRequest(request, opts) {
123
141
  }
124
142
  requestHeaders.set("Prepr-Preview-Bar", "true");
125
143
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
144
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
145
+ responseCookies.push({
146
+ name: COOKIE_PREVIEW_MODE,
147
+ value: "true",
148
+ maxAge: ONE_YEAR_SECONDS,
149
+ path: "/",
150
+ ...crossSite
151
+ });
152
+ }
126
153
  if (!isLivePreview) {
127
154
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
128
155
  if (segmentCookie) {
@@ -141,7 +168,8 @@ function processPreprRequest(request, opts) {
141
168
  name: COOKIE_VARIANT,
142
169
  value: previewAb,
143
170
  maxAge: ONE_YEAR_SECONDS,
144
- path: "/"
171
+ path: "/",
172
+ ...crossSite
145
173
  });
146
174
  }
147
175
  }
@@ -153,7 +181,8 @@ function processPreprRequest(request, opts) {
153
181
  name: COOKIE_SEGMENT,
154
182
  value: previewSegment,
155
183
  maxAge: ONE_YEAR_SECONDS,
156
- path: "/"
184
+ path: "/",
185
+ ...crossSite
157
186
  });
158
187
  }
159
188
  }
@@ -173,12 +202,7 @@ function preprHandle(options) {
173
202
  }
174
203
  const response = await resolve(event);
175
204
  for (const cookie of responseCookies) {
176
- const parts = [
177
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
178
- `Max-Age=${cookie.maxAge}`,
179
- `Path=${cookie.path}`
180
- ];
181
- response.headers.append("Set-Cookie", parts.join("; "));
205
+ response.headers.append("Set-Cookie", serializeCookie(cookie));
182
206
  }
183
207
  return response;
184
208
  };
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.1.0-beta.3";
2
+ var VERSION = "0.1.0-beta.4";
3
3
 
4
4
  // src/core/constants.ts
5
5
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -20,6 +20,20 @@ var UTM_PARAMS = [
20
20
  "utm_content",
21
21
  "utm_campaign"
22
22
  ];
23
+ function serializeCookie(cookie) {
24
+ const parts = [
25
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
26
+ `Max-Age=${cookie.maxAge}`,
27
+ `Path=${cookie.path}`
28
+ ];
29
+ if (cookie.sameSite) {
30
+ parts.push(`SameSite=${cookie.sameSite}`);
31
+ }
32
+ if (cookie.secure) {
33
+ parts.push("Secure");
34
+ }
35
+ return parts.join("; ");
36
+ }
23
37
  function parseCookies(request) {
24
38
  const cookies = /* @__PURE__ */ new Map();
25
39
  const header = request.headers.get("cookie");
@@ -38,7 +52,11 @@ function processPreprRequest(request, opts) {
38
52
  const requestHeaders = new Headers(request.headers);
39
53
  const responseCookies = [];
40
54
  const requestCookies = parseCookies(request);
41
- const searchParams = new URL(request.url).searchParams;
55
+ const url = new URL(request.url);
56
+ const searchParams = url.searchParams;
57
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
58
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
59
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
42
60
  for (const key of UTM_PARAMS) {
43
61
  const value = searchParams.get(key);
44
62
  if (value !== null) {
@@ -87,6 +105,15 @@ function processPreprRequest(request, opts) {
87
105
  }
88
106
  requestHeaders.set("Prepr-Preview-Bar", "true");
89
107
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
108
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
109
+ responseCookies.push({
110
+ name: COOKIE_PREVIEW_MODE,
111
+ value: "true",
112
+ maxAge: ONE_YEAR_SECONDS,
113
+ path: "/",
114
+ ...crossSite
115
+ });
116
+ }
90
117
  if (!isLivePreview) {
91
118
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
92
119
  if (segmentCookie) {
@@ -105,7 +132,8 @@ function processPreprRequest(request, opts) {
105
132
  name: COOKIE_VARIANT,
106
133
  value: previewAb,
107
134
  maxAge: ONE_YEAR_SECONDS,
108
- path: "/"
135
+ path: "/",
136
+ ...crossSite
109
137
  });
110
138
  }
111
139
  }
@@ -117,7 +145,8 @@ function processPreprRequest(request, opts) {
117
145
  name: COOKIE_SEGMENT,
118
146
  value: previewSegment,
119
147
  maxAge: ONE_YEAR_SECONDS,
120
- path: "/"
148
+ path: "/",
149
+ ...crossSite
121
150
  });
122
151
  }
123
152
  }
@@ -137,12 +166,7 @@ function preprHandle(options) {
137
166
  }
138
167
  const response = await resolve(event);
139
168
  for (const cookie of responseCookies) {
140
- const parts = [
141
- `${cookie.name}=${encodeURIComponent(cookie.value)}`,
142
- `Max-Age=${cookie.maxAge}`,
143
- `Path=${cookie.path}`
144
- ];
145
- response.headers.append("Set-Cookie", parts.join("; "));
169
+ response.headers.append("Set-Cookie", serializeCookie(cookie));
146
170
  }
147
171
  return response;
148
172
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preprio/toolkit",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Prepr personalization, A/B testing and preview toolkit for Next.js, Nuxt, Astro, SvelteKit and Express",
5
5
  "license": "MIT",
6
6
  "repository": {