lynkow 3.8.75 → 3.8.77

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.d.mts CHANGED
@@ -154,9 +154,21 @@ declare class ContentsService extends BaseService {
154
154
  */
155
155
  getBySlug(slug: string, options?: BaseRequestOptions): Promise<Content>;
156
156
  /**
157
- * Invalidates all cached content responses (lists and single articles).
158
- * Call this after knowing content has been updated to force fresh data
159
- * on the next request.
157
+ * Invalidate every cached response produced by this service (list
158
+ * queries, slug lookups, single-content fetches). Call after an admin
159
+ * mutation or on receipt of a `content.*` webhook so the next public
160
+ * request bypasses the 5-minute SWR cache and hits the origin.
161
+ *
162
+ * @returns void
163
+ * @throws Never throws.
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // In a Next.js route handler receiving a Lynkow webhook:
168
+ * if (event.type === 'content.updated') {
169
+ * lynkow.contents.clearCache()
170
+ * }
171
+ * ```
160
172
  */
161
173
  clearCache(): void;
162
174
  }
@@ -251,9 +263,19 @@ declare class CategoriesService extends BaseService {
251
263
  */
252
264
  getBySlug(slug: string, options?: CategoryOptions & BaseRequestOptions): Promise<CategoryDetailResponse>;
253
265
  /**
254
- * Invalidates all cached category responses (lists, tree, and detail views).
255
- * Call this after knowing categories have been updated to force fresh data
256
- * on the next request.
266
+ * Invalidate every cached category response (flat list, hierarchy
267
+ * tree, detail views with paginated contents). Call after an admin
268
+ * mutation or on receipt of a `category.*` webhook so the next public
269
+ * request bypasses the 30-minute SWR cache.
270
+ *
271
+ * @returns void
272
+ * @throws Never throws.
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * // On category restructuring:
277
+ * lynkow.categories.clearCache()
278
+ * ```
257
279
  */
258
280
  clearCache(): void;
259
281
  }
@@ -287,9 +309,17 @@ declare class TagsService extends BaseService {
287
309
  */
288
310
  list(options?: BaseRequestOptions): Promise<TagsListResponse>;
289
311
  /**
290
- * Invalidates all cached tag responses.
291
- * Call this after knowing tags have been updated to force fresh data
292
- * on the next request.
312
+ * Invalidate every cached tag response (lists, tag-filtered contents).
313
+ * Call after an admin mutation or on receipt of a `tag.*` webhook so
314
+ * the next public request bypasses the SWR cache.
315
+ *
316
+ * @returns void
317
+ * @throws Never throws.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * lynkow.tags.clearCache()
322
+ * ```
293
323
  */
294
324
  clearCache(): void;
295
325
  }
@@ -298,7 +328,14 @@ declare class TagsService extends BaseService {
298
328
  * Options for listing pages
299
329
  */
300
330
  interface PagesListOptions extends BaseRequestOptions {
301
- /** Filter pages by tag (e.g., 'legal' for legal documents) */
331
+ /**
332
+ * Restrict results to pages carrying this tag slug (e.g. `'legal'` to
333
+ * list Privacy Policy + Terms of Service). Tags are declared on each
334
+ * page in the admin under SEO / Organization and used mainly for
335
+ * grouping unrelated pages that share a purpose.
336
+ *
337
+ * Omit to return every published page for the site.
338
+ */
302
339
  tag?: string;
303
340
  }
304
341
  /**
@@ -403,9 +440,19 @@ declare class PagesService extends BaseService {
403
440
  */
404
441
  getJsonLd(slug: string, options?: BaseRequestOptions): Promise<Record<string, unknown>>;
405
442
  /**
406
- * Invalidates all cached page responses (lists, slug lookups, path lookups,
407
- * and JSON-LD data). Call this after knowing pages have been updated to
408
- * force fresh data on the next request.
443
+ * Invalidate every cached page response (lists, slug lookups, path
444
+ * lookups, and the JSON-LD endpoint). Call after an admin mutation or
445
+ * on receipt of a `page.*` webhook so the next public request bypasses
446
+ * the SWR cache and re-materializes the resolved data (including
447
+ * `structuredData.graph`).
448
+ *
449
+ * @returns void
450
+ * @throws Never throws.
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * lynkow.pages.clearCache()
455
+ * ```
409
456
  */
410
457
  clearCache(): void;
411
458
  }
@@ -479,6 +526,9 @@ declare class BlocksService extends BaseService {
479
526
  * @param slug - The block slug
480
527
  * @param options - Request options
481
528
  * @returns The resolved global block
529
+ * @throws {LynkowError} With code `'NOT_FOUND'` when the slug does not
530
+ * match any global block for the site, `'NETWORK_ERROR'` on transport
531
+ * failure. Same surface as {@link getBySlug}.
482
532
  *
483
533
  * @example
484
534
  * ```typescript
@@ -488,9 +538,18 @@ declare class BlocksService extends BaseService {
488
538
  */
489
539
  global(slug: string, options?: BaseRequestOptions): Promise<GlobalBlockResponse>;
490
540
  /**
491
- * Invalidates all cached global block responses (site config and individual blocks).
492
- * Call this after knowing global blocks have been updated to force fresh data
493
- * on the next request.
541
+ * Invalidate every cached global block response (site config payload
542
+ * and per-slug lookups). Call after an admin mutation or on receipt of
543
+ * a `globalBlock.updated` webhook so the next public request hits the
544
+ * origin and re-resolves any referenced variables.
545
+ *
546
+ * @returns void
547
+ * @throws Never throws.
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * lynkow.globals.clearCache()
552
+ * ```
494
553
  */
495
554
  clearCache(): void;
496
555
  }
@@ -586,8 +645,20 @@ declare class FormsService extends BaseService {
586
645
  */
587
646
  submit(slug: string, data: FormSubmitData, options?: SubmitOptions & BaseRequestOptions): Promise<FormSubmitResponse>;
588
647
  /**
589
- * Invalidates all cached form schema responses. Call this if you know
590
- * a form definition has changed and want to fetch the latest schema.
648
+ * Invalidate every cached form schema response. Call after an admin
649
+ * mutation or on receipt of a `form.*` webhook so the next public
650
+ * request re-fetches the latest field definitions (required fields,
651
+ * validators, spam settings).
652
+ *
653
+ * Does not affect form submissions, which are never cached.
654
+ *
655
+ * @returns void
656
+ * @throws Never throws.
657
+ *
658
+ * @example
659
+ * ```typescript
660
+ * lynkow.forms.clearCache()
661
+ * ```
591
662
  */
592
663
  clearCache(): void;
593
664
  }
@@ -696,6 +767,9 @@ declare class ReviewsService extends BaseService {
696
767
  * // Render email field as required
697
768
  * }
698
769
  * ```
770
+ *
771
+ * @throws {LynkowError} With code `'NETWORK_ERROR'` on transport
772
+ * failure, `'NOT_FOUND'` if the site does not exist.
699
773
  */
700
774
  settings(): Promise<ReviewSettings>;
701
775
  /**
@@ -734,9 +808,19 @@ declare class ReviewsService extends BaseService {
734
808
  */
735
809
  submit(data: ReviewSubmitData, options?: SubmitOptions & BaseRequestOptions): Promise<ReviewSubmitResponse>;
736
810
  /**
737
- * Invalidates all cached review responses (lists, individual reviews, and settings).
738
- * This is called automatically after a successful `submit()`, but can also be
739
- * called manually if needed.
811
+ * Invalidate every cached review response (lists, individual reviews,
812
+ * settings). Automatically invoked after a successful {@link submit};
813
+ * call it manually after an admin moderation action or on receipt of a
814
+ * `review.*` webhook to keep public listings in sync.
815
+ *
816
+ * @returns void
817
+ * @throws Never throws.
818
+ *
819
+ * @example
820
+ * ```typescript
821
+ * // After an admin approved a pending review:
822
+ * lynkow.reviews.clearCache()
823
+ * ```
740
824
  */
741
825
  clearCache(): void;
742
826
  }
@@ -782,9 +866,20 @@ declare class SiteService extends BaseService {
782
866
  */
783
867
  getConfig(): Promise<SiteConfig>;
784
868
  /**
785
- * Invalidates the cached site configuration. Call this if you know the
786
- * site settings have changed (e.g. after a locale is added) and want to
787
- * force a fresh fetch on the next `getConfig()` call.
869
+ * Invalidate the cached site configuration. Call after a settings
870
+ * change on the admin (branding, enabled locales, default author,
871
+ * search config) or on receipt of a `site.updated` webhook so the next
872
+ * `getConfig()` fetches fresh values.
873
+ *
874
+ * @returns void
875
+ * @throws Never throws.
876
+ *
877
+ * @example
878
+ * ```typescript
879
+ * // After enabling a new locale in the admin:
880
+ * lynkow.site.clearCache()
881
+ * const fresh = await lynkow.site.getConfig()
882
+ * ```
788
883
  */
789
884
  clearCache(): void;
790
885
  }
@@ -854,9 +949,20 @@ declare class LegalService extends BaseService {
854
949
  */
855
950
  getBySlug(slug: string, options?: BaseRequestOptions): Promise<LegalDocument>;
856
951
  /**
857
- * Invalidates all cached legal document responses.
952
+ * Invalidate every cached legal document response. Kept for
953
+ * backwards compatibility with sites that still reference the legacy
954
+ * `/legal/*` surface.
955
+ *
956
+ * @deprecated This service is deprecated. Use `lynkow.pages` instead,
957
+ * which covers legal pages along with every other page type and is
958
+ * actively maintained.
959
+ * @returns void
960
+ * @throws Never throws.
858
961
  *
859
- * @deprecated This service is deprecated. Use `lynkow.pages` instead.
962
+ * @example
963
+ * ```typescript
964
+ * lynkow.legal.clearCache() // Deprecated; prefer lynkow.pages.clearCache()
965
+ * ```
860
966
  */
861
967
  clearCache(): void;
862
968
  }
@@ -932,9 +1038,19 @@ declare class CookiesService extends BaseService {
932
1038
  */
933
1039
  logConsent(preferences: CookiePreferences, options?: BaseRequestOptions): Promise<ConsentLogResponse>;
934
1040
  /**
935
- * Invalidates the cached cookie consent configuration. Call this if you
936
- * know the consent settings have changed and want to force a fresh fetch
937
- * on the next `getConfig()` call.
1041
+ * Invalidate the cached cookie consent configuration (categories,
1042
+ * scripts, banner appearance). Call after a settings change on the
1043
+ * admin or on receipt of a `cookies.updated` webhook so the next
1044
+ * `getConfig()` returns the updated categories and the consent banner
1045
+ * reflects the new policy.
1046
+ *
1047
+ * @returns void
1048
+ * @throws Never throws.
1049
+ *
1050
+ * @example
1051
+ * ```typescript
1052
+ * lynkow.cookies.clearCache()
1053
+ * ```
938
1054
  */
939
1055
  clearCache(): void;
940
1056
  }
@@ -969,6 +1085,8 @@ declare class SeoService extends BaseService {
969
1085
  *
970
1086
  * @param options - Request options (custom fetch options)
971
1087
  * @returns The sitemap XML content as a raw string
1088
+ * @throws {LynkowError} With code `'NETWORK_ERROR'` on transport
1089
+ * failure, `'NOT_FOUND'` if the site has sitemap generation disabled.
972
1090
  *
973
1091
  * @example
974
1092
  * ```typescript
@@ -1011,6 +1129,8 @@ declare class SeoService extends BaseService {
1011
1129
  *
1012
1130
  * @param options - Request options (custom fetch options)
1013
1131
  * @returns The robots.txt content as a raw string
1132
+ * @throws {LynkowError} With code `'NETWORK_ERROR'` on transport
1133
+ * failure, `'NOT_FOUND'` if the site has robots.txt disabled.
1014
1134
  *
1015
1135
  * @example
1016
1136
  * ```typescript
@@ -1035,6 +1155,9 @@ declare class SeoService extends BaseService {
1035
1155
  * When set, the API returns `/{locale}/llms.txt`. When omitted, returns
1036
1156
  * the default locale version.
1037
1157
  * @returns The llms.txt Markdown content as a raw string
1158
+ * @throws {LynkowError} With code `'NETWORK_ERROR'` on transport
1159
+ * failure, `'NOT_FOUND'` if `llmsTxtEnabled` is `false` on the site's
1160
+ * SEO settings or the locale has no llms.txt.
1038
1161
  *
1039
1162
  * @example
1040
1163
  * ```typescript
@@ -1061,6 +1184,9 @@ declare class SeoService extends BaseService {
1061
1184
  * - `locale` — fetch the full content for a specific locale (e.g. `'en'`).
1062
1185
  * When set, only content in that locale is included.
1063
1186
  * @returns The full Markdown content of all published articles and pages as a raw string
1187
+ * @throws {LynkowError} With code `'NETWORK_ERROR'` on transport
1188
+ * failure, `'NOT_FOUND'` if `llmsTxtEnabled` is `false` on the site's
1189
+ * SEO settings.
1064
1190
  *
1065
1191
  * @example
1066
1192
  * ```typescript
@@ -1071,6 +1197,9 @@ declare class SeoService extends BaseService {
1071
1197
  * headers: { 'Content-Type': 'text/plain; charset=utf-8' }
1072
1198
  * })
1073
1199
  * }
1200
+ *
1201
+ * // Fetch the French version
1202
+ * const md = await lynkow.seo.llmsFullTxt({ locale: 'fr' })
1074
1203
  * ```
1075
1204
  */
1076
1205
  llmsFullTxt(options?: BaseRequestOptions): Promise<string>;
@@ -1231,35 +1360,68 @@ declare class PathsService extends BaseService {
1231
1360
  * Only published content appears in search results.
1232
1361
  */
1233
1362
  interface SearchHit {
1234
- /** Content UUID */
1363
+ /** Content UUID. Matches `id` on `Content` / `ContentSummary`. */
1235
1364
  id: string;
1236
- /** Article title */
1365
+ /**
1366
+ * Content title in the searched locale. Never empty (the indexer skips
1367
+ * untitled drafts). May contain `<em>` markers when highlighting is
1368
+ * enabled; see `_formatted.title` for the highlighted variant.
1369
+ */
1237
1370
  title: string;
1238
- /** URL slug */
1371
+ /** URL-safe slug. Unique within the site + locale combination. */
1239
1372
  slug: string;
1240
- /** Short summary / excerpt */
1373
+ /**
1374
+ * Short text summary shown in the search dropdown. Taken from the
1375
+ * content's `excerpt` field, or generated from the first paragraph
1376
+ * when `excerpt` is empty. Always non-null in search results.
1377
+ */
1241
1378
  excerpt: string;
1242
- /** SEO meta title */
1379
+ /**
1380
+ * SEO meta title. Falls back to {@link title} when the content has no
1381
+ * override. Max ~255 characters, generally kept under 60 for search
1382
+ * result listings.
1383
+ */
1243
1384
  metaTitle: string;
1244
- /** SEO meta description */
1385
+ /**
1386
+ * SEO meta description. Falls back to {@link excerpt} when the content
1387
+ * has no override. Max ~500 characters, typically under 160 for
1388
+ * search snippets.
1389
+ */
1245
1390
  metaDescription: string;
1246
1391
  /** Content locale code (e.g. `'fr'`, `'en'`) */
1247
1392
  locale: string;
1248
1393
  /** Full URL path including locale and category prefix (e.g. `'/fr/guides/forms'`) */
1249
1394
  path: string;
1250
- /** Content type (e.g. `'post'`) */
1395
+ /**
1396
+ * Content type slug. Currently always `'post'`; the value is exposed
1397
+ * to support future content types (product, event, etc.) without a
1398
+ * breaking schema change.
1399
+ */
1251
1400
  type: string;
1252
- /** Categories assigned to this content */
1401
+ /**
1402
+ * Categories assigned to this content as minimal `{ name, slug }`
1403
+ * projections. Empty array when the content has no category. Use the
1404
+ * `slug` to build category URLs and pass to
1405
+ * {@link CategoriesService.getBySlug} for full detail.
1406
+ */
1253
1407
  categories: Array<{
1254
1408
  name: string;
1255
1409
  slug: string;
1256
1410
  }>;
1257
- /** Tags assigned to this content */
1411
+ /**
1412
+ * Tags assigned to this content as minimal `{ name, slug }`
1413
+ * projections. Empty array when the content has no tag. Use the
1414
+ * `slug` for tag-filtered listings.
1415
+ */
1258
1416
  tags: Array<{
1259
1417
  name: string;
1260
1418
  slug: string;
1261
1419
  }>;
1262
- /** Full name of the content author */
1420
+ /**
1421
+ * Full name of the content author (or the site's default author
1422
+ * when the content has no explicit author). Always non-empty because
1423
+ * the indexer requires a tokenizable value.
1424
+ */
1263
1425
  authorName: string;
1264
1426
  /** Featured image URL, or `null` if none */
1265
1427
  featuredImage: string | null;
@@ -1285,19 +1447,42 @@ interface SearchHit {
1285
1447
  * Contains an array of matching articles and pagination metadata.
1286
1448
  */
1287
1449
  interface SearchResponse {
1288
- /** Array of matching articles, ordered by relevance */
1450
+ /**
1451
+ * Matching articles for the current page of results, already ordered
1452
+ * by relevance. Empty array when the query matches nothing.
1453
+ */
1289
1454
  data: SearchHit[];
1290
- /** Pagination and query metadata */
1455
+ /**
1456
+ * Pagination and query metadata for rendering controls like "N results
1457
+ * in 42 ms" or a paginator. Uses snake-free naming (`page`,
1458
+ * `totalPages`, `perPage`) that differs from the standard
1459
+ * {@link PaginationMeta} because the search engine response predates
1460
+ * the common pagination type.
1461
+ */
1291
1462
  meta: {
1292
- /** Total number of matching results across all pages */
1463
+ /**
1464
+ * Total number of matching results across every page. Useful for
1465
+ * "Showing 1-10 of 142" UI. Capped at the search engine's
1466
+ * configured upper bound (50_000 by default).
1467
+ */
1293
1468
  total: number;
1294
1469
  /** Current page number (1-based) */
1295
1470
  page: number;
1296
- /** Total number of pages */
1471
+ /**
1472
+ * Total number of pages for the current query + `perPage`. `1` when
1473
+ * results fit on one page, `0` when `total === 0`.
1474
+ */
1297
1475
  totalPages: number;
1298
- /** Number of results per page */
1476
+ /**
1477
+ * Number of results per page as actually applied by the search
1478
+ * engine (the request's `limit` clamped to 1-100).
1479
+ */
1299
1480
  perPage: number;
1300
- /** The search query as received */
1481
+ /**
1482
+ * The search query echoed back from the server, useful for
1483
+ * debouncing UIs that drop late responses when the input has
1484
+ * changed. Whitespace is preserved as-sent.
1485
+ */
1301
1486
  query: string;
1302
1487
  /** Search engine processing time in milliseconds */
1303
1488
  processingTimeMs: number;
@@ -1329,11 +1514,19 @@ interface SearchOptions extends BaseRequestOptions {
1329
1514
  * round-tripping through your server.
1330
1515
  */
1331
1516
  interface SearchConfig {
1332
- /** Public search host URL (e.g. `'https://search.lynkow.com'`) */
1517
+ /**
1518
+ * Public search engine host URL (e.g. `'https://search.lynkow.com'`).
1519
+ * Use as the `host` when instantiating a Meilisearch-compatible
1520
+ * browser client. Does not include a trailing slash.
1521
+ */
1333
1522
  host: string;
1334
1523
  /** Short-lived tenant token (JWT, 1-hour expiry) scoped to your site's index */
1335
1524
  apiKey: string;
1336
- /** Your site's search index name */
1525
+ /**
1526
+ * Meilisearch index name for this site, of the form
1527
+ * `site-<siteId>_<locale>` or `site-<siteId>` for single-locale sites.
1528
+ * Pass verbatim as the `index` parameter in browser search queries.
1529
+ */
1337
1530
  indexName: string;
1338
1531
  }
1339
1532
  /**
@@ -1889,9 +2082,13 @@ interface ContentSchema {
1889
2082
  * array; no client-side cascade logic is needed.
1890
2083
  *
1891
2084
  * Reserved ids beginning with `auto:` identify the implicit nodes Lynkow
1892
- * injects automatically (Article, FAQPage, BreadcrumbList, Organization,
1893
- * WebPage). They may appear in `jsonLdExclusions` to opt out of the
1894
- * corresponding auto-node, but MUST NOT be used as user-provided ids.
2085
+ * injects automatically (Article, FAQPage, BreadcrumbList, WebPage). They
2086
+ * may appear in `jsonLdExclusions` to opt out of the corresponding
2087
+ * auto-node, but MUST NOT be used as user-provided ids.
2088
+ *
2089
+ * Organization is no longer auto-injected. Declare it explicitly at the
2090
+ * site level via `seo_settings.jsonLdGraph` (from the admin UI or the
2091
+ * `update_seo_settings` MCP tool).
1895
2092
  */
1896
2093
  /**
1897
2094
  * Source of a JSON-LD node.
@@ -1914,25 +2111,57 @@ type JsonLdNodeSource = 'preset' | 'custom';
1914
2111
  */
1915
2112
  interface JsonLdNode {
1916
2113
  /**
1917
- * Stable node identifier. Auto-generated when the caller does not provide
1918
- * one. Never starts with the reserved `auto:` prefix.
2114
+ * Stable `@id` for this node. Server-generated (pattern `own-<8hex>`) when
2115
+ * the caller omits it on create. Safe to treat as an opaque string; the
2116
+ * public API rewrites it to an absolute URL (`<pageUrl>#<id>`) in the
2117
+ * resolved graph. Never starts with the reserved `auto:` prefix, which is
2118
+ * reserved for nodes Lynkow injects automatically.
1919
2119
  */
1920
2120
  id: string;
1921
- /** schema.org `@type` string (e.g. "Organization", "LocalBusiness"). */
2121
+ /**
2122
+ * schema.org `@type` identifier (e.g. `"Organization"`, `"LocalBusiness"`,
2123
+ * `"Product"`). Any schema.org type is accepted; 27 first-class presets
2124
+ * get typed field mapping server-side, unknown types pass through via
2125
+ * `source: 'custom'`.
2126
+ */
1922
2127
  type: string;
1923
- /** Node payload. For presets, only the preset-documented fields. */
2128
+ /**
2129
+ * Node payload. The accepted shape depends on {@link source}:
2130
+ *
2131
+ * - `preset`: only the fields documented for the matching preset
2132
+ * (e.g. `name`, `address`, `geo` for `LocalBusiness`). Unknown keys are
2133
+ * ignored. Missing context fields (url, inLanguage, etc.) are filled
2134
+ * from the page context at render time.
2135
+ * - `custom`: the full schema.org object, minus `@context` and `@id`
2136
+ * which the server injects. Passed through verbatim after basic sanity
2137
+ * checks (non-empty `@type`, no prototype-pollution keys).
2138
+ */
1924
2139
  data: Record<string, unknown>;
1925
- /** Whether the node was created from a preset or a raw custom JSON-LD. */
2140
+ /** Whether the node was created from a Lynkow typed preset or from raw JSON-LD. */
1926
2141
  source: JsonLdNodeSource;
1927
2142
  }
1928
2143
  /**
1929
2144
  * Cascade configuration stored at any level (site, category, page, content).
1930
2145
  *
1931
- * `graph` carries the nodes declared at this level; `exclusions` lists the
1932
- * parent node ids this level opts out of.
2146
+ * This is the wire shape persisted in the Lynkow database. The public API
2147
+ * exposes the already-resolved graph on `structuredData.graph`; SDK consumers
2148
+ * normally read that resolved array rather than reconstructing one from the
2149
+ * raw configs at each level.
1933
2150
  */
1934
2151
  interface JsonLdGraphConfig {
2152
+ /**
2153
+ * Nodes declared at this cascade level. Order is preserved in the emitted
2154
+ * `@graph` but is not semantically significant for schema.org consumers.
2155
+ * Empty array when no nodes are declared.
2156
+ */
1935
2157
  graph: JsonLdNode[];
2158
+ /**
2159
+ * Parent-level `@id` values this level opts out of. Accepts both
2160
+ * user-provided ids (e.g. `"site-org"`) and the reserved
2161
+ * `auto:article` / `auto:faqpage` / `auto:breadcrumb` / `auto:webpage`
2162
+ * identifiers to suppress Lynkow's implicit nodes. Empty array when no
2163
+ * parent node is excluded.
2164
+ */
1936
2165
  exclusions: string[];
1937
2166
  }
1938
2167
 
@@ -2852,19 +3081,24 @@ interface Page extends PageSummary {
2852
3081
  */
2853
3082
  _warnings?: string[];
2854
3083
  /**
2855
- * Resolved JSON-LD cascade for the page.
2856
- *
2857
- * `graph` contains the `@graph` array merged by the server from the site
2858
- * level plus this page's own nodes plus the auto-nodes (WebPage,
2859
- * BreadcrumbList, Organization when configured). Use
2860
- * {@link renderJsonLdGraph} from the helpers to serialize it as a single
2861
- * `<script type="application/ld+json">` tag.
3084
+ * Resolved JSON-LD cascade for the page. Server-merged and ready to
3085
+ * render; no client-side cascade logic required.
2862
3086
  *
2863
3087
  * `undefined` on responses from older API versions that do not populate
2864
3088
  * the cascade; in that case, fall back to the dedicated
2865
- * `/public/:siteId/pages/:slug/json-ld` endpoint.
3089
+ * `/public/:siteId/pages/:slug/json-ld` endpoint which always returns
3090
+ * the array directly under `data`.
2866
3091
  */
2867
3092
  structuredData?: {
3093
+ /**
3094
+ * The resolved `@graph` array: site-level nodes + this page's own
3095
+ * nodes + auto-nodes (WebPage, BreadcrumbList, Organization when
3096
+ * configured), minus any excluded ids. Each entry is a fully-formed
3097
+ * schema.org object with `@context`, `@id`, and `@type`. Use
3098
+ * {@link renderJsonLdGraph} to serialize the whole array as a single
3099
+ * `<script type="application/ld+json">` tag. Empty array when nothing
3100
+ * is declared and all auto-nodes are excluded.
3101
+ */
2868
3102
  graph: object[];
2869
3103
  };
2870
3104
  }
@@ -4166,7 +4400,18 @@ interface CategoryDetailResponse {
4166
4400
  * Supports the same pagination options as `contents.list()`.
4167
4401
  */
4168
4402
  contents: {
4403
+ /**
4404
+ * Current page of matching content summaries, already filtered to
4405
+ * this category + locale. Empty array when the category has no
4406
+ * published content on this page.
4407
+ */
4169
4408
  data: ContentSummary[];
4409
+ /**
4410
+ * Pagination cursors for the paginated list: `total`, `perPage`,
4411
+ * `currentPage`, `lastPage`, `hasMorePages`. Use these to drive
4412
+ * "Load more" or page-number UIs; shape matches the generic
4413
+ * {@link PaginationMeta}.
4414
+ */
4170
4415
  meta: PaginationMeta;
4171
4416
  };
4172
4417
  /**
@@ -4407,7 +4652,16 @@ interface CategoryResolveResponse {
4407
4652
  * Pagination can be controlled via query parameters on the resolve request.
4408
4653
  */
4409
4654
  contents: {
4655
+ /**
4656
+ * Current page of matching content summaries for the resolved
4657
+ * category. Order follows the site's configured content sort
4658
+ * (typically publication date desc).
4659
+ */
4410
4660
  data: ContentSummary[];
4661
+ /**
4662
+ * Pagination cursors. Shape matches {@link PaginationMeta}; use
4663
+ * `hasMorePages` to decide whether to show a "Load more" button.
4664
+ */
4411
4665
  meta: PaginationMeta;
4412
4666
  };
4413
4667
  }
@@ -4623,23 +4877,48 @@ declare function isCategoryResolve(response: ResolveResponse): response is Categ
4623
4877
  */
4624
4878
 
4625
4879
  /**
4626
- * Data for tracking pageviews
4880
+ * Payload accepted by {@link AnalyticsService.trackPageview}. Every field
4881
+ * is optional; unset values fall back to the browser context at call time.
4627
4882
  */
4628
4883
  interface PageviewData {
4629
- /** Page path (default: window.location.pathname) */
4884
+ /**
4885
+ * URL path to record. Should start with `/`. Query string and hash are
4886
+ * preserved as-is; strip them when they do not identify a distinct
4887
+ * pageview (e.g. tracker-specific UTM parameters). Defaults to
4888
+ * `window.location.pathname` when omitted.
4889
+ */
4630
4890
  path?: string;
4631
- /** Page title (default: document.title) */
4891
+ /**
4892
+ * Human-readable page title as it appears in the browser tab, used for
4893
+ * the analytics dashboard listing. Defaults to `document.title` when
4894
+ * omitted. Max ~255 characters before server-side truncation.
4895
+ */
4632
4896
  title?: string;
4633
- /** Referrer URL */
4897
+ /**
4898
+ * Referring URL for this pageview, typically `document.referrer`.
4899
+ * Pass `''` to record "direct" traffic when you want to override the
4900
+ * browser's value. Omit to let the tracker fill it from
4901
+ * `document.referrer`.
4902
+ */
4634
4903
  referrer?: string;
4635
4904
  }
4636
4905
  /**
4637
- * Data for tracking custom events
4906
+ * Payload accepted by {@link AnalyticsService.trackEvent}. `type` is the
4907
+ * only required field; every other key becomes an ad-hoc property on the
4908
+ * event recorded by the tracker.
4638
4909
  */
4639
4910
  interface EventData {
4640
- /** Event type */
4911
+ /**
4912
+ * Short slug identifying the event (e.g. `'cta_click'`,
4913
+ * `'signup_complete'`). Prefer snake_case so events group cleanly in
4914
+ * the analytics dashboard. Required and must be non-empty.
4915
+ */
4641
4916
  type: string;
4642
- /** Additional event data */
4917
+ /**
4918
+ * Arbitrary extra properties to attach to the event. Values must be
4919
+ * JSON-serializable. Keys prefixed with `_` are reserved for the
4920
+ * tracker and may be overwritten server-side.
4921
+ */
4643
4922
  [key: string]: unknown;
4644
4923
  }
4645
4924
  /**
@@ -4778,6 +5057,9 @@ declare class AnalyticsService {
4778
5057
  * }
4779
5058
  * })
4780
5059
  * ```
5060
+ *
5061
+ * @returns void
5062
+ * @throws Never throws.
4781
5063
  */
4782
5064
  enable(): void;
4783
5065
  /**
@@ -4785,6 +5067,9 @@ declare class AnalyticsService {
4785
5067
  * `trackPageview()` calls become no-ops. The tracker script remains loaded;
4786
5068
  * call `destroy()` to fully remove it.
4787
5069
  *
5070
+ * @returns void
5071
+ * @throws Never throws.
5072
+ *
4788
5073
  * @example
4789
5074
  * ```typescript
4790
5075
  * // Disable tracking when the user revokes analytics consent
@@ -4793,25 +5078,56 @@ declare class AnalyticsService {
4793
5078
  */
4794
5079
  disable(): void;
4795
5080
  /**
4796
- * Returns whether analytics tracking is currently enabled.
5081
+ * Returns whether analytics tracking is currently enabled (i.e. whether
5082
+ * `trackEvent` and `trackPageview` will actually emit). Does not
5083
+ * indicate whether the underlying tracker script has loaded; use
5084
+ * {@link isInitialized} for that.
4797
5085
  *
4798
- * @returns `true` if tracking is enabled (default), `false` if `disable()` was called
5086
+ * @returns `true` if tracking is enabled (default), `false` after
5087
+ * {@link disable} has been called.
5088
+ * @throws Never throws.
5089
+ *
5090
+ * @example
5091
+ * ```typescript
5092
+ * if (lynkow.analytics.isEnabled()) {
5093
+ * // Safe to track
5094
+ * }
5095
+ * ```
4799
5096
  */
4800
5097
  isEnabled(): boolean;
4801
5098
  /**
4802
5099
  * Returns whether the tracker.js script has been loaded and the
4803
- * `window.LynkowAnalytics` global is available.
5100
+ * `window.LynkowAnalytics` global is available. Always `false` on the
5101
+ * server.
5102
+ *
5103
+ * @returns `true` if the tracker is fully loaded and ready to accept
5104
+ * events, `false` otherwise.
5105
+ * @throws Never throws.
4804
5106
  *
4805
- * @returns `true` if the tracker is fully initialized and ready to track events
5107
+ * @example
5108
+ * ```typescript
5109
+ * if (lynkow.analytics.isInitialized()) {
5110
+ * lynkow.analytics.trackEvent({ type: 'cta_click' })
5111
+ * }
5112
+ * ```
4806
5113
  */
4807
5114
  isInitialized(): boolean;
4808
5115
  /**
4809
- * Returns the underlying `window.LynkowAnalytics` global object for advanced
4810
- * usage when you need direct access to the tracker API beyond what this
4811
- * service wraps.
5116
+ * Return the underlying `window.LynkowAnalytics` global for advanced
5117
+ * use cases that need direct access to the tracker's lower-level API
5118
+ * (e.g. calling `init` again with different options, or invoking
5119
+ * undocumented tracker internals).
5120
+ *
5121
+ * @returns The `LynkowAnalyticsGlobal` with `init()` and `track()`
5122
+ * methods, or `undefined` if running on the server or the tracker
5123
+ * script has not loaded yet.
5124
+ * @throws Never throws.
4812
5125
  *
4813
- * @returns The `LynkowAnalyticsGlobal` object with `init()` and `track()` methods,
4814
- * or `undefined` if running on the server or the tracker is not loaded
5126
+ * @example
5127
+ * ```typescript
5128
+ * const tracker = lynkow.analytics.getTracker()
5129
+ * tracker?.track({ custom: 'payload' })
5130
+ * ```
4815
5131
  */
4816
5132
  getTracker(): LynkowAnalyticsGlobal | undefined;
4817
5133
  /**
@@ -4873,9 +5189,25 @@ type EventName = keyof LynkowEvents;
4873
5189
  */
4874
5190
  type EventListener<T> = (data: T) => void;
4875
5191
  /**
4876
- * Create a new event emitter instance.
4877
- * Returns an object with `on`, `off`, `emit`, `once`, and `removeAllListeners` methods.
4878
- * Each SDK client creates its own emitter; events do not leak between client instances.
5192
+ * Create a new event emitter instance backing the `lynkow.on/off/once`
5193
+ * API of the client. Each SDK client creates its own emitter, so events
5194
+ * do not leak between client instances (e.g. multi-tenant server rendering).
5195
+ *
5196
+ * @returns An {@link EventEmitter} object exposing `on`, `off`, `emit`,
5197
+ * `once`, and `removeAllListeners`. `on()` and `once()` return an
5198
+ * unsubscribe closure for convenience.
5199
+ *
5200
+ * @example
5201
+ * ```typescript
5202
+ * import { createEventEmitter } from 'lynkow'
5203
+ *
5204
+ * const events = createEventEmitter()
5205
+ * const unsubscribe = events.on('locale-changed', (locale) => {
5206
+ * refetchContent(locale)
5207
+ * })
5208
+ * events.emit('locale-changed', 'fr')
5209
+ * unsubscribe()
5210
+ * ```
4879
5211
  */
4880
5212
  declare function createEventEmitter(): {
4881
5213
  on: <K extends EventName>(event: K, listener: EventListener<LynkowEvents[K]>) => () => void;
@@ -4896,16 +5228,38 @@ type EventEmitter = ReturnType<typeof createEventEmitter>;
4896
5228
  */
4897
5229
 
4898
5230
  /**
4899
- * Consent categories
5231
+ * User consent state for each cookie category Lynkow manages. Used as
5232
+ * input to {@link ConsentService.setCategories} and emitted as the payload
5233
+ * of the `'consent-changed'` client event.
5234
+ *
5235
+ * A category set to `false` means the corresponding scripts (from the
5236
+ * site's cookie configuration) MUST NOT be loaded; a category set to
5237
+ * `true` authorises them.
4900
5238
  */
4901
5239
  interface ConsentCategories {
4902
- /** Always true, not modifiable */
5240
+ /**
5241
+ * Strictly necessary cookies (session, CSRF). Always `true`: users
5242
+ * cannot opt out because the site would be non-functional without them.
5243
+ * Included in the type so consent payloads remain uniform.
5244
+ */
4903
5245
  necessary: boolean;
4904
- /** Analytics cookies */
5246
+ /**
5247
+ * Consent to first-party and third-party analytics (e.g. the Lynkow
5248
+ * tracker, Google Analytics). When `false`, the analytics service
5249
+ * automatically becomes a no-op.
5250
+ */
4905
5251
  analytics: boolean;
4906
- /** Marketing cookies */
5252
+ /**
5253
+ * Consent to marketing and advertising cookies (ad networks,
5254
+ * retargeting). Required before loading scripts classified as
5255
+ * `marketing` in the site's cookie config.
5256
+ */
4907
5257
  marketing: boolean;
4908
- /** Preference cookies */
5258
+ /**
5259
+ * Consent to personalization and preference cookies (theme, language,
5260
+ * non-essential UI state). Required before loading scripts classified
5261
+ * as `preferences` in the site's cookie config.
5262
+ */
4909
5263
  preferences: boolean;
4910
5264
  }
4911
5265
  /**
@@ -4954,8 +5308,19 @@ declare class ConsentService {
4954
5308
  * Works on both server and browser.
4955
5309
  *
4956
5310
  * @returns A `CookieConfig` object with banner settings, categories, texts,
4957
- * theming options, and third-party script definitions
4958
- * @throws {Error} If the API request fails (non-2xx response)
5311
+ * theming options, and third-party script definitions.
5312
+ * @throws {Error} If the API request fails (non-2xx response). The SDK
5313
+ * does not wrap this in a {@link LynkowError} for this endpoint,
5314
+ * since consent config is fetched via a raw `fetch` call rather than
5315
+ * the shared request pipeline.
5316
+ *
5317
+ * @example
5318
+ * ```typescript
5319
+ * const config = await lynkow.consent.getConfig()
5320
+ * if (config.enabled) {
5321
+ * console.log('Categories:', config.categories.map((c) => c.id))
5322
+ * }
5323
+ * ```
4959
5324
  */
4960
5325
  getConfig(): Promise<CookieConfig>;
4961
5326
  /**
@@ -4968,7 +5333,19 @@ declare class ConsentService {
4968
5333
  * (e.g. `{ necessary: true, analytics: true, marketing: false }`)
4969
5334
  * @param action - Optional explicit action type. If omitted, the action is inferred
4970
5335
  * from the preferences (all true = `'accept_all'`, all false = `'reject_all'`,
4971
- * mixed = `'customize'`)
5336
+ * mixed = `'customize'`). `'withdraw'` must be passed explicitly.
5337
+ * @returns A promise that resolves once the POST has completed or
5338
+ * been suppressed on error. Never rejects.
5339
+ * @throws Never throws. Network or server errors are caught and silently
5340
+ * discarded so the consent UI flow is never interrupted.
5341
+ *
5342
+ * @example
5343
+ * ```typescript
5344
+ * await lynkow.consent.logConsent(
5345
+ * { necessary: true, analytics: true, marketing: false },
5346
+ * 'customize'
5347
+ * )
5348
+ * ```
4972
5349
  */
4973
5350
  logConsent(preferences: CookiePreferences, action?: 'accept_all' | 'reject_all' | 'customize' | 'withdraw'): Promise<void>;
4974
5351
  private getOrCreateVisitorId;
@@ -4984,6 +5361,9 @@ declare class ConsentService {
4984
5361
  * When theme is `'auto'`, a MutationObserver watches for site theme changes
4985
5362
  * and updates the banner colors in real-time.
4986
5363
  *
5364
+ * @returns void
5365
+ * @throws Never throws. Config-fetch rejections are caught internally.
5366
+ *
4987
5367
  * @example
4988
5368
  * ```typescript
4989
5369
  * // Show the consent banner on page load (skips if already consented)
@@ -4993,15 +5373,37 @@ declare class ConsentService {
4993
5373
  */
4994
5374
  show(): void;
4995
5375
  /**
4996
- * Hides and removes the consent banner from the DOM. Does not affect stored
4997
- * consent preferences. No-op on server or if the banner is not shown.
5376
+ * Hide and remove the consent banner from the DOM. Does not affect
5377
+ * stored consent preferences (the user will not be re-prompted on the
5378
+ * next page load if they already chose). No-op on server or if the
5379
+ * banner is not currently shown.
5380
+ *
5381
+ * @returns void
5382
+ * @throws Never throws.
5383
+ *
5384
+ * @example
5385
+ * ```typescript
5386
+ * // Close the banner after the user clicked "Accept all" via custom UI:
5387
+ * lynkow.consent.hide()
5388
+ * ```
4998
5389
  */
4999
5390
  hide(): void;
5000
5391
  /**
5001
- * Opens the preferences modal, allowing the user to toggle individual
5002
- * consent categories (analytics, marketing, preferences). The necessary
5003
- * category is always checked and disabled. Pre-populates checkboxes with
5004
- * the user's current consent state. No-op on server.
5392
+ * Open the preferences modal so the user can toggle individual consent
5393
+ * categories (analytics, marketing, preferences). The `necessary`
5394
+ * category is always checked and disabled. Pre-populates checkboxes
5395
+ * with the user's current consent state. No-op on server or if the
5396
+ * modal is already mounted.
5397
+ *
5398
+ * @returns void
5399
+ * @throws Never throws.
5400
+ *
5401
+ * @example
5402
+ * ```tsx
5403
+ * <button onClick={() => lynkow.consent.showPreferences()}>
5404
+ * Cookie settings
5405
+ * </button>
5406
+ * ```
5005
5407
  */
5006
5408
  showPreferences(): void;
5007
5409
  /**
@@ -5094,6 +5496,9 @@ declare class ConsentService {
5094
5496
  * banner. Useful for providing a "manage cookies" link that lets users
5095
5497
  * change their preferences. No-op on server.
5096
5498
  *
5499
+ * @returns void
5500
+ * @throws Never throws. localStorage errors are silently ignored.
5501
+ *
5097
5502
  * @example
5098
5503
  * ```typescript
5099
5504
  * // Add a "Manage cookies" link in the footer to let users re-choose
@@ -5122,10 +5527,22 @@ declare class ConsentService {
5122
5527
  private attachBannerEvents;
5123
5528
  private attachPreferencesEvents;
5124
5529
  /**
5125
- * Cleans up all consent UI resources: removes the banner and preferences
5126
- * modal from the DOM, removes injected third-party scripts, and stops
5127
- * the theme observer. Call this when unmounting the SDK (e.g. in a
5128
- * React useEffect cleanup). No-op on server.
5530
+ * Clean up every DOM resource this service owns: removes the banner
5531
+ * and preferences modal, removes injected third-party scripts, and
5532
+ * stops the theme observer. Call when unmounting the SDK (e.g. inside
5533
+ * a React `useEffect` cleanup) so the page can be navigated without
5534
+ * leaking listeners. No-op on server.
5535
+ *
5536
+ * @returns void
5537
+ * @throws Never throws.
5538
+ *
5539
+ * @example
5540
+ * ```tsx
5541
+ * useEffect(() => {
5542
+ * lynkow.consent.show()
5543
+ * return () => lynkow.consent.destroy()
5544
+ * }, [])
5545
+ * ```
5129
5546
  */
5130
5547
  destroy(): void;
5131
5548
  }
@@ -5186,21 +5603,50 @@ declare class BrandingService extends BaseService {
5186
5603
  */
5187
5604
  inject(): Promise<void>;
5188
5605
  /**
5189
- * Removes the branding badge and its associated styles from the DOM,
5190
- * and stops the theme observer. No-op on server or if the badge is
5191
- * not currently injected.
5606
+ * Remove the branding badge and its associated `<style>` block from
5607
+ * the DOM and stop the theme observer. No-op on server or if the
5608
+ * badge is not currently injected.
5609
+ *
5610
+ * @returns void
5611
+ * @throws Never throws.
5612
+ *
5613
+ * @example
5614
+ * ```typescript
5615
+ * lynkow.branding.remove()
5616
+ * ```
5192
5617
  */
5193
5618
  remove(): void;
5194
5619
  /**
5195
- * Checks whether the branding badge is currently present in the DOM.
5620
+ * Check whether the branding badge is currently mounted in the DOM.
5621
+ * Useful for conditional logic (e.g. show a custom "Powered by" only
5622
+ * when the badge is not already rendered).
5623
+ *
5624
+ * @returns `true` if the badge container element exists in the
5625
+ * document, `false` otherwise. Always returns `false` on the server.
5626
+ * @throws Never throws.
5196
5627
  *
5197
- * @returns `true` if the badge container element exists in the document,
5198
- * `false` otherwise. Always returns `false` on the server.
5628
+ * @example
5629
+ * ```typescript
5630
+ * if (!lynkow.branding.isVisible()) {
5631
+ * // Render our own attribution
5632
+ * }
5633
+ * ```
5199
5634
  */
5200
5635
  isVisible(): boolean;
5201
5636
  /**
5202
- * Alias for `remove()`. Cleans up the badge, styles, and theme observer.
5203
- * Use this in cleanup callbacks (e.g. React useEffect cleanup).
5637
+ * Alias for {@link remove}. Cleans up the badge, styles, and theme
5638
+ * observer. Matches the `destroy()` naming used on other lifecycle
5639
+ * services so cleanup code can stay uniform.
5640
+ *
5641
+ * @returns void
5642
+ * @throws Never throws.
5643
+ *
5644
+ * @example
5645
+ * ```tsx
5646
+ * useEffect(() => {
5647
+ * return () => lynkow.branding.destroy()
5648
+ * }, [])
5649
+ * ```
5204
5650
  */
5205
5651
  destroy(): void;
5206
5652
  }
@@ -5284,17 +5730,40 @@ declare class EnhancementsService {
5284
5730
  */
5285
5731
  init(): void;
5286
5732
  /**
5287
- * Checks whether the enhancements service has been initialized.
5733
+ * Check whether the enhancements service has been initialized for the
5734
+ * current page. Returns `false` on the server and after a call to
5735
+ * {@link destroy} (until `init()` is invoked again).
5736
+ *
5737
+ * @returns `true` if `init()` has been called successfully, `false`
5738
+ * otherwise.
5739
+ * @throws Never throws.
5288
5740
  *
5289
- * @returns `true` if `init()` has been called successfully, `false` otherwise
5741
+ * @example
5742
+ * ```typescript
5743
+ * if (!lynkow.enhancements.isInitialized()) {
5744
+ * lynkow.enhancements.init()
5745
+ * }
5746
+ * ```
5290
5747
  */
5291
5748
  isInitialized(): boolean;
5292
5749
  /**
5293
- * Cleans up all enhancement resources: disconnects the MutationObserver,
5294
- * removes the widget resize listener, cancels any pending animation frame,
5295
- * removes injected styles and cloned scripts from `<head>`, and resets
5296
- * the initialized state. After calling `destroy()`, you can re-initialize
5297
- * by calling `init()` again. No-op on server.
5750
+ * Clean up every resource the enhancements service owns: disconnect the
5751
+ * MutationObserver, remove the widget resize listener, cancel any
5752
+ * pending animation frame, remove injected styles and cloned scripts
5753
+ * from `<head>`, and reset the initialized state. Safe to call
5754
+ * repeatedly; subsequent calls are no-ops. After `destroy()` you can
5755
+ * re-attach by calling `init()` again. No-op on server.
5756
+ *
5757
+ * @returns void
5758
+ * @throws Never throws.
5759
+ *
5760
+ * @example
5761
+ * ```tsx
5762
+ * useEffect(() => {
5763
+ * lynkow.enhancements.init()
5764
+ * return () => lynkow.enhancements.destroy()
5765
+ * }, [])
5766
+ * ```
5298
5767
  */
5299
5768
  destroy(): void;
5300
5769
  }
@@ -5303,32 +5772,74 @@ declare class EnhancementsService {
5303
5772
  * Options for building srcset URLs
5304
5773
  */
5305
5774
  interface SrcsetOptions {
5306
- /** Image widths to include in srcset (default: [400, 800, 1200, 1920]) */
5775
+ /**
5776
+ * Pixel widths to generate in the srcset, in ascending order. Each
5777
+ * width becomes a `Nw` entry in the returned string. Defaults to
5778
+ * `[400, 800, 1200, 1920]` to cover phone, tablet, desktop, large
5779
+ * desktop. Supply a custom list when you know your layout's
5780
+ * breakpoints to avoid bandwidth waste.
5781
+ */
5307
5782
  widths?: number[];
5308
- /** Resize fit mode (default: 'scale-down') */
5783
+ /**
5784
+ * Cloudflare resize fit mode. `'scale-down'` (default) preserves
5785
+ * aspect ratio and never upscales; `'cover'` fills the box and crops;
5786
+ * `'contain'` fits inside the box with letterboxing; `'crop'` hard
5787
+ * crops to the exact dimensions. Must pair with `gravity` for
5788
+ * `'cover'` / `'crop'` when the subject is not centered.
5789
+ */
5309
5790
  fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
5310
- /** Image quality 1-100 (default: 80) */
5791
+ /**
5792
+ * JPEG / WebP quality on a 1-100 scale. Higher values produce larger
5793
+ * files. Default `80` strikes a good balance for photography; drop to
5794
+ * 60-70 for hero images on slow connections.
5795
+ */
5311
5796
  quality?: number;
5312
- /** Focal point for crop (e.g., '0.5x0.3') */
5797
+ /**
5798
+ * Focal point for `fit: 'cover' | 'crop'` as an `XxY` pair of
5799
+ * fractions (e.g. `'0.5x0.3'` keeps the horizontal center but biases
5800
+ * towards the upper third). Omit to center the crop.
5801
+ */
5313
5802
  gravity?: string;
5314
5803
  }
5315
5804
  /**
5316
- * Options for building a single transformed URL
5805
+ * Options for building a single transformed URL. Matches the Cloudflare
5806
+ * Image Transformations query parameters; omit any value to let the CDN
5807
+ * choose a sensible default.
5317
5808
  */
5318
5809
  interface TransformOptions {
5319
- /** Target width in pixels */
5810
+ /**
5811
+ * Target width in pixels. When set alone, height is derived from the
5812
+ * image's aspect ratio (unless `fit` requires both).
5813
+ */
5320
5814
  w?: number;
5321
- /** Target height in pixels */
5815
+ /**
5816
+ * Target height in pixels. When set alone, width is derived from the
5817
+ * image's aspect ratio (unless `fit` requires both).
5818
+ */
5322
5819
  h?: number;
5323
- /** Resize fit mode */
5820
+ /**
5821
+ * Resize fit mode. See {@link SrcsetOptions.fit} for semantics; the
5822
+ * default here is `'scale-down'` to avoid accidental upscaling.
5823
+ */
5324
5824
  fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
5325
5825
  /** Image quality 1-100 (default: 80) */
5326
5826
  quality?: number;
5327
- /** Output format (default: 'auto') */
5827
+ /**
5828
+ * Output image format. `'auto'` (default) lets the CDN negotiate
5829
+ * based on `Accept` (WebP on modern browsers, AVIF on the newest).
5830
+ * Force a specific format only when the consumer is known.
5831
+ */
5328
5832
  format?: 'auto' | 'webp' | 'avif' | 'jpeg';
5329
- /** Focal point for crop */
5833
+ /**
5834
+ * Focal point for `fit: 'cover' | 'crop'` as an `XxY` pair of
5835
+ * fractions (see {@link SrcsetOptions.gravity}). Omit to center.
5836
+ */
5330
5837
  gravity?: string;
5331
- /** Device Pixel Ratio 1-4 */
5838
+ /**
5839
+ * Device Pixel Ratio multiplier on a `1`-`4` scale. Multiplies the
5840
+ * rendered width/height so a 400px box renders sharp at 2x on
5841
+ * Retina. Prefer using a `srcset` over a hard-coded DPR.
5842
+ */
5332
5843
  dpr?: number;
5333
5844
  }
5334
5845
  /**
@@ -5852,6 +6363,11 @@ declare function onSiteThemeChange(callback: (theme: 'dark' | 'light') => void):
5852
6363
  * conditional branches.
5853
6364
  * @returns Serialized `<script>` tag string. Empty string when there are
5854
6365
  * no nodes to render.
6366
+ * @throws Never throws. The function is designed for server components
6367
+ * and is safe to call with `undefined` or malformed payloads
6368
+ * (values that cannot be `JSON.stringify`-ed, e.g. circular
6369
+ * references, will throw from the underlying `JSON.stringify`
6370
+ * call - caller's responsibility, not a library behaviour).
5855
6371
  *
5856
6372
  * @example
5857
6373
  * ```tsx