@preprio/toolkit 0.2.0-beta.5 → 0.2.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -17,10 +17,10 @@ import {
17
17
  setTrackingParam,
18
18
  stegaClean,
19
19
  trackEvent
20
- } from "./chunk-BYJ2JBGX.js";
20
+ } from "./chunk-P6VTLWM4.js";
21
21
 
22
22
  // src/version.ts
23
- var VERSION = "0.2.0-beta.5";
23
+ var VERSION = "0.2.0-beta.7";
24
24
 
25
25
  // src/core/server.ts
26
26
  var PreprError = class extends Error {
@@ -184,6 +184,11 @@ var UTM_PARAMS = [
184
184
  "utm_content",
185
185
  "utm_campaign"
186
186
  ];
187
+ var MAX_HEADER_VALUE_LENGTH = 2048;
188
+ function sanitizeHeaderValue(value) {
189
+ const stripped = value.replace(/[\u0000-\u001f\u007f]/g, "");
190
+ return stripped.length > MAX_HEADER_VALUE_LENGTH ? stripped.slice(0, MAX_HEADER_VALUE_LENGTH) : stripped;
191
+ }
187
192
  function parseCookies(request) {
188
193
  const cookies = /* @__PURE__ */ new Map();
189
194
  const header = request.headers.get("cookie");
@@ -201,6 +206,15 @@ function parseCookies(request) {
201
206
  function processPreprRequest(request, opts) {
202
207
  const requestHeaders = new Headers(request.headers);
203
208
  const responseCookies = [];
209
+ const inboundPreprHeaders = [];
210
+ requestHeaders.forEach((_value, key) => {
211
+ if (key.toLowerCase().startsWith("prepr-")) {
212
+ inboundPreprHeaders.push(key);
213
+ }
214
+ });
215
+ for (const key of inboundPreprHeaders) {
216
+ requestHeaders.delete(key);
217
+ }
204
218
  const requestCookies = parseCookies(request);
205
219
  const url = new URL(request.url);
206
220
  const searchParams = url.searchParams;
@@ -210,25 +224,28 @@ function processPreprRequest(request, opts) {
210
224
  for (const key of UTM_PARAMS) {
211
225
  const value = searchParams.get(key);
212
226
  if (value !== null) {
213
- requestHeaders.set(`Prepr-Context-${key}`, value);
227
+ requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
214
228
  }
215
229
  }
216
230
  const referer = request.headers.get("referer");
217
231
  if (referer) {
218
- requestHeaders.set("Prepr-Context-initial_referral", referer);
232
+ requestHeaders.set(
233
+ "Prepr-Context-initial_referral",
234
+ sanitizeHeaderValue(referer)
235
+ );
219
236
  }
220
237
  const userAgent = request.headers.get("user-agent");
221
238
  if (userAgent) {
222
- requestHeaders.set("Prepr-User-Agent", userAgent);
239
+ requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
223
240
  }
224
241
  requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
225
242
  const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
226
243
  if (ip) {
227
- requestHeaders.set("Prepr-Visitor-IP", ip);
244
+ requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
228
245
  }
229
246
  const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
230
247
  if (hutkCookie) {
231
- requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
248
+ requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
232
249
  }
233
250
  let uid = requestCookies.get(COOKIE_UID);
234
251
  if (!uid) {
@@ -268,16 +285,16 @@ function processPreprRequest(request, opts) {
268
285
  if (!isLivePreview) {
269
286
  const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
270
287
  if (segmentCookie) {
271
- requestHeaders.set("Prepr-Segments", segmentCookie);
288
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
272
289
  }
273
290
  const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
274
291
  if (abCookie) {
275
- requestHeaders.set("Prepr-ABtesting", abCookie);
292
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
276
293
  }
277
294
  }
278
295
  const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
279
296
  if (previewAb !== null) {
280
- requestHeaders.set("Prepr-ABtesting", previewAb);
297
+ requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
281
298
  if (!isLivePreview) {
282
299
  responseCookies.push({
283
300
  name: COOKIE_VARIANT,
@@ -290,7 +307,7 @@ function processPreprRequest(request, opts) {
290
307
  }
291
308
  const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
292
309
  if (previewSegment !== null) {
293
- requestHeaders.set("Prepr-Segments", previewSegment);
310
+ requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
294
311
  if (!isLivePreview) {
295
312
  responseCookies.push({
296
313
  name: COOKIE_SEGMENT,
@@ -335,7 +335,10 @@ function createIframeBridge(store, options = {}) {
335
335
  };
336
336
  return {
337
337
  start() {
338
- sendPreprEvent("loaded", void 0, { allowUntrustedTarget: true });
338
+ const features = store?.get().features;
339
+ sendPreprEvent("loaded", features ? { features } : void 0, {
340
+ allowUntrustedTarget: true
341
+ });
339
342
  window.addEventListener("keydown", onKeyDown);
340
343
  window.addEventListener("message", onMessage);
341
344
  },
@@ -437,6 +440,8 @@ function createStegaAutoClean() {
437
440
  function scanAndClean() {
438
441
  processing = true;
439
442
  walkTextNodes(document.body, cleanTextNode);
443
+ const title = (0, import_stega2.vercelStegaSplit)(document.title);
444
+ if (title.encoded) document.title = title.cleaned;
440
445
  processing = false;
441
446
  }
442
447
  function collectAffected(mutations) {
@@ -482,15 +487,8 @@ function createStegaAutoClean() {
482
487
  }
483
488
  function start() {
484
489
  if (observer || typeof window === "undefined") return;
485
- const run = () => {
486
- scanAndClean();
487
- setupObserver();
488
- };
489
- if ("requestIdleCallback" in window) {
490
- window.requestIdleCallback(run);
491
- } else {
492
- setTimeout(run, 0);
493
- }
490
+ scanAndClean();
491
+ setupObserver();
494
492
  debug2.log("stega auto-clean started");
495
493
  }
496
494
  function stop() {
@@ -983,7 +981,7 @@ function cookieOpts() {
983
981
  };
984
982
  }
985
983
  function createChangeHandler(deps) {
986
- const { store, stega, syncAutoClean, features, editingEnabled } = deps;
984
+ const { store, stega, features, editingEnabled } = deps;
987
985
  function updateParams(patch) {
988
986
  const [path, existing] = splitPath(deps.currentPath());
989
987
  const params = new URLSearchParams(existing);
@@ -1046,16 +1044,17 @@ function createChangeHandler(deps) {
1046
1044
  setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1047
1045
  setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
1048
1046
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
1049
- syncAutoClean(after.previewMode);
1050
- const [path, existing] = splitPath(deps.currentPath());
1051
- const params = new URLSearchParams(existing);
1052
- if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
1053
- params.delete(PARAM_SEGMENT);
1054
- params.delete(PARAM_VARIANT);
1055
- const query = params.toString();
1056
- deps.navigate(query ? `${path}?${query}` : path);
1057
- } else {
1058
- deps.reload();
1047
+ if (!after.isIframe) {
1048
+ const [path, existing] = splitPath(deps.currentPath());
1049
+ const params = new URLSearchParams(existing);
1050
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
1051
+ params.delete(PARAM_SEGMENT);
1052
+ params.delete(PARAM_VARIANT);
1053
+ const query = params.toString();
1054
+ deps.navigate(query ? `${path}?${query}` : path);
1055
+ } else {
1056
+ deps.reload();
1057
+ }
1059
1058
  }
1060
1059
  }
1061
1060
  if (before.toolbarOpen !== after.toolbarOpen) {
@@ -2050,6 +2049,14 @@ function defaultNavigation() {
2050
2049
  currentPath: () => window.location.pathname + window.location.search
2051
2050
  };
2052
2051
  }
2052
+ function safeEditUrl(href) {
2053
+ try {
2054
+ const url = new URL(href, window.location.href);
2055
+ return url.protocol === "https:" || url.protocol === "http:" ? url.href : null;
2056
+ } catch {
2057
+ return null;
2058
+ }
2059
+ }
2053
2060
  function buildSegments(data) {
2054
2061
  return [{ _id: "all_other_users", name: "All other users" }, ...data];
2055
2062
  }
@@ -2113,24 +2120,25 @@ function createPreprPreview(opts = {}) {
2113
2120
  // In the editor, ask the parent to focus the field instead of opening a new
2114
2121
  // tab. Standalone previews keep the window.open behaviour.
2115
2122
  onEdit: ({ href, origin, id, field }) => {
2123
+ const safeHref = href ? safeEditUrl(href) : null;
2124
+ if (href && !safeHref) {
2125
+ debug7.warn("ignored edit request with unsupported href scheme");
2126
+ return;
2127
+ }
2116
2128
  if (isIframe) {
2117
- sendPreprEvent("field_edit_requested", { href, origin, id, field });
2118
- } else if (href) {
2119
- window.open(href);
2129
+ sendPreprEvent("field_edit_requested", {
2130
+ href: safeHref ?? void 0,
2131
+ origin,
2132
+ id,
2133
+ field
2134
+ });
2135
+ } else if (safeHref) {
2136
+ window.open(safeHref, "_blank", "noopener,noreferrer");
2120
2137
  }
2121
2138
  }
2122
2139
  });
2123
2140
  const autoClean = createStegaAutoClean();
2124
- let autoCleanActive = false;
2125
- function syncAutoClean(active) {
2126
- if (active && !autoCleanActive) {
2127
- autoClean.start();
2128
- autoCleanActive = true;
2129
- } else if (!active && autoCleanActive) {
2130
- autoClean.stop();
2131
- autoCleanActive = false;
2132
- }
2133
- }
2141
+ autoClean.start();
2134
2142
  const handleChange = createChangeHandler({
2135
2143
  store,
2136
2144
  features,
@@ -2138,8 +2146,7 @@ function createPreprPreview(opts = {}) {
2138
2146
  navigate: (url) => navigation.navigate(url),
2139
2147
  currentPath: () => navigation.currentPath(),
2140
2148
  reload: navigation.reload ?? (() => window.location.reload()),
2141
- stega,
2142
- syncAutoClean
2149
+ stega
2143
2150
  });
2144
2151
  let prev = store.get();
2145
2152
  const unsubscribe = store.subscribe((state) => {
@@ -2147,7 +2154,6 @@ function createPreprPreview(opts = {}) {
2147
2154
  prev = state;
2148
2155
  handleChange(before, state);
2149
2156
  });
2150
- syncAutoClean(store.get().previewMode);
2151
2157
  const bridge = createIframeBridge(store, {
2152
2158
  allowedEditorOrigins: options?.allowedEditorOrigins
2153
2159
  });
@@ -2160,7 +2166,7 @@ function createPreprPreview(opts = {}) {
2160
2166
  function destroy() {
2161
2167
  unsubscribe();
2162
2168
  stega.stop();
2163
- syncAutoClean(false);
2169
+ autoClean.stop();
2164
2170
  if (isIframe) {
2165
2171
  bridge.stop();
2166
2172
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createPreprPreview,
4
4
  loadTrackingPixel
5
- } from "../chunk-BYJ2JBGX.js";
5
+ } from "../chunk-P6VTLWM4.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.2.0-beta.5";
41
+ var VERSION = "0.2.0-beta.7";
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.5";
5
+ var VERSION = "0.2.0-beta.7";
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.5";
38
+ var VERSION = "0.2.0-beta.7";
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.5";
2
+ var VERSION = "0.2.0-beta.7";
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,