@preprio/toolkit 0.1.0-beta.6 → 0.2.0-beta.3

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.
Files changed (40) hide show
  1. package/README.md +178 -13
  2. package/dist/astro/index.cjs +37 -15
  3. package/dist/astro/index.d.cts +38 -8
  4. package/dist/astro/index.d.ts +38 -8
  5. package/dist/astro/index.js +37 -15
  6. package/dist/{chunk-NLQIRN5O.js → chunk-6OOGNVJ4.js} +83 -41
  7. package/dist/index.cjs +102 -55
  8. package/dist/index.d.cts +59 -16
  9. package/dist/index.d.ts +59 -16
  10. package/dist/index.js +22 -16
  11. package/dist/nextjs/components.cjs +103 -50
  12. package/dist/nextjs/components.d.cts +16 -9
  13. package/dist/nextjs/components.d.ts +16 -9
  14. package/dist/nextjs/components.js +23 -11
  15. package/dist/nextjs/index.cjs +37 -15
  16. package/dist/nextjs/index.d.cts +46 -16
  17. package/dist/nextjs/index.d.ts +46 -16
  18. package/dist/nextjs/index.js +37 -15
  19. package/dist/nuxt/index.cjs +37 -15
  20. package/dist/nuxt/index.d.cts +62 -32
  21. package/dist/nuxt/index.d.ts +62 -32
  22. package/dist/nuxt/index.js +37 -15
  23. package/dist/{pixel-DVSJQC0K.d.cts → pixel-763p7m6A.d.cts} +64 -1
  24. package/dist/{pixel-DVSJQC0K.d.ts → pixel-763p7m6A.d.ts} +64 -1
  25. package/dist/react/components.cjs +2237 -0
  26. package/dist/react/components.d.cts +167 -0
  27. package/dist/react/components.d.ts +167 -0
  28. package/dist/react/components.js +2212 -0
  29. package/dist/react/index.cjs +32 -0
  30. package/dist/react/index.d.cts +1 -0
  31. package/dist/react/index.d.ts +1 -0
  32. package/dist/react/index.js +9 -0
  33. package/dist/sveltekit/index.cjs +37 -15
  34. package/dist/sveltekit/index.d.cts +62 -32
  35. package/dist/sveltekit/index.d.ts +62 -32
  36. package/dist/sveltekit/index.js +37 -15
  37. package/package.json +13 -2
  38. package/src/astro/PreprToolbar.astro +16 -10
  39. package/src/nuxt/PreprToolbar.vue +10 -8
  40. package/src/sveltekit/PreprToolbar.svelte +11 -4
@@ -1,17 +1,24 @@
1
- import { b as PreprToolbarProps, i as PreprPixelConfig } from '../pixel-DVSJQC0K.js';
1
+ import { k as PreprPixelConfig, l as PreprToolbarComponentProps } from '../pixel-763p7m6A.js';
2
2
 
3
- /**
4
- * Mounts the Prepr toolbar and wires it to the Next.js router so segment/variant
5
- * switches navigate. Renders nothing — the toolbar UI is a custom element that
6
- * `createPreprToolbar` mounts imperatively.
7
- */
8
- declare function PreprToolbar(props: PreprToolbarProps): null;
9
3
  interface PreprTrackingPixelProps {
10
4
  /** Prepr tracking/access token. */
11
5
  id: string;
12
6
  config?: PreprPixelConfig;
13
7
  }
14
- /** Loads Prepr's CDN tracking pixel on mount. Renders nothing. */
15
- declare function PreprTrackingPixel({ id, config }: PreprTrackingPixelProps): null;
8
+ /**
9
+ * Loads Prepr's CDN tracking pixel on mount. Renders nothing.
10
+ *
11
+ * The pixel queues a single `pageload` event when it installs. Client-side
12
+ * route changes emit nothing on their own — call `trackEvent('pageload')` from
13
+ * the router to count them.
14
+ */
15
+ declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): null;
16
+
17
+ /**
18
+ * Mounts the Prepr toolbar and wires it to the Next.js router so segment/variant
19
+ * switches navigate. Renders nothing — the toolbar UI is a custom element that
20
+ * `createPreprPreview` mounts imperatively.
21
+ */
22
+ declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
16
23
 
17
24
  export { PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps };
@@ -1,18 +1,36 @@
1
1
  "use client";
2
2
  import {
3
- createPreprToolbar,
3
+ createPreprPreview,
4
4
  loadTrackingPixel
5
- } from "../chunk-NLQIRN5O.js";
5
+ } from "../chunk-6OOGNVJ4.js";
6
6
 
7
7
  // src/nextjs/components.ts
8
8
  import { usePathname, useRouter } from "next/navigation";
9
+ import { useEffect as useEffect2 } from "react";
10
+
11
+ // src/react/components.ts
9
12
  import { useEffect } from "react";
10
- function PreprToolbar(props) {
13
+ function PreprTrackingPixel({
14
+ id,
15
+ config
16
+ }) {
17
+ useEffect(() => {
18
+ loadTrackingPixel(id, config);
19
+ }, []);
20
+ return null;
21
+ }
22
+
23
+ // src/nextjs/components.ts
24
+ function PreprToolbar({
25
+ options,
26
+ ...props
27
+ }) {
11
28
  const router = useRouter();
12
29
  const pathname = usePathname();
13
- useEffect(() => {
14
- const toolbar = createPreprToolbar({
30
+ useEffect2(() => {
31
+ const toolbar = createPreprPreview({
15
32
  props,
33
+ options,
16
34
  navigation: {
17
35
  navigate: (url) => router.push(url),
18
36
  currentPath: () => pathname + window.location.search
@@ -22,12 +40,6 @@ function PreprToolbar(props) {
22
40
  }, []);
23
41
  return null;
24
42
  }
25
- function PreprTrackingPixel({ id, config }) {
26
- useEffect(() => {
27
- loadTrackingPixel(id, config);
28
- }, []);
29
- return null;
30
- }
31
43
  export {
32
44
  PreprToolbar,
33
45
  PreprTrackingPixel
@@ -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.6";
41
+ var VERSION = "0.2.0-beta.3";
42
42
 
43
43
  // src/core/constants.ts
44
44
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -51,6 +51,24 @@ var PARAM_VARIANT = "prepr_preview_ab";
51
51
  var PARAM_HIDE_BAR = "prepr_hide_bar";
52
52
  var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
53
53
 
54
+ // src/core/features.ts
55
+ function isEnabled(config) {
56
+ if (typeof config === "boolean") return config;
57
+ return config?.enabled ?? true;
58
+ }
59
+ function resolveFeatures(features) {
60
+ return {
61
+ segments: isEnabled(features?.segments),
62
+ abTesting: isEnabled(features?.abTesting),
63
+ editMode: isEnabled(features?.editMode)
64
+ };
65
+ }
66
+ var ALL_FEATURES_ENABLED = Object.freeze({
67
+ segments: true,
68
+ abTesting: true,
69
+ editMode: true
70
+ });
71
+
54
72
  // src/core/middleware.ts
55
73
  var UTM_PARAMS = [
56
74
  "utm_source",
@@ -120,7 +138,8 @@ function processPreprRequest(request, opts) {
120
138
  if (!opts?.preview) {
121
139
  return { requestHeaders, responseCookies };
122
140
  }
123
- const hasPreviewParams = searchParams.has(PARAM_SEGMENT) || searchParams.has(PARAM_VARIANT);
141
+ const features = resolveFeatures(opts?.features);
142
+ const hasPreviewParams = features.segments && searchParams.has(PARAM_SEGMENT) || features.abTesting && searchParams.has(PARAM_VARIANT);
124
143
  if (!hasPreviewParams) {
125
144
  const previewModeCookie = requestCookies.get(COOKIE_PREVIEW_MODE);
126
145
  const previewModeEnabled = previewModeCookie !== "false";
@@ -140,16 +159,16 @@ function processPreprRequest(request, opts) {
140
159
  });
141
160
  }
142
161
  if (!isLivePreview) {
143
- const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
162
+ const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
144
163
  if (segmentCookie) {
145
164
  requestHeaders.set("Prepr-Segments", segmentCookie);
146
165
  }
147
- const abCookie = requestCookies.get(COOKIE_VARIANT);
166
+ const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
148
167
  if (abCookie) {
149
168
  requestHeaders.set("Prepr-ABtesting", abCookie);
150
169
  }
151
170
  }
152
- const previewAb = searchParams.get(PARAM_VARIANT);
171
+ const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
153
172
  if (previewAb !== null) {
154
173
  requestHeaders.set("Prepr-ABtesting", previewAb);
155
174
  if (!isLivePreview) {
@@ -162,7 +181,7 @@ function processPreprRequest(request, opts) {
162
181
  });
163
182
  }
164
183
  }
165
- const previewSegment = searchParams.get(PARAM_SEGMENT);
184
+ const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
166
185
  if (previewSegment !== null) {
167
186
  requestHeaders.set("Prepr-Segments", previewSegment);
168
187
  if (!isLivePreview) {
@@ -346,16 +365,19 @@ async function getPreprEnvironmentSegments(token) {
346
365
  );
347
366
  }
348
367
  }
349
- async function getToolbarPropsFromHeaders(headers2, token) {
368
+ async function getToolbarPropsFromHeaders(headers2, token, features) {
369
+ const resolved = resolveFeatures(features);
350
370
  let segments = [];
351
- try {
352
- segments = await getPreprEnvironmentSegments(token);
353
- } catch {
354
- segments = [];
371
+ if (resolved.segments) {
372
+ try {
373
+ segments = await getPreprEnvironmentSegments(token);
374
+ } catch {
375
+ segments = [];
376
+ }
355
377
  }
356
378
  return {
357
- activeSegment: getActiveSegmentFromHeaders(headers2),
358
- activeVariant: getActiveVariantFromHeaders(headers2),
379
+ activeSegment: resolved.segments ? getActiveSegmentFromHeaders(headers2) : null,
380
+ activeVariant: resolved.abTesting ? getActiveVariantFromHeaders(headers2) : null,
359
381
  segments,
360
382
  data: segments
361
383
  };
@@ -381,9 +403,9 @@ async function getPreprHeaders() {
381
403
  const h = await readHeaders();
382
404
  return getPreprHeadersFromHeaders(h);
383
405
  }
384
- async function getToolbarProps(token) {
406
+ async function getToolbarProps(token, features) {
385
407
  const h = await readHeaders();
386
- return getToolbarPropsFromHeaders(h, token);
408
+ return getToolbarPropsFromHeaders(h, token, features);
387
409
  }
388
410
 
389
411
  // src/nextjs/index.ts
@@ -1,25 +1,34 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  export { PreprToolbar, PreprTrackingPixel, PreprTrackingPixelProps } from './components';
3
3
 
4
- interface PreprMiddlewareOptions {
5
- /** Enable preview-mode headers (segment/AB overrides, preview bar). */
6
- preview?: boolean;
7
- /** Override the version reported in Prepr-Package (mainly for tests). */
8
- version?: string;
9
- }
10
-
11
- /**
12
- * Next.js middleware entry point. Despite the `create` prefix this runs
13
- * per-request — it does not return a handler. Pass an existing `NextResponse`
14
- * as the second argument to chain with other middleware.
15
- */
16
- declare function createPreprMiddleware(request: NextRequest, options?: PreprMiddlewareOptions): NextResponse;
17
- declare function createPreprMiddleware(request: NextRequest, response: NextResponse, options?: PreprMiddlewareOptions): NextResponse;
18
-
19
4
  interface PreprSegment {
20
5
  readonly _id: string;
21
6
  readonly name: string;
22
7
  }
8
+ /**
9
+ * Per-feature config. `false` is shorthand for `{ enabled: false }`; the object
10
+ * form leaves room for per-feature options later without a breaking change.
11
+ */
12
+ type PreprFeatureConfig = boolean | {
13
+ enabled?: boolean;
14
+ };
15
+ /** Toolkit features a consumer can turn off. Omitted keys stay enabled. */
16
+ interface PreprFeatures {
17
+ /** Segment picker, `Prepr-Segments` header and its cookie/query param. */
18
+ segments?: PreprFeatureConfig;
19
+ /** A/B variant switch, `Prepr-ABtesting` header and its cookie/query param. */
20
+ abTesting?: PreprFeatureConfig;
21
+ /**
22
+ * The site's own click-to-edit: the toolbar's Edit mode control, the stega
23
+ * tooltip/overlay and the close-edit pill.
24
+ *
25
+ * NOT a security control, and NOT the Prepr editor's live preview. When the
26
+ * site is framed by the editor, `prepr:initVE` still activates edit mode —
27
+ * that is the CMS operating inside its own iframe, not an affordance offered
28
+ * to visitors. See iframe-bridge.ts.
29
+ */
30
+ editMode?: PreprFeatureConfig;
31
+ }
23
32
  interface PreprToolbarProps {
24
33
  readonly activeSegment: string | null;
25
34
  readonly activeVariant: string | null;
@@ -47,6 +56,27 @@ interface PreprHeaders {
47
56
  }
48
57
  type PreprErrorCode = 'INVALID_TOKEN' | 'MISSING_TOKEN' | 'HTTP_ERROR' | 'FETCH_ERROR' | 'INVALID_RESPONSE' | 'CONTEXT_ERROR';
49
58
 
59
+ interface PreprMiddlewareOptions {
60
+ /** Enable preview-mode headers (segment/AB overrides, preview bar). */
61
+ preview?: boolean;
62
+ /**
63
+ * Disable features app-wide. Pass the same object you give the toolbar: a
64
+ * disabled feature injects no header and persists no cookie, whatever the
65
+ * request carries.
66
+ */
67
+ features?: PreprFeatures;
68
+ /** Override the version reported in Prepr-Package (mainly for tests). */
69
+ version?: string;
70
+ }
71
+
72
+ /**
73
+ * Next.js middleware entry point. Despite the `create` prefix this runs
74
+ * per-request — it does not return a handler. Pass an existing `NextResponse`
75
+ * as the second argument to chain with other middleware.
76
+ */
77
+ declare function createPreprMiddleware(request: NextRequest, options?: PreprMiddlewareOptions): NextResponse;
78
+ declare function createPreprMiddleware(request: NextRequest, response: NextResponse, options?: PreprMiddlewareOptions): NextResponse;
79
+
50
80
  /** Prepr Customer ID for the current request. Server-only. */
51
81
  declare function getPreprUUID(): Promise<string | null>;
52
82
  /** Active segment for the current request. Server-only. */
@@ -66,7 +96,7 @@ declare function getPreprHeaders(): Promise<PreprHeaders>;
66
96
  * Never throws: segment-fetch failures degrade to an empty segment list, so a
67
97
  * bad or missing token can't crash the host app.
68
98
  */
69
- declare function getToolbarProps(token: string): Promise<PreprToolbarProps>;
99
+ declare function getToolbarProps(token: string, features?: PreprFeatures): Promise<PreprToolbarProps>;
70
100
 
71
101
  /** Error thrown by the token helpers and the segments fetch. */
72
102
  declare class PreprError extends Error {
@@ -1,25 +1,34 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  export { PreprToolbar, PreprTrackingPixel, PreprTrackingPixelProps } from './components';
3
3
 
4
- interface PreprMiddlewareOptions {
5
- /** Enable preview-mode headers (segment/AB overrides, preview bar). */
6
- preview?: boolean;
7
- /** Override the version reported in Prepr-Package (mainly for tests). */
8
- version?: string;
9
- }
10
-
11
- /**
12
- * Next.js middleware entry point. Despite the `create` prefix this runs
13
- * per-request — it does not return a handler. Pass an existing `NextResponse`
14
- * as the second argument to chain with other middleware.
15
- */
16
- declare function createPreprMiddleware(request: NextRequest, options?: PreprMiddlewareOptions): NextResponse;
17
- declare function createPreprMiddleware(request: NextRequest, response: NextResponse, options?: PreprMiddlewareOptions): NextResponse;
18
-
19
4
  interface PreprSegment {
20
5
  readonly _id: string;
21
6
  readonly name: string;
22
7
  }
8
+ /**
9
+ * Per-feature config. `false` is shorthand for `{ enabled: false }`; the object
10
+ * form leaves room for per-feature options later without a breaking change.
11
+ */
12
+ type PreprFeatureConfig = boolean | {
13
+ enabled?: boolean;
14
+ };
15
+ /** Toolkit features a consumer can turn off. Omitted keys stay enabled. */
16
+ interface PreprFeatures {
17
+ /** Segment picker, `Prepr-Segments` header and its cookie/query param. */
18
+ segments?: PreprFeatureConfig;
19
+ /** A/B variant switch, `Prepr-ABtesting` header and its cookie/query param. */
20
+ abTesting?: PreprFeatureConfig;
21
+ /**
22
+ * The site's own click-to-edit: the toolbar's Edit mode control, the stega
23
+ * tooltip/overlay and the close-edit pill.
24
+ *
25
+ * NOT a security control, and NOT the Prepr editor's live preview. When the
26
+ * site is framed by the editor, `prepr:initVE` still activates edit mode —
27
+ * that is the CMS operating inside its own iframe, not an affordance offered
28
+ * to visitors. See iframe-bridge.ts.
29
+ */
30
+ editMode?: PreprFeatureConfig;
31
+ }
23
32
  interface PreprToolbarProps {
24
33
  readonly activeSegment: string | null;
25
34
  readonly activeVariant: string | null;
@@ -47,6 +56,27 @@ interface PreprHeaders {
47
56
  }
48
57
  type PreprErrorCode = 'INVALID_TOKEN' | 'MISSING_TOKEN' | 'HTTP_ERROR' | 'FETCH_ERROR' | 'INVALID_RESPONSE' | 'CONTEXT_ERROR';
49
58
 
59
+ interface PreprMiddlewareOptions {
60
+ /** Enable preview-mode headers (segment/AB overrides, preview bar). */
61
+ preview?: boolean;
62
+ /**
63
+ * Disable features app-wide. Pass the same object you give the toolbar: a
64
+ * disabled feature injects no header and persists no cookie, whatever the
65
+ * request carries.
66
+ */
67
+ features?: PreprFeatures;
68
+ /** Override the version reported in Prepr-Package (mainly for tests). */
69
+ version?: string;
70
+ }
71
+
72
+ /**
73
+ * Next.js middleware entry point. Despite the `create` prefix this runs
74
+ * per-request — it does not return a handler. Pass an existing `NextResponse`
75
+ * as the second argument to chain with other middleware.
76
+ */
77
+ declare function createPreprMiddleware(request: NextRequest, options?: PreprMiddlewareOptions): NextResponse;
78
+ declare function createPreprMiddleware(request: NextRequest, response: NextResponse, options?: PreprMiddlewareOptions): NextResponse;
79
+
50
80
  /** Prepr Customer ID for the current request. Server-only. */
51
81
  declare function getPreprUUID(): Promise<string | null>;
52
82
  /** Active segment for the current request. Server-only. */
@@ -66,7 +96,7 @@ declare function getPreprHeaders(): Promise<PreprHeaders>;
66
96
  * Never throws: segment-fetch failures degrade to an empty segment list, so a
67
97
  * bad or missing token can't crash the host app.
68
98
  */
69
- declare function getToolbarProps(token: string): Promise<PreprToolbarProps>;
99
+ declare function getToolbarProps(token: string, features?: PreprFeatures): Promise<PreprToolbarProps>;
70
100
 
71
101
  /** Error thrown by the token helpers and the segments fetch. */
72
102
  declare class PreprError extends Error {
@@ -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.6";
5
+ var VERSION = "0.2.0-beta.3";
6
6
 
7
7
  // src/core/constants.ts
8
8
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -15,6 +15,24 @@ var PARAM_VARIANT = "prepr_preview_ab";
15
15
  var PARAM_HIDE_BAR = "prepr_hide_bar";
16
16
  var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
17
17
 
18
+ // src/core/features.ts
19
+ function isEnabled(config) {
20
+ if (typeof config === "boolean") return config;
21
+ return config?.enabled ?? true;
22
+ }
23
+ function resolveFeatures(features) {
24
+ return {
25
+ segments: isEnabled(features?.segments),
26
+ abTesting: isEnabled(features?.abTesting),
27
+ editMode: isEnabled(features?.editMode)
28
+ };
29
+ }
30
+ var ALL_FEATURES_ENABLED = Object.freeze({
31
+ segments: true,
32
+ abTesting: true,
33
+ editMode: true
34
+ });
35
+
18
36
  // src/core/middleware.ts
19
37
  var UTM_PARAMS = [
20
38
  "utm_source",
@@ -84,7 +102,8 @@ function processPreprRequest(request, opts) {
84
102
  if (!opts?.preview) {
85
103
  return { requestHeaders, responseCookies };
86
104
  }
87
- const hasPreviewParams = searchParams.has(PARAM_SEGMENT) || searchParams.has(PARAM_VARIANT);
105
+ const features = resolveFeatures(opts?.features);
106
+ const hasPreviewParams = features.segments && searchParams.has(PARAM_SEGMENT) || features.abTesting && searchParams.has(PARAM_VARIANT);
88
107
  if (!hasPreviewParams) {
89
108
  const previewModeCookie = requestCookies.get(COOKIE_PREVIEW_MODE);
90
109
  const previewModeEnabled = previewModeCookie !== "false";
@@ -104,16 +123,16 @@ function processPreprRequest(request, opts) {
104
123
  });
105
124
  }
106
125
  if (!isLivePreview) {
107
- const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
126
+ const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
108
127
  if (segmentCookie) {
109
128
  requestHeaders.set("Prepr-Segments", segmentCookie);
110
129
  }
111
- const abCookie = requestCookies.get(COOKIE_VARIANT);
130
+ const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
112
131
  if (abCookie) {
113
132
  requestHeaders.set("Prepr-ABtesting", abCookie);
114
133
  }
115
134
  }
116
- const previewAb = searchParams.get(PARAM_VARIANT);
135
+ const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
117
136
  if (previewAb !== null) {
118
137
  requestHeaders.set("Prepr-ABtesting", previewAb);
119
138
  if (!isLivePreview) {
@@ -126,7 +145,7 @@ function processPreprRequest(request, opts) {
126
145
  });
127
146
  }
128
147
  }
129
- const previewSegment = searchParams.get(PARAM_SEGMENT);
148
+ const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
130
149
  if (previewSegment !== null) {
131
150
  requestHeaders.set("Prepr-Segments", previewSegment);
132
151
  if (!isLivePreview) {
@@ -310,16 +329,19 @@ async function getPreprEnvironmentSegments(token) {
310
329
  );
311
330
  }
312
331
  }
313
- async function getToolbarPropsFromHeaders(headers2, token) {
332
+ async function getToolbarPropsFromHeaders(headers2, token, features) {
333
+ const resolved = resolveFeatures(features);
314
334
  let segments = [];
315
- try {
316
- segments = await getPreprEnvironmentSegments(token);
317
- } catch {
318
- segments = [];
335
+ if (resolved.segments) {
336
+ try {
337
+ segments = await getPreprEnvironmentSegments(token);
338
+ } catch {
339
+ segments = [];
340
+ }
319
341
  }
320
342
  return {
321
- activeSegment: getActiveSegmentFromHeaders(headers2),
322
- activeVariant: getActiveVariantFromHeaders(headers2),
343
+ activeSegment: resolved.segments ? getActiveSegmentFromHeaders(headers2) : null,
344
+ activeVariant: resolved.abTesting ? getActiveVariantFromHeaders(headers2) : null,
323
345
  segments,
324
346
  data: segments
325
347
  };
@@ -345,9 +367,9 @@ async function getPreprHeaders() {
345
367
  const h = await readHeaders();
346
368
  return getPreprHeadersFromHeaders(h);
347
369
  }
348
- async function getToolbarProps(token) {
370
+ async function getToolbarProps(token, features) {
349
371
  const h = await readHeaders();
350
- return getToolbarPropsFromHeaders(h, token);
372
+ return getToolbarPropsFromHeaders(h, token, features);
351
373
  }
352
374
 
353
375
  // src/nextjs/index.ts
@@ -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.6";
38
+ var VERSION = "0.2.0-beta.3";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -48,6 +48,24 @@ var PARAM_VARIANT = "prepr_preview_ab";
48
48
  var PARAM_HIDE_BAR = "prepr_hide_bar";
49
49
  var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
50
50
 
51
+ // src/core/features.ts
52
+ function isEnabled(config) {
53
+ if (typeof config === "boolean") return config;
54
+ return config?.enabled ?? true;
55
+ }
56
+ function resolveFeatures(features) {
57
+ return {
58
+ segments: isEnabled(features?.segments),
59
+ abTesting: isEnabled(features?.abTesting),
60
+ editMode: isEnabled(features?.editMode)
61
+ };
62
+ }
63
+ var ALL_FEATURES_ENABLED = Object.freeze({
64
+ segments: true,
65
+ abTesting: true,
66
+ editMode: true
67
+ });
68
+
51
69
  // src/core/middleware.ts
52
70
  var UTM_PARAMS = [
53
71
  "utm_source",
@@ -131,7 +149,8 @@ function processPreprRequest(request, opts) {
131
149
  if (!opts?.preview) {
132
150
  return { requestHeaders, responseCookies };
133
151
  }
134
- const hasPreviewParams = searchParams.has(PARAM_SEGMENT) || searchParams.has(PARAM_VARIANT);
152
+ const features = resolveFeatures(opts?.features);
153
+ const hasPreviewParams = features.segments && searchParams.has(PARAM_SEGMENT) || features.abTesting && searchParams.has(PARAM_VARIANT);
135
154
  if (!hasPreviewParams) {
136
155
  const previewModeCookie = requestCookies.get(COOKIE_PREVIEW_MODE);
137
156
  const previewModeEnabled = previewModeCookie !== "false";
@@ -151,16 +170,16 @@ function processPreprRequest(request, opts) {
151
170
  });
152
171
  }
153
172
  if (!isLivePreview) {
154
- const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
173
+ const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
155
174
  if (segmentCookie) {
156
175
  requestHeaders.set("Prepr-Segments", segmentCookie);
157
176
  }
158
- const abCookie = requestCookies.get(COOKIE_VARIANT);
177
+ const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
159
178
  if (abCookie) {
160
179
  requestHeaders.set("Prepr-ABtesting", abCookie);
161
180
  }
162
181
  }
163
- const previewAb = searchParams.get(PARAM_VARIANT);
182
+ const previewAb = features.abTesting ? searchParams.get(PARAM_VARIANT) : null;
164
183
  if (previewAb !== null) {
165
184
  requestHeaders.set("Prepr-ABtesting", previewAb);
166
185
  if (!isLivePreview) {
@@ -173,7 +192,7 @@ function processPreprRequest(request, opts) {
173
192
  });
174
193
  }
175
194
  }
176
- const previewSegment = searchParams.get(PARAM_SEGMENT);
195
+ const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
177
196
  if (previewSegment !== null) {
178
197
  requestHeaders.set("Prepr-Segments", previewSegment);
179
198
  if (!isLivePreview) {
@@ -352,16 +371,19 @@ async function getPreprEnvironmentSegments(token) {
352
371
  );
353
372
  }
354
373
  }
355
- async function getToolbarPropsFromHeaders(headers, token) {
374
+ async function getToolbarPropsFromHeaders(headers, token, features) {
375
+ const resolved = resolveFeatures(features);
356
376
  let segments = [];
357
- try {
358
- segments = await getPreprEnvironmentSegments(token);
359
- } catch {
360
- segments = [];
377
+ if (resolved.segments) {
378
+ try {
379
+ segments = await getPreprEnvironmentSegments(token);
380
+ } catch {
381
+ segments = [];
382
+ }
361
383
  }
362
384
  return {
363
- activeSegment: getActiveSegmentFromHeaders(headers),
364
- activeVariant: getActiveVariantFromHeaders(headers),
385
+ activeSegment: resolved.segments ? getActiveSegmentFromHeaders(headers) : null,
386
+ activeVariant: resolved.abTesting ? getActiveVariantFromHeaders(headers) : null,
365
387
  segments,
366
388
  data: segments
367
389
  };
@@ -380,8 +402,8 @@ function getActiveVariant(headers) {
380
402
  function getPreprHeaders(headers) {
381
403
  return getPreprHeadersFromHeaders(headers);
382
404
  }
383
- async function getToolbarProps(headers, token) {
384
- return getToolbarPropsFromHeaders(headers, token);
405
+ async function getToolbarProps(headers, token, features) {
406
+ return getToolbarPropsFromHeaders(headers, token, features);
385
407
  }
386
408
  // Annotate the CommonJS export names for ESM import in node:
387
409
  0 && (module.exports = {