@burdenoff/website-sdk 2026.1021.2 → 2026.1021.4

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
@@ -318,6 +318,64 @@ attributes are deliberately distinct: several assertions select
318
318
  back, so a second element wearing it would keep them green while describing the
319
319
  wrong element.
320
320
 
321
+ ### Legal pages (`LegalPage`)
322
+
323
+ Every product website publishes the same legal set, read from the global CMS.
324
+ A product either has its own row for a slug or falls back to the global
325
+ template, whose `{{productName}}`-style placeholders are filled in by
326
+ `publicResolvedContentPage` (always use the resolved query; the plain one
327
+ returns raw placeholders for the templates).
328
+
329
+ | `document` | CMS slug |
330
+ |---|---|
331
+ | `privacy` | `privacy-policy` |
332
+ | `terms` | `terms-of-service` |
333
+ | `cookies` | `cookie-policy` |
334
+ | `refunds` | `refund-policy` |
335
+ | `aup` | `acceptable-use-policy` |
336
+ | `dpa` | `data-processing-addendum` |
337
+ | `ai-terms` | `ai-product-terms` |
338
+ | `subprocessors` | `subprocessors` |
339
+
340
+ For prerendered sites, fetch at build time and pass the result in, so the page
341
+ renders its final HTML with no request and no layout shift:
342
+
343
+ ```ts
344
+ // scripts/fetch-legal-content.ts
345
+ import { WebSDKClient } from '@burdenoff/website-sdk/client'
346
+ import { fetchLegalContent } from '@burdenoff/website-sdk/content'
347
+
348
+ const client = new WebSDKClient({
349
+ gatewayUrl: 'https://graphql.burdenoff.com/global/graphql',
350
+ productId: 'vibecontrols',
351
+ })
352
+ // Rejects on any failed request: keep the previous JSON instead of writing an outage.
353
+ const pages = await fetchLegalContent(client, { productId: 'vibecontrols' })
354
+ await Bun.write('src/data/legal-content.json', JSON.stringify(pages, null, 2) + '\n')
355
+ ```
356
+
357
+ ```tsx
358
+ import { LegalPage } from '@burdenoff/website-sdk'
359
+ import legal from '@/data/legal-content.json'
360
+
361
+ <Route
362
+ path="/dpa"
363
+ element={
364
+ <LegalPage
365
+ document="dpa"
366
+ initialContent={legal['data-processing-addendum']}
367
+ productName="VibeControls"
368
+ contactEmail="legal@vibecontrols.com"
369
+ />
370
+ }
371
+ />
372
+ ```
373
+
374
+ Without `initialContent` the page fetches at run time through the
375
+ `WebSDKProvider` client. A document the CMS does not have renders an honest
376
+ "not available" state marked `noindex`. A leading `# Title` in markdown content
377
+ is lifted into the page heading, so there is only ever one `<h1>`.
378
+
321
379
  ### SEO Component
322
380
 
323
381
  ```tsx