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

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.
@@ -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
@@ -151,7 +169,11 @@ function t(key, locale, vars) {
151
169
  }
152
170
 
153
171
  // src/core/utils.ts
154
- function sendPreprEvent(event, data) {
172
+ var trustedParentOrigin = null;
173
+ function setTrustedParentOrigin(origin) {
174
+ trustedParentOrigin = origin;
175
+ }
176
+ function sendPreprEvent(event, data, options) {
155
177
  if (typeof window !== "undefined") {
156
178
  const message = {
157
179
  name: "prepr_preview_bar",
@@ -162,7 +184,11 @@ function sendPreprEvent(event, data) {
162
184
  new CustomEvent("prepr_preview_bar", { detail: message })
163
185
  );
164
186
  if (window.parent && window.parent !== window) {
165
- window.parent.postMessage(message, "*");
187
+ if (trustedParentOrigin) {
188
+ window.parent.postMessage(message, trustedParentOrigin);
189
+ } else if (options?.allowUntrustedTarget) {
190
+ window.parent.postMessage(message, "*");
191
+ }
166
192
  }
167
193
  }
168
194
  }
@@ -248,7 +274,23 @@ function createElementCache(query, ttl = 1e3) {
248
274
  }
249
275
 
250
276
  // src/core/iframe-bridge.ts
251
- function createIframeBridge(store) {
277
+ var EDITOR_BASE_DOMAIN = "prepr.io";
278
+ function isAllowedEditorOrigin(origin, allowed) {
279
+ if (allowed) return allowed.includes(origin);
280
+ let url;
281
+ try {
282
+ url = new URL(origin);
283
+ } catch {
284
+ return false;
285
+ }
286
+ if (url.protocol !== "https:" || url.port !== "") return false;
287
+ const suffix = `.${EDITOR_BASE_DOMAIN}`;
288
+ if (!url.hostname.endsWith(suffix)) return false;
289
+ const label = url.hostname.slice(0, -suffix.length);
290
+ return label.length > 0 && !label.includes(".");
291
+ }
292
+ function createIframeBridge(store, options = {}) {
293
+ const allowedOrigins = options.allowedEditorOrigins;
252
294
  let parentOrigin = null;
253
295
  const onKeyDown = (event) => {
254
296
  const key = event.key.toLowerCase();
@@ -258,14 +300,16 @@ function createIframeBridge(store) {
258
300
  const onMessage = (evt) => {
259
301
  const data = evt?.data;
260
302
  if (data?.event === "prepr:initVE" && !parentOrigin) {
303
+ if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) return;
261
304
  parentOrigin = evt.origin;
305
+ setTrustedParentOrigin(parentOrigin);
262
306
  if (data.scrollPosition != null) {
263
307
  const top = data.scrollPosition;
264
308
  setTimeout(() => window.scrollTo(0, top), 1);
265
309
  }
266
310
  store.set({ previewMode: true, editMode: data.editMode ?? true });
267
311
  }
268
- if (evt.origin !== parentOrigin) return;
312
+ if (!parentOrigin || evt.origin !== parentOrigin) return;
269
313
  if (data?.event === "prepr:getScrollPosition") {
270
314
  const currentScrollY = window.scrollY || document.documentElement.scrollTop;
271
315
  sendPreprEvent("getScrollPosition", { value: currentScrollY });
@@ -273,13 +317,15 @@ function createIframeBridge(store) {
273
317
  };
274
318
  return {
275
319
  start() {
276
- sendPreprEvent("loaded");
320
+ sendPreprEvent("loaded", void 0, { allowUntrustedTarget: true });
277
321
  window.addEventListener("keydown", onKeyDown);
278
322
  window.addEventListener("message", onMessage);
279
323
  },
280
324
  stop() {
281
325
  window.removeEventListener("keydown", onKeyDown);
282
326
  window.removeEventListener("message", onMessage);
327
+ parentOrigin = null;
328
+ setTrustedParentOrigin(null);
283
329
  }
284
330
  };
285
331
  }
@@ -910,43 +956,55 @@ function createToolbarStore(initial = {}) {
910
956
  }
911
957
 
912
958
  // src/core/toolbar-change-handler.ts
913
- var COOKIE_OPTS = { maxAge: ONE_YEAR_SECONDS, path: "/" };
959
+ function cookieOpts() {
960
+ return {
961
+ maxAge: ONE_YEAR_SECONDS,
962
+ path: "/",
963
+ ...crossSiteCookieOptions()
964
+ };
965
+ }
914
966
  function createChangeHandler(deps) {
915
967
  const { store, stega, syncAutoClean } = deps;
916
- function updateParam(name, value) {
968
+ function updateParams(patch) {
917
969
  const [path, existing] = splitPath(deps.currentPath());
918
970
  const params = new URLSearchParams(existing);
919
- if (value === null) {
920
- params.delete(name);
921
- } else {
922
- params.set(name, value);
971
+ for (const [name, value] of Object.entries(patch)) {
972
+ if (value === null) {
973
+ params.delete(name);
974
+ } else {
975
+ params.set(name, value);
976
+ }
923
977
  }
924
978
  const query = params.toString();
925
979
  deps.navigate(query ? `${path}?${query}` : path);
926
980
  }
927
981
  return function handleChange(before, after) {
982
+ const paramPatch = {};
928
983
  if (before.selectedSegment !== after.selectedSegment) {
929
984
  if (after.selectedSegment === null) {
930
- removeCookie(COOKIE_SEGMENT);
985
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
931
986
  } else {
932
- setCookie(COOKIE_SEGMENT, after.selectedSegment, COOKIE_OPTS);
987
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
933
988
  }
934
- updateParam(PARAM_SEGMENT, after.selectedSegment);
989
+ paramPatch[PARAM_SEGMENT] = after.selectedSegment;
935
990
  sendPreprEvent("segment_changed", {
936
991
  segment: after.selectedSegment ?? void 0
937
992
  });
938
993
  }
939
994
  if (before.selectedVariant !== after.selectedVariant) {
940
995
  if (after.selectedVariant === null) {
941
- removeCookie(COOKIE_VARIANT);
996
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
942
997
  } else {
943
- setCookie(COOKIE_VARIANT, after.selectedVariant, COOKIE_OPTS);
998
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
944
999
  }
945
- updateParam(PARAM_VARIANT, after.selectedVariant);
1000
+ paramPatch[PARAM_VARIANT] = after.selectedVariant;
946
1001
  sendPreprEvent("variant_changed", {
947
1002
  variant: after.selectedVariant ?? void 0
948
1003
  });
949
1004
  }
1005
+ if (Object.keys(paramPatch).length > 0) {
1006
+ updateParams(paramPatch);
1007
+ }
950
1008
  if (before.editMode !== after.editMode) {
951
1009
  if (after.editMode) {
952
1010
  stega.start();
@@ -966,8 +1024,8 @@ function createChangeHandler(deps) {
966
1024
  if (Object.keys(coupled).length > 0) {
967
1025
  store.set(coupled);
968
1026
  }
969
- setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), COOKIE_OPTS);
970
- setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
1027
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1028
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
971
1029
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
972
1030
  syncAutoClean(after.previewMode);
973
1031
  const [path, existing] = splitPath(deps.currentPath());
@@ -982,7 +1040,7 @@ function createChangeHandler(deps) {
982
1040
  }
983
1041
  }
984
1042
  if (before.toolbarOpen !== after.toolbarOpen) {
985
- setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
1043
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
986
1044
  }
987
1045
  };
988
1046
  }
@@ -2052,7 +2110,9 @@ function createPreprToolbar(opts) {
2052
2110
  });
2053
2111
  syncAutoClean(store.get().previewMode);
2054
2112
  const bridge = createIframeBridge(store);
2055
- sendPreprEvent("getScrollPosition", { value: 0 });
2113
+ sendPreprEvent("getScrollPosition", { value: 0 }, {
2114
+ allowUntrustedTarget: true
2115
+ });
2056
2116
  if (isIframe) {
2057
2117
  bridge.start();
2058
2118
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createPreprToolbar,
4
4
  loadTrackingPixel
5
- } from "../chunk-5JGPWQVA.js";
5
+ } from "../chunk-NLQIRN5O.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.5";
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.5";
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.5";
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.5";
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.5";
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
  };