@preprio/prepr-nextjs 2.0.0-alpha.9 β†’ 2.0.0

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/README.md CHANGED
@@ -1,177 +1,795 @@
1
- # The Prepr Next.js package
1
+ # Prepr Next.js Package
2
2
 
3
- ## Getting Started
4
- <hr>
5
- The Prepr Next.js package offers some helper functions and a preview toolbar component for an
6
- easier personalization & A/B testing implementation in your Next.js project.
3
+ A powerful TypeScript library that provides preview functionality, visual editing capabilities, and A/B testing for [Prepr CMS](https://prepr.io) integrated with Next.js applications.
7
4
 
8
- ## Installation
9
- <hr>
10
- To install the Prepr Next.js package, run the following command:
5
+ ## ⚑ Quick Start
11
6
 
12
7
  ```bash
8
+ # Install the package
13
9
  npm install @preprio/prepr-nextjs
10
+ # or
11
+ pnpm add @preprio/prepr-nextjs
14
12
  ```
15
13
 
16
- Next, add the `PREPR_ENV` variable to the `.env` file. You can enable the Prepr preview toolbar for a staging environment by setting the value to `preview`.
14
+ Add environment variables to your `.env`:
17
15
 
18
16
  ```bash
17
+ PREPR_GRAPHQL_URL=https://graphql.prepr.io/{YOUR_ACCESS_TOKEN}
19
18
  PREPR_ENV=preview
20
19
  ```
21
20
 
22
- When you're launching your project to production, then set the `PREPR_ENV` environment variable to `production`.
21
+ Set up middleware in `middleware.ts`:
23
22
 
24
- Next, implement the `PreprMiddleware` function. Go to your `middleware.js` or the `middleware.ts`
25
- file. If you don't have this file, you can create it in the root of your project.
23
+ ```typescript
24
+ import type { NextRequest } from 'next/server'
25
+ import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
26
26
 
27
- Then add the following code to the `middleware.ts` file:
28
- ```javascript
27
+ export function middleware(request: NextRequest) {
28
+ return createPreprMiddleware(request, { preview: true })
29
+ }
30
+ ```
31
+
32
+ Add toolbar and tracking to your layout:
33
+
34
+ ```typescript
35
+ import { getToolbarProps, extractAccessToken } from '@preprio/prepr-nextjs/server'
36
+ import { PreprToolbar, PreprToolbarProvider, PreprTrackingPixel } from '@preprio/prepr-nextjs/react'
37
+ import '@preprio/prepr-nextjs/index.css'
38
+
39
+ export default async function RootLayout({ children }: { children: React.ReactNode }) {
40
+ const toolbarProps = await getToolbarProps(process.env.PREPR_GRAPHQL_URL!)
41
+ const accessToken = extractAccessToken(process.env.PREPR_GRAPHQL_URL!)
42
+
43
+ return (
44
+ <html>
45
+ <head>
46
+ {accessToken && <PreprTrackingPixel accessToken={accessToken!} />}
47
+ </head>
48
+ <body>
49
+ <PreprToolbarProvider props={toolbarProps}>
50
+ <PreprToolbar />
51
+ {children}
52
+ </PreprToolbarProvider>
53
+ </body>
54
+ </html>
55
+ )
56
+ }
57
+ ```
58
+
59
+ ## πŸ“‹ Prerequisites
60
+
61
+ Before installing, ensure you have:
62
+
63
+ - **Next.js 13.0.0 or later** (supports App Router)
64
+ - **React 17.0.0 or later** (React 18+ recommended)
65
+ - **Node.js 16.0.0 or later**
66
+ - **A Prepr account**
67
+ - **Prepr GraphQL URL** (found in Settings β†’ Access tokens)
68
+
69
+ ### Prepr Account Setup
70
+
71
+ 1. **Create a Prepr account** at [prepr.io](https://prepr.io)
72
+ 2. **Get your GraphQL URL**:
73
+ - Go to Settings β†’ Access tokens
74
+ - Find your GraphQL Preview access token
75
+
76
+ ![preview API URL](https://assets-site.prepr.io//35k5a4g45wuy-preview-access-token.png)
77
+
78
+ - Copy the full GraphQL URL (e.g., `https://graphql.prepr.io/e6f7a0521f11e5149ce65b0e9f372ced2dfc923490890e7f225da1db84cxxxxx`)
79
+ - The URL format is always `https://graphql.prepr.io/{YOUR_ACCESS_TOKEN}`
80
+ 3. **Enable edit mode** (for toolbar):
81
+ - Open your GraphQL Preview access token
82
+ - Check "Enable edit mode"
83
+ - Save the token
84
+
85
+ ![Preview access token](https://assets-site.prepr.io/229kaekn7m96//preview-access-token-enable-edit-mode.png)
86
+
87
+ ## πŸ”§ Installation & Setup
88
+
89
+ ### 1. Install the Package
90
+
91
+ ```bash
92
+ npm install @preprio/prepr-nextjs
93
+ # or
94
+ pnpm add @preprio/prepr-nextjs
95
+ # or
96
+ yarn add @preprio/prepr-nextjs
97
+ ```
98
+
99
+ ### 2. Environment Configuration
100
+
101
+ Create or update your `.env` file:
102
+
103
+ ```bash
104
+ # Required: Your Prepr GraphQL endpoint
105
+ PREPR_GRAPHQL_URL=https://graphql.prepr.io/{YOUR_ACCESS_TOKEN}
106
+
107
+ # Required: Environment mode
108
+ PREPR_ENV=preview # Use 'preview' for staging/development
109
+ # PREPR_ENV=production # Use 'production' for live sites
110
+
111
+ # Optional: Enable debug logging (development only)
112
+ # PREPR_DEBUG=true
113
+ ```
114
+
115
+ > **Important**: Replace `{YOUR_ACCESS_TOKEN}` with your actual Prepr access token from Settings β†’ Access tokens.
116
+
117
+ ### 3. Middleware Setup
118
+
119
+ The middleware handles personalization headers, customer ID tracking, and preview mode functionality.
120
+
121
+ #### TypeScript Setup
122
+
123
+ Create or update `middleware.ts` in your project root:
124
+
125
+ ```typescript
29
126
  import type { NextRequest } from 'next/server'
30
127
  import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
31
128
 
32
129
  export function middleware(request: NextRequest) {
33
- return createPreprMiddleware(request)
130
+ return createPreprMiddleware(request, {
131
+ preview: process.env.PREPR_ENV === 'preview'
132
+ })
133
+ }
134
+
135
+ export const config = {
136
+ matcher: [
137
+ /*
138
+ * Match all request paths except for the ones starting with:
139
+ * - api (API routes)
140
+ * - _next/static (static files)
141
+ * - _next/image (image optimization files)
142
+ * - favicon.ico (favicon file)
143
+ */
144
+ '/((?!api|_next/static|_next/image|favicon.ico).*)',
145
+ ],
34
146
  }
35
147
  ```
36
148
 
37
- Or add the following code to the `middleware.js` file:
149
+ #### JavaScript Setup
150
+
151
+ Create or update `middleware.js` in your project root:
152
+
38
153
  ```javascript
39
154
  import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
40
155
 
41
- export async function middleware(request: NextRequest) {
42
- return createPreprMiddleware(request)
156
+ export async function middleware(request) {
157
+ return createPreprMiddleware(request, {
158
+ preview: process.env.PREPR_ENV === 'preview'
159
+ })
160
+ }
161
+
162
+ export const config = {
163
+ matcher: [
164
+ '/((?!api|_next/static|_next/image|favicon.ico).*)',
165
+ ],
43
166
  }
44
167
  ```
45
168
 
46
- ### Middleware functionality
47
- The `PreprMiddleware` accepts a request and optional response property and returns a `NextRequest` object.
48
- This is done so you are able to chain your own middleware to it.
169
+ #### Chaining with Existing Middleware
49
170
 
50
- The `PreprMiddleware` function checks every request if the `__prepr_uid` cookie is set. If it isn't, the function generates a new UUID and sets it as a cookie. Then it returns a `Prepr-Customer-Id` header with the value of the `__prepr_uid` cookie to simplify your personalization and A/B testing implementation.
171
+ ##### Basic Chaining Pattern
51
172
 
52
- If the `PREPR_ENV` environment variable is set to `preview`, the `PreprMiddleware` function also checks for searchParams `segments` and `a-b-testing` in the URL.
53
- If these searchParams are set, the PreprMiddleware sets the `Prepr-Segments` and `Prepr-AB-Testing` headers with the values of the searchParams, and stores its value in a cookie.
173
+ ```typescript
174
+ import type { NextRequest, NextResponse } from 'next/server'
175
+ import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
54
176
 
55
- ## Usage
56
- To set your API request headers to query adaptive content or A/B testing content, you can call the `getPreprHeaders()` helper function. It returns an array of headers that you can spread in your fetch call.
57
- See the example code below in the `page.tsx` file.
177
+ export function middleware(request: NextRequest) {
178
+ // Start with your existing middleware
179
+ let response = NextResponse.next()
180
+
181
+ // Add your custom logic
182
+ if (request.nextUrl.pathname.startsWith('/admin')) {
183
+ response.headers.set('x-admin-route', 'true')
184
+ }
185
+
186
+ // Chain with Prepr middleware
187
+ return createPreprMiddleware(request, response, {
188
+ preview: process.env.PREPR_ENV === 'preview'
189
+ })
190
+ }
191
+ ```
58
192
 
59
- ```javascript
193
+ ##### With next-intl Integration
194
+
195
+ ```typescript
196
+ import type { NextRequest } from 'next/server'
197
+ import createIntlMiddleware from 'next-intl/middleware'
198
+ import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
199
+
200
+ const intlMiddleware = createIntlMiddleware({
201
+ locales: ['en', 'de', 'fr'],
202
+ defaultLocale: 'en'
203
+ })
204
+
205
+ export function middleware(request: NextRequest) {
206
+ // First run internationalization middleware
207
+ const intlResponse = intlMiddleware(request)
208
+
209
+ // If next-intl returns a redirect, return it immediately
210
+ if (intlResponse.status >= 300 && intlResponse.status < 400) {
211
+ return intlResponse
212
+ }
213
+
214
+ // Otherwise, chain with Prepr middleware
215
+ return createPreprMiddleware(request, intlResponse, {
216
+ preview: process.env.PREPR_ENV === 'preview'
217
+ })
218
+ }
219
+
220
+ export const config = {
221
+ matcher: [
222
+ '/((?!api|_next/static|_next/image|favicon.ico).*)',
223
+ ],
224
+ }
225
+ ```
226
+
227
+ ##### Advanced Chaining with Multiple Middlewares
228
+
229
+ ```typescript
230
+ import type { NextRequest, NextResponse } from 'next/server'
231
+ import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
232
+ import { authMiddleware } from '@/lib/auth'
233
+ import { rateLimitMiddleware } from '@/lib/rate-limit'
234
+
235
+ export function middleware(request: NextRequest) {
236
+ let response = NextResponse.next()
237
+
238
+ // 1. Rate limiting
239
+ response = rateLimitMiddleware(request, response)
240
+
241
+ // 2. Authentication (if needed)
242
+ if (request.nextUrl.pathname.startsWith('/dashboard')) {
243
+ response = authMiddleware(request, response)
244
+ }
245
+
246
+ // 3. Custom headers
247
+ response.headers.set('x-custom-header', 'my-value')
248
+
249
+ // 4. Finally, Prepr middleware
250
+ return createPreprMiddleware(request, response, {
251
+ preview: process.env.PREPR_ENV === 'preview'
252
+ })
253
+ }
254
+ ```
255
+
256
+ ##### Conditional Chaining
257
+
258
+ ```typescript
259
+ import type { NextRequest, NextResponse } from 'next/server'
260
+ import createPreprMiddleware from '@preprio/prepr-nextjs/middleware'
261
+
262
+ export function middleware(request: NextRequest) {
263
+ const { pathname } = request.nextUrl
264
+
265
+ // Skip Prepr middleware for API routes
266
+ if (pathname.startsWith('/api/')) {
267
+ return NextResponse.next()
268
+ }
269
+
270
+ // Apply different logic based on route
271
+ let response = NextResponse.next()
272
+
273
+ if (pathname.startsWith('/blog')) {
274
+ response.headers.set('x-content-type', 'blog')
275
+ } else if (pathname.startsWith('/product')) {
276
+ response.headers.set('x-content-type', 'product')
277
+ }
278
+
279
+ // Always apply Prepr middleware for content routes
280
+ return createPreprMiddleware(request, response, {
281
+ preview: process.env.PREPR_ENV === 'preview'
282
+ })
283
+ }
284
+ ```
285
+
286
+ ### 4. Layout Integration
287
+
288
+ #### App Router (Next.js 13+)
289
+
290
+ The toolbar should only be rendered in preview environments to avoid showing development tools in production. Here are several approaches for conditional rendering:
291
+
292
+ ##### Basic Conditional Rendering
293
+
294
+ Update your `app/layout.tsx`:
295
+
296
+ ```typescript
297
+ import { getToolbarProps } from '@preprio/prepr-nextjs/server'
298
+ import {
299
+ PreprToolbar,
300
+ PreprToolbarProvider
301
+ } from '@preprio/prepr-nextjs/react'
302
+ import '@preprio/prepr-nextjs/index.css'
303
+
304
+ export default async function RootLayout({
305
+ children,
306
+ }: {
307
+ children: React.ReactNode
308
+ }) {
309
+ const isPreview = process.env.PREPR_ENV === 'preview'
310
+ const toolbarProps = isPreview ? await getToolbarProps(process.env.PREPR_GRAPHQL_URL!) : null
311
+
312
+ return (
313
+ <html lang="en">
314
+ <body>
315
+ {isPreview && toolbarProps ? (
316
+ <PreprToolbarProvider props={toolbarProps}>
317
+ <PreprToolbar />
318
+ {children}
319
+ </PreprToolbarProvider>
320
+ ) : (
321
+ children
322
+ )}
323
+ </body>
324
+ </html>
325
+ )
326
+ }
327
+ ```
328
+
329
+ ##### Advanced Conditional Rendering with Error Handling
330
+
331
+ For production applications, you may want more robust error handling:
332
+
333
+ ```typescript
334
+ import { getToolbarProps } from '@preprio/prepr-nextjs/server'
335
+ import {
336
+ PreprToolbar,
337
+ PreprToolbarProvider
338
+ } from '@preprio/prepr-nextjs/react'
339
+ import '@preprio/prepr-nextjs/index.css'
340
+
341
+ export default async function RootLayout({
342
+ children,
343
+ }: {
344
+ children: React.ReactNode
345
+ }) {
346
+ const isPreview = process.env.PREPR_ENV === 'preview'
347
+ const graphqlUrl = process.env.PREPR_GRAPHQL_URL
348
+
349
+ // Only fetch toolbar props in preview mode with valid URL
350
+ let toolbarProps = null
351
+ if (isPreview && graphqlUrl) {
352
+ try {
353
+ toolbarProps = await getToolbarProps(graphqlUrl)
354
+ } catch (error) {
355
+ console.error('Failed to load toolbar:', error)
356
+ // Continue without toolbar instead of breaking the app
357
+ }
358
+ }
359
+
360
+ return (
361
+ <html lang="en">
362
+ <body>
363
+ {isPreview && toolbarProps ? (
364
+ <PreprToolbarProvider props={toolbarProps}>
365
+ <PreprToolbar />
366
+ {children}
367
+ </PreprToolbarProvider>
368
+ ) : (
369
+ children
370
+ )}
371
+ </body>
372
+ </html>
373
+ )
374
+ }
375
+ ```
376
+
377
+ ##### Component-Level Conditional Rendering
378
+
379
+ For better separation of concerns, create a dedicated component:
380
+
381
+ ```typescript
382
+ // components/PreviewWrapper.tsx
383
+ import { getToolbarProps } from '@preprio/prepr-nextjs/server'
384
+ import {
385
+ PreprToolbar,
386
+ PreprToolbarProvider
387
+ } from '@preprio/prepr-nextjs/react'
388
+
389
+ interface PreviewWrapperProps {
390
+ children: React.ReactNode
391
+ }
392
+
393
+ export default async function PreviewWrapper({ children }: PreviewWrapperProps) {
394
+ const isPreview = process.env.PREPR_ENV === 'preview'
395
+
396
+ if (!isPreview) {
397
+ return <>{children}</>
398
+ }
399
+
400
+ const toolbarProps = await getToolbarProps(process.env.PREPR_GRAPHQL_URL!)
401
+
402
+ return (
403
+ <PreprToolbarProvider props={toolbarProps}>
404
+ <PreprToolbar />
405
+ {children}
406
+ </PreprToolbarProvider>
407
+ )
408
+ }
409
+
410
+ // app/layout.tsx
411
+ import PreviewWrapper from '@/components/PreviewWrapper'
412
+ import '@preprio/prepr-nextjs/index.css'
413
+
414
+ export default function RootLayout({
415
+ children,
416
+ }: {
417
+ children: React.ReactNode
418
+ }) {
419
+ return (
420
+ <html lang="en">
421
+ <body>
422
+ <PreviewWrapper>
423
+ {children}
424
+ </PreviewWrapper>
425
+ </body>
426
+ </html>
427
+ )
428
+ }
429
+ ```
430
+
431
+ #### Why Conditional Rendering Matters
432
+
433
+ 1. **Performance**: Prevents unnecessary API calls in production
434
+ 2. **Security**: Avoids exposing preview functionality to end users
435
+ 3. **Bundle Size**: Excludes toolbar code from production builds
436
+ 4. **User Experience**: Ensures clean production UI without development tools
437
+
438
+ #### Best Practices for Conditional Rendering
439
+
440
+ - **Environment Variables**: Always use environment variables to control preview mode
441
+ - **Error Boundaries**: Wrap preview components in error boundaries to prevent crashes
442
+ - **Fallback UI**: Always provide a fallback when toolbar fails to load
443
+ - **TypeScript Safety**: Use proper type guards when checking conditions
444
+ - **Bundle Optimization**: Consider dynamic imports for preview-only code
445
+
446
+ ```typescript
447
+ // Dynamic import example for advanced optimization
448
+ const ToolbarDynamic = dynamic(
449
+ () => import('@preprio/prepr-nextjs/react').then(mod => mod.PreprToolbar),
450
+ {
451
+ ssr: false,
452
+ loading: () => <div>Loading preview tools...</div>
453
+ }
454
+ )
455
+ ```
456
+
457
+ ### 5. User Tracking Setup
458
+
459
+ The tracking pixel is essential for collecting user interaction data and enabling personalization features. It should be included in all environments (both preview and production).
460
+
461
+ #### Basic Setup
462
+
463
+ Add the tracking pixel to your layout's `<head>` section:
464
+
465
+ ```typescript
466
+ import { extractAccessToken } from '@preprio/prepr-nextjs/server'
467
+ import { PreprTrackingPixel } from '@preprio/prepr-nextjs/react'
468
+
469
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
470
+ const accessToken = extractAccessToken(process.env.PREPR_GRAPHQL_URL!)
471
+
472
+ return (
473
+ <html>
474
+ <head>
475
+ {accessToken && <PreprTrackingPixel accessToken={accessToken!} />}
476
+ </head>
477
+ <body>{children}</body>
478
+ </html>
479
+ )
480
+ }
481
+ ```
482
+
483
+ #### Alternative: Body Placement
484
+
485
+ You can also place the tracking pixel in the body if needed:
486
+
487
+ ```typescript
488
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
489
+ const accessToken = extractAccessToken(process.env.PREPR_GRAPHQL_URL!)
490
+
491
+ return (
492
+ <html>
493
+ <body>
494
+ {accessToken && <PreprTrackingPixel accessToken={accessToken!} />}
495
+ {children}
496
+ </body>
497
+ </html>
498
+ )
499
+ }
500
+ ```
501
+
502
+ ### 6. API Integration
503
+
504
+ Use the `getPreprHeaders()` helper function in your data fetching to enable personalization and A/B testing:
505
+
506
+ #### With Apollo Client
507
+
508
+ ```typescript
60
509
  import { getClient } from '@/lib/client'
61
- import { GetPageBySlugDocument, GetPageBySlugQuery } from '@/gql/graphql'
510
+ import { GetPageBySlugDocument } from '@/gql/graphql'
62
511
  import { getPreprHeaders } from '@preprio/prepr-nextjs/server'
63
512
 
64
- const getData = async () => {
65
- // Fetching the data using Apollo Client
66
- const {data} = await getClient().query < GetPageBySlugQuery > ({
67
- query: GetPageBySlugDocument,
68
- variables: {
69
- slug: '/',
70
- },
71
- context: {
72
- // Call the getPreprHeaders function to get the appropriate headers
73
- headers: getPreprHeaders(),
74
- },
75
- fetchPolicy: 'no-cache',
76
- })
513
+ const getData = async (slug: string) => {
514
+ const { data } = await getClient().query({
515
+ query: GetPageBySlugDocument,
516
+ variables: { slug },
517
+ context: {
518
+ headers: await getPreprHeaders(),
519
+ },
520
+ fetchPolicy: 'no-cache',
521
+ })
522
+ return data
77
523
  }
78
524
  ```
79
- See the JavaScript example code below in the `page.js`file.
80
525
 
81
- ```javascript
82
- import { getClient } from '@/lib/client'
83
- import { GetPageBySlug } from '@/queries/get-page-by-slug';
526
+ #### With Fetch API
527
+
528
+ ```typescript
84
529
  import { getPreprHeaders } from '@preprio/prepr-nextjs/server'
85
530
 
86
- const getData = async () => {
87
- // Fetching the data using Apollo Client
88
- const { data } = await client.query({
89
- query: GetPageBySlug,
90
- variables: {
91
- slug: '/',
531
+ const getData = async (slug: string) => {
532
+ const headers = await getPreprHeaders()
533
+
534
+ const response = await fetch(process.env.PREPR_GRAPHQL_URL!, {
535
+ method: 'POST',
536
+ headers: {
537
+ 'Content-Type': 'application/json',
538
+ ...headers,
92
539
  },
93
- context: {
94
- // Call the getPreprHeaders function to get the appropriate headers
95
- headers: getPreprHeaders(),
96
- },
97
- fetchPolicy: 'no-cache',
98
- })
99
- return data;
540
+ body: JSON.stringify({
541
+ query: `
542
+ query GetPageBySlug($slug: String!) {
543
+ Page(slug: $slug) {
544
+ title
545
+ content
546
+ }
547
+ }
548
+ `,
549
+ variables: { slug },
550
+ }),
551
+ })
552
+
553
+ return response.json()
100
554
  }
101
555
  ```
102
556
 
103
- ### Installing the Prepr preview toolbar component
557
+ ## πŸŽ›οΈ API Reference
104
558
 
105
- The Prepr preview toolbar component fetches all segments from the Prepr API. So, you need to give it access to do this as follows:
559
+ ### Server Functions
106
560
 
107
- 1. In your Prepr environment, go to the **Settings β†’ Access tokens** page to view all the access tokens.
108
- 2. Click the *GraphQL Preview* access token to open it and tick the **Enable edit mode** checkbox and click the **Save** button.
561
+ #### `getPreprHeaders()`
562
+ Returns all Prepr headers for API requests.
109
563
 
110
- ![Preview access token](https://assets-site.prepr.io/229kaekn7m96//preview-access-token-enable-edit-mode.png)
564
+ ```typescript
565
+ import { getPreprHeaders } from '@preprio/prepr-nextjs/server'
111
566
 
112
- To implement the toolbar component, navigate to your root layout file, this is usually `layout.tsx`.
567
+ const headers = await getPreprHeaders()
568
+ // Returns: { 'prepr-customer-id': 'uuid', 'Prepr-Segments': 'segment-id', ... }
569
+ ```
113
570
 
114
- Then add the following code to the `layout.tsx` file:
571
+ #### `getPreprUUID()`
572
+ Returns the current customer ID from headers.
115
573
 
116
- ```javascript
117
- // Helper function to get all the props for the PreviewBar component (this needs a server component)
118
- import { getPreviewBarProps } from '@preprio/prepr-nextjs/server'
574
+ ```typescript
575
+ import { getPreprUUID } from '@preprio/prepr-nextjs/server'
119
576
 
120
- // Import the PreviewBar component & proivder
121
- import {
122
- PreprPreviewBar,
123
- PreprPreviewBarProvider,
124
- } from '@preprio/prepr-nextjs/react'
577
+ const customerId = await getPreprUUID()
578
+ // Returns: 'uuid-string' or null
579
+ ```
125
580
 
126
- // Import the PreviewBar CSS
127
- import '@preprio/prepr-nextjs/index.css'
581
+ #### `getActiveSegment()`
582
+ Returns the currently active segment.
583
+
584
+ ```typescript
585
+ import { getActiveSegment } from '@preprio/prepr-nextjs/server'
586
+
587
+ const segment = await getActiveSegment()
588
+ // Returns: 'segment-id' or null
589
+ ```
590
+
591
+ #### `getActiveVariant()`
592
+ Returns the currently active A/B testing variant.
593
+
594
+ ```typescript
595
+ import { getActiveVariant } from '@preprio/prepr-nextjs/server'
596
+
597
+ const variant = await getActiveVariant()
598
+ // Returns: 'A' | 'B' | null
599
+ ```
600
+
601
+ #### `getToolbarProps()`
602
+ Fetches all necessary props for the toolbar component.
603
+
604
+ ```typescript
605
+ import { getToolbarProps } from '@preprio/prepr-nextjs/server'
606
+
607
+ const props = await getToolbarProps(process.env.PREPR_GRAPHQL_URL!)
608
+ // Returns: { activeSegment, activeVariant, data }
609
+ ```
128
610
 
611
+ #### `validatePreprToken()`
612
+ Validates a Prepr GraphQL URL format.
129
613
 
130
- export default async function RootLayout({children}: {children: React.ReactNode}) {
131
- // Get the props for the PreviewBar component, pass the access token as an argument
132
- const previewBarProps = await getPreviewBarProps(process.env.PREPR_GRAPHQL_URL!)
614
+ ```typescript
615
+ import { validatePreprToken } from '@preprio/prepr-nextjs/server'
133
616
 
134
- return (
135
- <html>
136
- <head>
137
- {/*...*/}
138
- </head>
139
- <body>
140
- <PreprPreviewBarProvider props={previewBarProps}>
141
- <PreprPreviewBar />
142
- {children}
143
- </PreprPreviewBarProvider>
144
- </body>
145
- </html>
146
- )
617
+ const result = validatePreprToken('https://graphql.prepr.io/YOUR_ACCESS_TOKEN')
618
+ // Returns: { valid: boolean, error?: string }
619
+ ```
620
+
621
+ #### `isPreviewMode()`
622
+ Checks if the current environment is in preview mode.
623
+
624
+ ```typescript
625
+ import { isPreviewMode } from '@preprio/prepr-nextjs/server'
626
+
627
+ const isPreview = isPreviewMode()
628
+ // Returns: boolean
629
+ ```
630
+
631
+ #### `extractAccessToken()`
632
+ Extracts the access token from a Prepr GraphQL URL.
633
+
634
+ ```typescript
635
+ import { extractAccessToken } from '@preprio/prepr-nextjs/server'
636
+
637
+ const token = extractAccessToken('https://graphql.prepr.io/abc123')
638
+ // Returns: 'abc123' or null
639
+ ```
640
+
641
+ ### React Components
642
+
643
+ #### `PreprToolbarProvider`
644
+ Context provider that wraps your app with toolbar functionality.
645
+
646
+ ```typescript
647
+ import { PreprToolbarProvider } from '@preprio/prepr-nextjs/react'
648
+
649
+ <PreprToolbarProvider props={toolbarProps}>
650
+ {children}
651
+ </PreprToolbarProvider>
652
+ ```
653
+
654
+ #### `PreprToolbar`
655
+ The main toolbar component.
656
+
657
+ ```typescript
658
+ import { PreprToolbar } from '@preprio/prepr-nextjs/react'
659
+
660
+ <PreprToolbar />
661
+ ```
662
+
663
+ #### `PreprTrackingPixel`
664
+ User tracking component that loads the Prepr tracking script.
665
+
666
+ ```typescript
667
+ import { PreprTrackingPixel } from '@preprio/prepr-nextjs/react'
668
+
669
+ <PreprTrackingPixel accessToken="your-access-token" />
670
+ ```
671
+
672
+ ## πŸ”§ Configuration Options
673
+
674
+ ### Environment Variables
675
+
676
+ | Variable | Required | Default | Description |
677
+ |----------|----------|---------|-------------|
678
+ | `PREPR_GRAPHQL_URL` | Yes | - | Your Prepr GraphQL endpoint URL |
679
+ | `PREPR_ENV` | Yes | - | Environment mode (`preview` or `production`) |
680
+
681
+ ### Middleware Options
682
+
683
+ ```typescript
684
+ // Simple usage (creates new NextResponse)
685
+ createPreprMiddleware(request, {
686
+ preview: boolean // Enable preview mode functionality
687
+ })
688
+
689
+ // Chaining usage (uses existing NextResponse)
690
+ createPreprMiddleware(request, response, {
691
+ preview: boolean // Enable preview mode functionality
692
+ })
693
+ ```
694
+
695
+ ### Toolbar Options
696
+
697
+ ```typescript
698
+ <PreprToolbarProvider
699
+ props={toolbarProps}
700
+ options={{
701
+ debug: true // Enable debug logging
702
+ }}
703
+ >
704
+ ```
705
+
706
+ ## 🚨 Troubleshooting
707
+
708
+ ### Common Issues
709
+
710
+ #### Toolbar Not Showing
711
+ - **Check environment**: Ensure `PREPR_ENV=preview` is set
712
+ - **Verify GraphQL URL**: Make sure `PREPR_GRAPHQL_URL` is correct and follows the format `https://graphql.prepr.io/YOUR_ACCESS_TOKEN`
713
+ - **Check token permissions**: Ensure "Enable edit mode" is checked in Prepr
714
+
715
+ #### Headers Not Working
716
+ - **Middleware setup**: Verify middleware is properly configured
717
+ - **API calls**: Ensure you're using `getPreprHeaders()` in your API calls
718
+ - **Environment**: Check that environment variables are loaded
719
+
720
+ #### TypeScript Errors
721
+ - **Version compatibility**: Ensure you're using compatible versions of Next.js and React
722
+ - **Type imports**: Import types from `@preprio/prepr-nextjs/types`
723
+
724
+ #### Build Issues
725
+ - **CSS imports**: Make sure to import the CSS file in your layout
726
+ - **Server components**: Ensure server functions are only called in server components
727
+
728
+ ### Error Handling
729
+
730
+ The package includes comprehensive error handling:
731
+
732
+ ```typescript
733
+ import { PreprError } from '@preprio/prepr-nextjs/server'
734
+
735
+ try {
736
+ const segments = await getPreprEnvironmentSegments(process.env.PREPR_GRAPHQL_URL!)
737
+ } catch (error) {
738
+ if (error instanceof PreprError) {
739
+ console.log('Error code:', error.code)
740
+ console.log('Context:', error.context)
741
+ }
147
742
  }
148
743
  ```
149
744
 
150
- Now the Prepr preview toolbar is rendered on every page of your website. This component shows the segments in a dropdown list and a switch for A and B variants for an A/B test. If you have added the `getPreprHeaders()` function to your API calls it automatically updates the segments and A/B testing variants when you select a new segment or variant.
745
+ ### Debug Mode
746
+
747
+ Enable debug logging in development:
748
+
749
+ ```typescript
750
+ <PreprToolbarProvider
751
+ props={toolbarProps}
752
+ options={{ debug: true }}
753
+ >
754
+ ```
755
+
756
+ ## πŸ“Š How It Works
757
+
758
+ ### Middleware Functionality
759
+
760
+ The middleware automatically:
761
+ 1. **Generates customer IDs**: Creates unique visitor identifiers
762
+ 2. **Tracks UTM parameters**: Captures marketing campaign data
763
+ 3. **Manages segments**: Handles audience segmentation
764
+ 4. **Processes A/B tests**: Manages variant assignments
765
+ 5. **Sets headers**: Adds necessary headers for API calls
151
766
 
152
- ### Helper functions
767
+ ### Toolbar Features
153
768
 
154
- #### getPreprUUID()
155
- The `getPreprUUID()` function will return the value of the `__prepr_uid` cookie. This can be useful if you want to store the `__prepr_uid` in a cookie or local storage.
769
+ The toolbar provides:
770
+ - **Segment selection**: Switch between different audience segments
771
+ - **A/B testing**: Toggle between variants A and B
772
+ - **Edit mode**: Visual content editing capabilities
773
+ - **Reset functionality**: Clear personalization settings
156
774
 
157
- #### getActiveSegment()
158
- Returns the active segment from the `Prepr-Segments` header.
775
+ ### Visual Editing
159
776
 
160
- #### getActiveVariant()
161
- Returns the active variant from the `Prepr-ABTesting` header.
777
+ When edit mode is enabled, the package:
778
+ 1. **Scans content**: Identifies editable content using Stega encoding
779
+ 2. **Highlights elements**: Shows proximity-based highlighting
780
+ 3. **Provides overlays**: Click-to-edit functionality
781
+ 4. **Syncs with Prepr**: Direct integration with Prepr's editing interface
162
782
 
163
- #### getPreviewHeaders()
164
- Helper function to only get the preview headers.
783
+ ## πŸ”„ Upgrading from v1 to v2
165
784
 
166
- #### getPreprHeaders()
167
- Helper function that will either return the customer id header or the preview headers depending on the `PREPR_ENV` environment variable.
785
+ If you're upgrading from v1, please follow the [Upgrade Guide](./UPGRADE_GUIDE.md) for detailed migration instructions.
168
786
 
169
- #### getPreviewBarProps()
170
- Helper function to get the props for the PreviewBar component. Will return the segments and A/B testing variants aswell as an aray of all the segments.
787
+ ## πŸ“œ License
171
788
 
172
- ## πŸ“Œ Upgrade from v1 to v2
789
+ MIT License - see the [LICENSE](./LICENSE) file for details.
173
790
 
174
- If you’re upgrading from **Prepr Next.js v1** to **v2**,
175
- please follow the [Upgrade Guide](./UPGRADE_GUIDE.mdx) for step-by-step instructions.
791
+ ## πŸ†˜ Support
176
792
 
177
- This guide will help you update your middleware, helper imports, and preview toolbar usage.
793
+ - **Documentation**: [Prepr Documentation](https://docs.prepr.io)
794
+ - **Issues**: [GitHub Issues](https://github.com/preprio/prepr-nextjs/issues)
795
+ - **Support**: [Prepr Support](https://prepr.io/support)