@preprio/toolkit 0.2.0-beta.4 → 0.2.0-beta.6

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.
@@ -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.2.0-beta.4";
41
+ var VERSION = "0.2.0-beta.6";
42
42
 
43
43
  // src/core/constants.ts
44
44
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -77,6 +77,11 @@ var UTM_PARAMS = [
77
77
  "utm_content",
78
78
  "utm_campaign"
79
79
  ];
80
+ var MAX_HEADER_VALUE_LENGTH = 2048;
81
+ function sanitizeHeaderValue(value) {
82
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
83
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
84
+ }
80
85
  function parseCookies(request) {
81
86
  const cookies = /* @__PURE__ */ new Map();
82
87
  const header = request.headers.get("cookie");
@@ -94,6 +99,15 @@ function parseCookies(request) {
94
99
  function processPreprRequest(request, opts) {
95
100
  const requestHeaders = new Headers(request.headers);
96
101
  const responseCookies = [];
102
+ const inboundPreprHeaders = [];
103
+ requestHeaders.forEach((_value, key) => {
104
+ if (key.toLowerCase().startsWith("prepr-")) {
105
+ inboundPreprHeaders.push(key);
106
+ }
107
+ });
108
+ for (const key of inboundPreprHeaders) {
109
+ requestHeaders.delete(key);
110
+ }
97
111
  const requestCookies = parseCookies(request);
98
112
  const url = new URL(request.url);
99
113
  const searchParams = url.searchParams;
@@ -103,25 +117,28 @@ function processPreprRequest(request, opts) {
103
117
  for (const key of UTM_PARAMS) {
104
118
  const value = searchParams.get(key);
105
119
  if (value !== null) {
106
- requestHeaders.set(`Prepr-Context-${key}`, value);
120
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
107
121
  }
108
122
  }
109
123
  const referer = request.headers.get("referer");
110
124
  if (referer) {
111
- requestHeaders.set("Prepr-Context-initial_referral", referer);
125
+ requestHeaders.set(
126
+ "Prepr-Context-initial_referral",
127
+ sanitizeHeaderValue(referer)
128
+ );
112
129
  }
113
130
  const userAgent = request.headers.get("user-agent");
114
131
  if (userAgent) {
115
- requestHeaders.set("Prepr-User-Agent", userAgent);
132
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
116
133
  }
117
134
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
118
135
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
119
136
  if (ip) {
120
- requestHeaders.set("Prepr-Visitor-IP", ip);
137
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
121
138
  }
122
139
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
123
140
  if (hutkCookie) {
124
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
141
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
125
142
  }
126
143
  let uid = requestCookies.get(COOKIE_UID);
127
144
  if (!uid) {
@@ -161,16 +178,16 @@ function processPreprRequest(request, opts) {
161
178
  if (!isLivePreview) {
162
179
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
163
180
  if (segmentCookie) {
164
- requestHeaders.set("Prepr-Segments", segmentCookie);
181
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
165
182
  }
166
183
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
167
184
  if (abCookie) {
168
- requestHeaders.set("Prepr-ABtesting", abCookie);
185
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
169
186
  }
170
187
  }
171
188
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
172
189
  if (previewAb !== null) {
173
- requestHeaders.set("Prepr-ABtesting", previewAb);
190
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
174
191
  if (!isLivePreview) {
175
192
  responseCookies.push({
176
193
  name: COOKIE_VARIANT,
@@ -183,7 +200,7 @@ function processPreprRequest(request, opts) {
183
200
  }
184
201
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
185
202
  if (previewSegment !== null) {
186
- requestHeaders.set("Prepr-Segments", previewSegment);
203
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
187
204
  if (!isLivePreview) {
188
205
  responseCookies.push({
189
206
  name: COOKIE_SEGMENT,
@@ -2,7 +2,7 @@
2
2
  import { NextResponse } from "next/server";
3
3
 
4
4
  // src/version.ts
5
- var VERSION = "0.2.0-beta.4";
5
+ var VERSION = "0.2.0-beta.6";
6
6
 
7
7
  // src/core/constants.ts
8
8
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -41,6 +41,11 @@ var UTM_PARAMS = [
41
41
  "utm_content",
42
42
  "utm_campaign"
43
43
  ];
44
+ var MAX_HEADER_VALUE_LENGTH = 2048;
45
+ function sanitizeHeaderValue(value) {
46
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
47
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
48
+ }
44
49
  function parseCookies(request) {
45
50
  const cookies = /* @__PURE__ */ new Map();
46
51
  const header = request.headers.get("cookie");
@@ -58,6 +63,15 @@ function parseCookies(request) {
58
63
  function processPreprRequest(request, opts) {
59
64
  const requestHeaders = new Headers(request.headers);
60
65
  const responseCookies = [];
66
+ const inboundPreprHeaders = [];
67
+ requestHeaders.forEach((_value, key) => {
68
+ if (key.toLowerCase().startsWith("prepr-")) {
69
+ inboundPreprHeaders.push(key);
70
+ }
71
+ });
72
+ for (const key of inboundPreprHeaders) {
73
+ requestHeaders.delete(key);
74
+ }
61
75
  const requestCookies = parseCookies(request);
62
76
  const url = new URL(request.url);
63
77
  const searchParams = url.searchParams;
@@ -67,25 +81,28 @@ function processPreprRequest(request, opts) {
67
81
  for (const key of UTM_PARAMS) {
68
82
  const value = searchParams.get(key);
69
83
  if (value !== null) {
70
- requestHeaders.set(`Prepr-Context-${key}`, value);
84
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
71
85
  }
72
86
  }
73
87
  const referer = request.headers.get("referer");
74
88
  if (referer) {
75
- requestHeaders.set("Prepr-Context-initial_referral", referer);
89
+ requestHeaders.set(
90
+ "Prepr-Context-initial_referral",
91
+ sanitizeHeaderValue(referer)
92
+ );
76
93
  }
77
94
  const userAgent = request.headers.get("user-agent");
78
95
  if (userAgent) {
79
- requestHeaders.set("Prepr-User-Agent", userAgent);
96
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
80
97
  }
81
98
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
82
99
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
83
100
  if (ip) {
84
- requestHeaders.set("Prepr-Visitor-IP", ip);
101
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
85
102
  }
86
103
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
87
104
  if (hutkCookie) {
88
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
105
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
89
106
  }
90
107
  let uid = requestCookies.get(COOKIE_UID);
91
108
  if (!uid) {
@@ -125,16 +142,16 @@ function processPreprRequest(request, opts) {
125
142
  if (!isLivePreview) {
126
143
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
127
144
  if (segmentCookie) {
128
- requestHeaders.set("Prepr-Segments", segmentCookie);
145
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
129
146
  }
130
147
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
131
148
  if (abCookie) {
132
- requestHeaders.set("Prepr-ABtesting", abCookie);
149
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
133
150
  }
134
151
  }
135
152
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
136
153
  if (previewAb !== null) {
137
- requestHeaders.set("Prepr-ABtesting", previewAb);
154
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
138
155
  if (!isLivePreview) {
139
156
  responseCookies.push({
140
157
  name: COOKIE_VARIANT,
@@ -147,7 +164,7 @@ function processPreprRequest(request, opts) {
147
164
  }
148
165
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
149
166
  if (previewSegment !== null) {
150
- requestHeaders.set("Prepr-Segments", previewSegment);
167
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
151
168
  if (!isLivePreview) {
152
169
  responseCookies.push({
153
170
  name: COOKIE_SEGMENT,
@@ -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.2.0-beta.4";
38
+ var VERSION = "0.2.0-beta.6";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -74,6 +74,11 @@ var UTM_PARAMS = [
74
74
  "utm_content",
75
75
  "utm_campaign"
76
76
  ];
77
+ var MAX_HEADER_VALUE_LENGTH = 2048;
78
+ function sanitizeHeaderValue(value) {
79
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
80
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
81
+ }
77
82
  function serializeCookie(cookie) {
78
83
  const parts = [
79
84
  `${cookie.name}=${encodeURIComponent(cookie.value)}`,
@@ -105,6 +110,15 @@ function parseCookies(request) {
105
110
  function processPreprRequest(request, opts) {
106
111
  const requestHeaders = new Headers(request.headers);
107
112
  const responseCookies = [];
113
+ const inboundPreprHeaders = [];
114
+ requestHeaders.forEach((_value, key) => {
115
+ if (key.toLowerCase().startsWith("prepr-")) {
116
+ inboundPreprHeaders.push(key);
117
+ }
118
+ });
119
+ for (const key of inboundPreprHeaders) {
120
+ requestHeaders.delete(key);
121
+ }
108
122
  const requestCookies = parseCookies(request);
109
123
  const url = new URL(request.url);
110
124
  const searchParams = url.searchParams;
@@ -114,25 +128,28 @@ function processPreprRequest(request, opts) {
114
128
  for (const key of UTM_PARAMS) {
115
129
  const value = searchParams.get(key);
116
130
  if (value !== null) {
117
- requestHeaders.set(`Prepr-Context-${key}`, value);
131
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
118
132
  }
119
133
  }
120
134
  const referer = request.headers.get("referer");
121
135
  if (referer) {
122
- requestHeaders.set("Prepr-Context-initial_referral", referer);
136
+ requestHeaders.set(
137
+ "Prepr-Context-initial_referral",
138
+ sanitizeHeaderValue(referer)
139
+ );
123
140
  }
124
141
  const userAgent = request.headers.get("user-agent");
125
142
  if (userAgent) {
126
- requestHeaders.set("Prepr-User-Agent", userAgent);
143
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
127
144
  }
128
145
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
129
146
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
130
147
  if (ip) {
131
- requestHeaders.set("Prepr-Visitor-IP", ip);
148
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
132
149
  }
133
150
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
134
151
  if (hutkCookie) {
135
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
152
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
136
153
  }
137
154
  let uid = requestCookies.get(COOKIE_UID);
138
155
  if (!uid) {
@@ -172,16 +189,16 @@ function processPreprRequest(request, opts) {
172
189
  if (!isLivePreview) {
173
190
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
174
191
  if (segmentCookie) {
175
- requestHeaders.set("Prepr-Segments", segmentCookie);
192
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
176
193
  }
177
194
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
178
195
  if (abCookie) {
179
- requestHeaders.set("Prepr-ABtesting", abCookie);
196
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
180
197
  }
181
198
  }
182
199
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
183
200
  if (previewAb !== null) {
184
- requestHeaders.set("Prepr-ABtesting", previewAb);
201
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
185
202
  if (!isLivePreview) {
186
203
  responseCookies.push({
187
204
  name: COOKIE_VARIANT,
@@ -194,7 +211,7 @@ function processPreprRequest(request, opts) {
194
211
  }
195
212
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
196
213
  if (previewSegment !== null) {
197
- requestHeaders.set("Prepr-Segments", previewSegment);
214
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
198
215
  if (!isLivePreview) {
199
216
  responseCookies.push({
200
217
  name: COOKIE_SEGMENT,
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.2.0-beta.4";
2
+ var VERSION = "0.2.0-beta.6";
3
3
 
4
4
  // src/core/constants.ts
5
5
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -38,6 +38,11 @@ var UTM_PARAMS = [
38
38
  "utm_content",
39
39
  "utm_campaign"
40
40
  ];
41
+ var MAX_HEADER_VALUE_LENGTH = 2048;
42
+ function sanitizeHeaderValue(value) {
43
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
44
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
45
+ }
41
46
  function serializeCookie(cookie) {
42
47
  const parts = [
43
48
  `${cookie.name}=${encodeURIComponent(cookie.value)}`,
@@ -69,6 +74,15 @@ function parseCookies(request) {
69
74
  function processPreprRequest(request, opts) {
70
75
  const requestHeaders = new Headers(request.headers);
71
76
  const responseCookies = [];
77
+ const inboundPreprHeaders = [];
78
+ requestHeaders.forEach((_value, key) => {
79
+ if (key.toLowerCase().startsWith("prepr-")) {
80
+ inboundPreprHeaders.push(key);
81
+ }
82
+ });
83
+ for (const key of inboundPreprHeaders) {
84
+ requestHeaders.delete(key);
85
+ }
72
86
  const requestCookies = parseCookies(request);
73
87
  const url = new URL(request.url);
74
88
  const searchParams = url.searchParams;
@@ -78,25 +92,28 @@ function processPreprRequest(request, opts) {
78
92
  for (const key of UTM_PARAMS) {
79
93
  const value = searchParams.get(key);
80
94
  if (value !== null) {
81
- requestHeaders.set(`Prepr-Context-${key}`, value);
95
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
82
96
  }
83
97
  }
84
98
  const referer = request.headers.get("referer");
85
99
  if (referer) {
86
- requestHeaders.set("Prepr-Context-initial_referral", referer);
100
+ requestHeaders.set(
101
+ "Prepr-Context-initial_referral",
102
+ sanitizeHeaderValue(referer)
103
+ );
87
104
  }
88
105
  const userAgent = request.headers.get("user-agent");
89
106
  if (userAgent) {
90
- requestHeaders.set("Prepr-User-Agent", userAgent);
107
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
91
108
  }
92
109
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
93
110
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
94
111
  if (ip) {
95
- requestHeaders.set("Prepr-Visitor-IP", ip);
112
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
96
113
  }
97
114
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
98
115
  if (hutkCookie) {
99
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
116
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
100
117
  }
101
118
  let uid = requestCookies.get(COOKIE_UID);
102
119
  if (!uid) {
@@ -136,16 +153,16 @@ function processPreprRequest(request, opts) {
136
153
  if (!isLivePreview) {
137
154
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
138
155
  if (segmentCookie) {
139
- requestHeaders.set("Prepr-Segments", segmentCookie);
156
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
140
157
  }
141
158
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
142
159
  if (abCookie) {
143
- requestHeaders.set("Prepr-ABtesting", abCookie);
160
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
144
161
  }
145
162
  }
146
163
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
147
164
  if (previewAb !== null) {
148
- requestHeaders.set("Prepr-ABtesting", previewAb);
165
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
149
166
  if (!isLivePreview) {
150
167
  responseCookies.push({
151
168
  name: COOKIE_VARIANT,
@@ -158,7 +175,7 @@ function processPreprRequest(request, opts) {
158
175
  }
159
176
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
160
177
  if (previewSegment !== null) {
161
- requestHeaders.set("Prepr-Segments", previewSegment);
178
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
162
179
  if (!isLivePreview) {
163
180
  responseCookies.push({
164
181
  name: COOKIE_SEGMENT,
@@ -334,7 +334,10 @@ function createIframeBridge(store, options = {}) {
334
334
  };
335
335
  return {
336
336
  start() {
337
- sendPreprEvent("loaded", void 0, { allowUntrustedTarget: true });
337
+ const features = store?.get().features;
338
+ sendPreprEvent("loaded", features ? { features } : void 0, {
339
+ allowUntrustedTarget: true
340
+ });
338
341
  window.addEventListener("keydown", onKeyDown);
339
342
  window.addEventListener("message", onMessage);
340
343
  },
@@ -1711,8 +1714,8 @@ function Panel({
1711
1714
  "aria-label": t3("common.toolbar"),
1712
1715
  children: [
1713
1716
  /* @__PURE__ */ u2(Header, { t: t3, onClose: handlers.onClose }),
1714
- /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
1715
- /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: showAdaptive ? t3("adaptiveContent.adaptiveContent") : t3("adaptiveContent.enablePreview") }),
1717
+ showAdaptive && /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
1718
+ /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: t3("adaptiveContent.adaptiveContent") }),
1716
1719
  /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
1717
1720
  /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "preview-label", children: t3("adaptiveContent.enablePreview") }),
1718
1721
  /* @__PURE__ */ u2(PreviewSelector, { state, t: t3, handlers })
@@ -2049,6 +2052,14 @@ function defaultNavigation() {
2049
2052
  currentPath: () => window.location.pathname + window.location.search
2050
2053
  };
2051
2054
  }
2055
+ function safeEditUrl(href) {
2056
+ try {
2057
+ const url = new URL(href, window.location.href);
2058
+ return url.protocol === "https:" || url.protocol === "http:" ? url.href : null;
2059
+ } catch {
2060
+ return null;
2061
+ }
2062
+ }
2052
2063
  function buildSegments(data) {
2053
2064
  return [{ _id: "all_other_users", name: "All other users" }, ...data];
2054
2065
  }
@@ -2112,10 +2123,20 @@ function createPreprPreview(opts = {}) {
2112
2123
  // In the editor, ask the parent to focus the field instead of opening a new
2113
2124
  // tab. Standalone previews keep the window.open behaviour.
2114
2125
  onEdit: ({ href, origin, id, field }) => {
2126
+ const safeHref = href ? safeEditUrl(href) : null;
2127
+ if (href && !safeHref) {
2128
+ debug7.warn("ignored edit request with unsupported href scheme");
2129
+ return;
2130
+ }
2115
2131
  if (isIframe) {
2116
- sendPreprEvent("field_edit_requested", { href, origin, id, field });
2117
- } else if (href) {
2118
- window.open(href);
2132
+ sendPreprEvent("field_edit_requested", {
2133
+ href: safeHref ?? void 0,
2134
+ origin,
2135
+ id,
2136
+ field
2137
+ });
2138
+ } else if (safeHref) {
2139
+ window.open(safeHref, "_blank", "noopener,noreferrer");
2119
2140
  }
2120
2141
  }
2121
2142
  });
@@ -310,7 +310,10 @@ function createIframeBridge(store, options = {}) {
310
310
  };
311
311
  return {
312
312
  start() {
313
- sendPreprEvent("loaded", void 0, { allowUntrustedTarget: true });
313
+ const features = store?.get().features;
314
+ sendPreprEvent("loaded", features ? { features } : void 0, {
315
+ allowUntrustedTarget: true
316
+ });
314
317
  window.addEventListener("keydown", onKeyDown);
315
318
  window.addEventListener("message", onMessage);
316
319
  },
@@ -1687,8 +1690,8 @@ function Panel({
1687
1690
  "aria-label": t3("common.toolbar"),
1688
1691
  children: [
1689
1692
  /* @__PURE__ */ u2(Header, { t: t3, onClose: handlers.onClose }),
1690
- /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
1691
- /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: showAdaptive ? t3("adaptiveContent.adaptiveContent") : t3("adaptiveContent.enablePreview") }),
1693
+ showAdaptive && /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
1694
+ /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: t3("adaptiveContent.adaptiveContent") }),
1692
1695
  /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
1693
1696
  /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "preview-label", children: t3("adaptiveContent.enablePreview") }),
1694
1697
  /* @__PURE__ */ u2(PreviewSelector, { state, t: t3, handlers })
@@ -2025,6 +2028,14 @@ function defaultNavigation() {
2025
2028
  currentPath: () => window.location.pathname + window.location.search
2026
2029
  };
2027
2030
  }
2031
+ function safeEditUrl(href) {
2032
+ try {
2033
+ const url = new URL(href, window.location.href);
2034
+ return url.protocol === "https:" || url.protocol === "http:" ? url.href : null;
2035
+ } catch {
2036
+ return null;
2037
+ }
2038
+ }
2028
2039
  function buildSegments(data) {
2029
2040
  return [{ _id: "all_other_users", name: "All other users" }, ...data];
2030
2041
  }
@@ -2088,10 +2099,20 @@ function createPreprPreview(opts = {}) {
2088
2099
  // In the editor, ask the parent to focus the field instead of opening a new
2089
2100
  // tab. Standalone previews keep the window.open behaviour.
2090
2101
  onEdit: ({ href, origin, id, field }) => {
2102
+ const safeHref = href ? safeEditUrl(href) : null;
2103
+ if (href && !safeHref) {
2104
+ debug7.warn("ignored edit request with unsupported href scheme");
2105
+ return;
2106
+ }
2091
2107
  if (isIframe) {
2092
- sendPreprEvent("field_edit_requested", { href, origin, id, field });
2093
- } else if (href) {
2094
- window.open(href);
2108
+ sendPreprEvent("field_edit_requested", {
2109
+ href: safeHref ?? void 0,
2110
+ origin,
2111
+ id,
2112
+ field
2113
+ });
2114
+ } else if (safeHref) {
2115
+ window.open(safeHref, "_blank", "noopener,noreferrer");
2095
2116
  }
2096
2117
  }
2097
2118
  });
@@ -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.2.0-beta.4";
38
+ var VERSION = "0.2.0-beta.6";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -74,6 +74,11 @@ var UTM_PARAMS = [
74
74
  "utm_content",
75
75
  "utm_campaign"
76
76
  ];
77
+ var MAX_HEADER_VALUE_LENGTH = 2048;
78
+ function sanitizeHeaderValue(value) {
79
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
80
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
81
+ }
77
82
  function serializeCookie(cookie) {
78
83
  const parts = [
79
84
  `${cookie.name}=${encodeURIComponent(cookie.value)}`,
@@ -105,6 +110,15 @@ function parseCookies(request) {
105
110
  function processPreprRequest(request, opts) {
106
111
  const requestHeaders = new Headers(request.headers);
107
112
  const responseCookies = [];
113
+ const inboundPreprHeaders = [];
114
+ requestHeaders.forEach((_value, key) => {
115
+ if (key.toLowerCase().startsWith("prepr-")) {
116
+ inboundPreprHeaders.push(key);
117
+ }
118
+ });
119
+ for (const key of inboundPreprHeaders) {
120
+ requestHeaders.delete(key);
121
+ }
108
122
  const requestCookies = parseCookies(request);
109
123
  const url = new URL(request.url);
110
124
  const searchParams = url.searchParams;
@@ -114,25 +128,28 @@ function processPreprRequest(request, opts) {
114
128
  for (const key of UTM_PARAMS) {
115
129
  const value = searchParams.get(key);
116
130
  if (value !== null) {
117
- requestHeaders.set(`Prepr-Context-${key}`, value);
131
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
118
132
  }
119
133
  }
120
134
  const referer = request.headers.get("referer");
121
135
  if (referer) {
122
- requestHeaders.set("Prepr-Context-initial_referral", referer);
136
+ requestHeaders.set(
137
+ "Prepr-Context-initial_referral",
138
+ sanitizeHeaderValue(referer)
139
+ );
123
140
  }
124
141
  const userAgent = request.headers.get("user-agent");
125
142
  if (userAgent) {
126
- requestHeaders.set("Prepr-User-Agent", userAgent);
143
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
127
144
  }
128
145
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
129
146
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
130
147
  if (ip) {
131
- requestHeaders.set("Prepr-Visitor-IP", ip);
148
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
132
149
  }
133
150
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
134
151
  if (hutkCookie) {
135
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
152
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
136
153
  }
137
154
  let uid = requestCookies.get(COOKIE_UID);
138
155
  if (!uid) {
@@ -172,16 +189,16 @@ function processPreprRequest(request, opts) {
172
189
  if (!isLivePreview) {
173
190
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
174
191
  if (segmentCookie) {
175
- requestHeaders.set("Prepr-Segments", segmentCookie);
192
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
176
193
  }
177
194
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
178
195
  if (abCookie) {
179
- requestHeaders.set("Prepr-ABtesting", abCookie);
196
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
180
197
  }
181
198
  }
182
199
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
183
200
  if (previewAb !== null) {
184
- requestHeaders.set("Prepr-ABtesting", previewAb);
201
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
185
202
  if (!isLivePreview) {
186
203
  responseCookies.push({
187
204
  name: COOKIE_VARIANT,
@@ -194,7 +211,7 @@ function processPreprRequest(request, opts) {
194
211
  }
195
212
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
196
213
  if (previewSegment !== null) {
197
- requestHeaders.set("Prepr-Segments", previewSegment);
214
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
198
215
  if (!isLivePreview) {
199
216
  responseCookies.push({
200
217
  name: COOKIE_SEGMENT,