lynkow 3.6.2 → 3.7.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
@@ -9,6 +9,7 @@ Official TypeScript SDK for [Lynkow](https://lynkow.com) Headless CMS.
9
9
  - **Framework-agnostic** - Works with Next.js, Nuxt, Astro, SvelteKit, etc.
10
10
  - **Tree-shakeable** - Only import what you need
11
11
  - **Isomorphic** - Works on both browser and server (Node.js, Deno, Bun)
12
+ - **Image Transformations** - Cloudflare CDN srcset and responsive image helpers
12
13
  - **Built-in Analytics** - Page views, events, and funnel tracking
13
14
  - **Cookie Consent** - GDPR-compliant consent banner with preferences
14
15
  - **Spam protection** - Built-in honeypot fields for form submissions
@@ -129,6 +130,7 @@ The SDK is isomorphic and works on both browser and server environments. Some fe
129
130
  | Feature | Browser | Server |
130
131
  |---------|---------|--------|
131
132
  | Contents, Categories, Pages... | ✅ | ✅ |
133
+ | Media (image transformations) | ✅ | ✅ |
132
134
  | Forms, Reviews | ✅ | ✅ |
133
135
  | Analytics tracking | ✅ | ❌ (no-op) |
134
136
  | Consent banner | ✅ | ❌ (no-op) |
@@ -327,6 +329,72 @@ if (redirect) {
327
329
  }
328
330
  ```
329
331
 
332
+ ### Media (Image Transformations)
333
+
334
+ Build optimized image URLs using Cloudflare Image Transformations.
335
+
336
+ ```typescript
337
+ // Build a srcset for responsive images
338
+ const srcset = lynkow.media.srcset(content.featuredImage)
339
+ // => "https://cdn.../cdn-cgi/image/w=400,.../photo.jpg 400w, ...800w, ...1200w, ...1920w"
340
+
341
+ // Custom widths and options
342
+ const srcset = lynkow.media.srcset(content.featuredImage, {
343
+ widths: [320, 640, 960],
344
+ fit: 'cover',
345
+ quality: 85,
346
+ gravity: '0.5x0.3', // focal point
347
+ })
348
+
349
+ // Build a single transformed URL
350
+ const url = lynkow.media.transform(content.featuredImage, {
351
+ w: 800,
352
+ h: 600,
353
+ fit: 'cover',
354
+ format: 'webp',
355
+ quality: 85,
356
+ })
357
+ ```
358
+
359
+ #### Using with `<img>` tags
360
+
361
+ ```jsx
362
+ // Simple: use pre-computed variants from the API
363
+ <img
364
+ src={content.featuredImageVariants?.card || content.featuredImage}
365
+ alt={content.title}
366
+ />
367
+
368
+ // Advanced: build srcset for fully responsive images
369
+ <img
370
+ src={content.featuredImage}
371
+ srcSet={lynkow.media.srcset(content.featuredImage)}
372
+ sizes="(max-width: 768px) 100vw, 800px"
373
+ alt={content.title}
374
+ />
375
+ ```
376
+
377
+ #### API Response Variants
378
+
379
+ The API automatically includes pre-computed image variants:
380
+
381
+ | Field | Available on | Presets |
382
+ |-------|-------------|---------|
383
+ | `featuredImageVariants` | Content | `thumbnail`, `card`, `hero`, `og` |
384
+ | `ogImageVariants` | Content | `og` |
385
+ | `imageVariants` | Category | `thumbnail`, `card`, `og` |
386
+
387
+ ```typescript
388
+ // Use variants directly (no SDK helper needed)
389
+ const thumbnailUrl = content.featuredImageVariants?.thumbnail
390
+ const heroUrl = content.featuredImageVariants?.hero
391
+
392
+ // Category images
393
+ const categoryImg = category.imageVariants?.card
394
+ ```
395
+
396
+ > **Note**: Body HTML (`content.body`) already includes `srcset`, `loading="lazy"`, and `decoding="async"` on images automatically. No client-side processing needed.
397
+
330
398
  ## Analytics (Browser-only)
331
399
 
332
400
  The SDK includes built-in analytics that loads the Lynkow tracker automatically.
@@ -961,6 +1029,11 @@ import type {
961
1029
  Review,
962
1030
  Tag,
963
1031
 
1032
+ // Images
1033
+ ImageVariants,
1034
+ SrcsetOptions,
1035
+ TransformOptions,
1036
+
964
1037
  // Config
965
1038
  LynkowConfig,
966
1039
  ClientConfig,
@@ -1018,6 +1091,12 @@ import type {
1018
1091
  - **Site config alignment**: API now returns both flat fields (`defaultLocale`, `enabledLocales`) and rich `i18n` object
1019
1092
  - **Next.js App Router documentation**: Comprehensive guide for Server Components and cookie-based i18n
1020
1093
 
1094
+ ### New in v3.7
1095
+
1096
+ - **Image Transformations**: New `lynkow.media` service with `srcset()` and `transform()` helpers for Cloudflare Image Transformations
1097
+ - **ImageVariants type**: API responses now include pre-computed `featuredImageVariants`, `ogImageVariants`, and `imageVariants` fields
1098
+ - **Body HTML srcset**: Content body images automatically include `srcset`, `loading="lazy"`, and `decoding="async"` attributes
1099
+
1021
1100
  ### Upgrade Steps
1022
1101
 
1023
1102
  ```typescript
package/dist/index.d.mts CHANGED
@@ -708,6 +708,29 @@ interface LynkowClient {
708
708
  paths: PathsService;
709
709
  }
710
710
 
711
+ /**
712
+ * Image transformation variant URLs generated by Cloudflare Image Transformations.
713
+ * Each key corresponds to a preset name.
714
+ */
715
+ interface ImageVariants {
716
+ /** 400x300, cover, sharpen (list thumbnails) */
717
+ thumbnail?: string;
718
+ /** 600x400, cover (card layouts) */
719
+ card?: string;
720
+ /** 1200w, scale-down (article body) */
721
+ content?: string;
722
+ /** 960w, scale-down (medium displays) */
723
+ medium?: string;
724
+ /** 1920w, scale-down (hero banners) */
725
+ hero?: string;
726
+ /** 1200x630, cover (Open Graph / social sharing) */
727
+ og?: string;
728
+ /** 128x128, cover + face gravity (avatars) */
729
+ avatar?: string;
730
+ /** 2560w, scale-down (full resolution) */
731
+ full?: string;
732
+ }
733
+
711
734
  /**
712
735
  * Content category
713
736
  */
@@ -733,6 +756,8 @@ interface CategoryWithCount extends Category {
733
756
  image: string | null;
734
757
  /** Number of contents in this category */
735
758
  contentCount: number;
759
+ /** CDN image variants */
760
+ imageVariants?: ImageVariants;
736
761
  }
737
762
  /**
738
763
  * Detailed category (with all info)
@@ -902,6 +927,7 @@ interface ContentSummary {
902
927
  path: string;
903
928
  excerpt: string | null;
904
929
  featuredImage: string | null;
930
+ featuredImageVariants?: ImageVariants;
905
931
  locale: string;
906
932
  publishedAt: string;
907
933
  createdAt: string;
@@ -926,6 +952,8 @@ interface Content extends ContentSummary {
926
952
  canonicalUrl: string | null;
927
953
  /** Open Graph image */
928
954
  ogImage: string | null;
955
+ /** Open Graph image CDN variants */
956
+ ogImageVariants?: ImageVariants;
929
957
  /** JSON-LD structured data */
930
958
  structuredData: StructuredData | null;
931
959
  /** Article author */
@@ -1984,6 +2012,82 @@ declare class EnhancementsService {
1984
2012
  destroy(): void;
1985
2013
  }
1986
2014
 
2015
+ /**
2016
+ * Options for building srcset URLs
2017
+ */
2018
+ interface SrcsetOptions {
2019
+ /** Image widths to include in srcset (default: [400, 800, 1200, 1920]) */
2020
+ widths?: number[];
2021
+ /** Resize fit mode (default: 'scale-down') */
2022
+ fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
2023
+ /** Image quality 1-100 (default: 80) */
2024
+ quality?: number;
2025
+ /** Focal point for crop (e.g., '0.5x0.3') */
2026
+ gravity?: string;
2027
+ }
2028
+ /**
2029
+ * Options for building a single transformed URL
2030
+ */
2031
+ interface TransformOptions {
2032
+ /** Target width in pixels */
2033
+ w?: number;
2034
+ /** Target height in pixels */
2035
+ h?: number;
2036
+ /** Resize fit mode */
2037
+ fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
2038
+ /** Image quality 1-100 (default: 80) */
2039
+ quality?: number;
2040
+ /** Output format (default: 'auto') */
2041
+ format?: 'auto' | 'webp' | 'avif' | 'jpeg';
2042
+ /** Focal point for crop */
2043
+ gravity?: string;
2044
+ /** Device Pixel Ratio 1-4 */
2045
+ dpr?: number;
2046
+ }
2047
+ /**
2048
+ * Service for working with Cloudflare Image Transformation URLs.
2049
+ *
2050
+ * This service helps build optimized image URLs client-side.
2051
+ * It works with any image URL from the Lynkow API.
2052
+ *
2053
+ * @example
2054
+ * ```typescript
2055
+ * const lynkow = createClient({ siteId: '...' })
2056
+ *
2057
+ * // Build srcset for responsive images
2058
+ * const srcset = lynkow.media.srcset(content.featuredImage)
2059
+ *
2060
+ * // Build a single transformed URL
2061
+ * const url = lynkow.media.transform(content.featuredImage, { w: 800 })
2062
+ * ```
2063
+ */
2064
+ declare class MediaHelperService {
2065
+ /**
2066
+ * Generates an HTML `srcset` attribute value from an image URL.
2067
+ *
2068
+ * @param imageUrl - Original image URL from the Lynkow API
2069
+ * @param options - Srcset configuration
2070
+ * @returns srcset string ready for use in an `<img>` tag, or empty string if URL is invalid
2071
+ */
2072
+ srcset(imageUrl: string | null | undefined, options?: SrcsetOptions): string;
2073
+ /**
2074
+ * Generates a single transformed image URL.
2075
+ *
2076
+ * @param imageUrl - Original image URL from the Lynkow API
2077
+ * @param options - Transformation options
2078
+ * @returns Transformed URL, or the original URL if transformation is not possible
2079
+ */
2080
+ transform(imageUrl: string | null | undefined, options?: TransformOptions): string;
2081
+ /**
2082
+ * Extracts the CDN base and relative path from a Lynkow image URL.
2083
+ *
2084
+ * Handles both original URLs and already-transformed URLs.
2085
+ *
2086
+ * @returns Parsed URL parts, or null if the URL is not a valid Lynkow CDN URL
2087
+ */
2088
+ private parseImageUrl;
2089
+ }
2090
+
1987
2091
  /**
1988
2092
  * Lynkow SDK Client
1989
2093
  * Main entry point for the SDK
@@ -2064,6 +2168,11 @@ interface Client extends LynkowClient {
2064
2168
  * Content enhancements service (code copy, etc.)
2065
2169
  */
2066
2170
  enhancements: EnhancementsService;
2171
+ /**
2172
+ * Image transformation helpers.
2173
+ * Use these to build optimized image URLs for responsive images.
2174
+ */
2175
+ readonly media: MediaHelperService;
2067
2176
  }
2068
2177
  /**
2069
2178
  * Creates a Lynkow client instance (SDK v3)
@@ -2213,4 +2322,4 @@ declare function browserOnly<T>(fn: () => T, fallback: T): T;
2213
2322
  */
2214
2323
  declare function browserOnlyAsync<T>(fn: () => Promise<T>, fallback: T): Promise<T>;
2215
2324
 
2216
- export { type Alternate, type ApiErrorDetail, type Author, type BaseRequestOptions, type CategoriesListResponse, type Category, type CategoryDetail, type CategoryDetailResponse, type CategoryOptions, type CategoryResolveResponse, type CategoryTreeNode, type CategoryTreeResponse, type CategoryWithCount, type Client, type ClientConfig, type ConsentCategories, type ConsentLogResponse, type Content, type ContentBody, type ContentResolveResponse, type ContentSummary, type ContentsFilters, type ContentsListResponse, type CookieCategory, type CookieConfig, type CookiePreferences, type CookieTexts, EnhancementsService, type ErrorCode, type EventData, type EventName, type Form, type FormField, type FormFieldOption, type FormFieldType, type FormFieldValidation, type FormSettings, type FormSubmitData, type FormSubmitResponse, type FunnelStepData, type GlobalBlock, type GlobalBlockResponse, type LegalDocument, type LynkowClient, type LynkowConfig, LynkowError, type LynkowEvents, type Page, type PageSeo, type PageSummary, type PagesListResponse, type PageviewData, type PaginatedResponse, type PaginationMeta, type PaginationOptions, type Path, type PathsListResponse, type Redirect, type ResolveResponse, type Review, type ReviewResponse, type ReviewSettings, type ReviewSubmitData, type ReviewSubmitResponse, type ReviewsFilters, type ReviewsListResponse, type SiteConfig, type SiteConfigResponse, type SortOptions, type SubmitOptions, type Tag, type TagsListResponse, type TipTapMark, type TipTapNode, browserOnly, browserOnlyAsync, createClient, createLynkowClient, isBrowser, isCategoryResolve, isContentResolve, isLynkowError, isServer };
2325
+ export { type Alternate, type ApiErrorDetail, type Author, type BaseRequestOptions, type CategoriesListResponse, type Category, type CategoryDetail, type CategoryDetailResponse, type CategoryOptions, type CategoryResolveResponse, type CategoryTreeNode, type CategoryTreeResponse, type CategoryWithCount, type Client, type ClientConfig, type ConsentCategories, type ConsentLogResponse, type Content, type ContentBody, type ContentResolveResponse, type ContentSummary, type ContentsFilters, type ContentsListResponse, type CookieCategory, type CookieConfig, type CookiePreferences, type CookieTexts, EnhancementsService, type ErrorCode, type EventData, type EventName, type Form, type FormField, type FormFieldOption, type FormFieldType, type FormFieldValidation, type FormSettings, type FormSubmitData, type FormSubmitResponse, type FunnelStepData, type GlobalBlock, type GlobalBlockResponse, type ImageVariants, type LegalDocument, type LynkowClient, type LynkowConfig, LynkowError, type LynkowEvents, MediaHelperService, type Page, type PageSeo, type PageSummary, type PagesListResponse, type PageviewData, type PaginatedResponse, type PaginationMeta, type PaginationOptions, type Path, type PathsListResponse, type Redirect, type ResolveResponse, type Review, type ReviewResponse, type ReviewSettings, type ReviewSubmitData, type ReviewSubmitResponse, type ReviewsFilters, type ReviewsListResponse, type SiteConfig, type SiteConfigResponse, type SortOptions, type SrcsetOptions, type SubmitOptions, type Tag, type TagsListResponse, type TipTapMark, type TipTapNode, type TransformOptions, browserOnly, browserOnlyAsync, createClient, createLynkowClient, isBrowser, isCategoryResolve, isContentResolve, isLynkowError, isServer };
package/dist/index.d.ts CHANGED
@@ -708,6 +708,29 @@ interface LynkowClient {
708
708
  paths: PathsService;
709
709
  }
710
710
 
711
+ /**
712
+ * Image transformation variant URLs generated by Cloudflare Image Transformations.
713
+ * Each key corresponds to a preset name.
714
+ */
715
+ interface ImageVariants {
716
+ /** 400x300, cover, sharpen (list thumbnails) */
717
+ thumbnail?: string;
718
+ /** 600x400, cover (card layouts) */
719
+ card?: string;
720
+ /** 1200w, scale-down (article body) */
721
+ content?: string;
722
+ /** 960w, scale-down (medium displays) */
723
+ medium?: string;
724
+ /** 1920w, scale-down (hero banners) */
725
+ hero?: string;
726
+ /** 1200x630, cover (Open Graph / social sharing) */
727
+ og?: string;
728
+ /** 128x128, cover + face gravity (avatars) */
729
+ avatar?: string;
730
+ /** 2560w, scale-down (full resolution) */
731
+ full?: string;
732
+ }
733
+
711
734
  /**
712
735
  * Content category
713
736
  */
@@ -733,6 +756,8 @@ interface CategoryWithCount extends Category {
733
756
  image: string | null;
734
757
  /** Number of contents in this category */
735
758
  contentCount: number;
759
+ /** CDN image variants */
760
+ imageVariants?: ImageVariants;
736
761
  }
737
762
  /**
738
763
  * Detailed category (with all info)
@@ -902,6 +927,7 @@ interface ContentSummary {
902
927
  path: string;
903
928
  excerpt: string | null;
904
929
  featuredImage: string | null;
930
+ featuredImageVariants?: ImageVariants;
905
931
  locale: string;
906
932
  publishedAt: string;
907
933
  createdAt: string;
@@ -926,6 +952,8 @@ interface Content extends ContentSummary {
926
952
  canonicalUrl: string | null;
927
953
  /** Open Graph image */
928
954
  ogImage: string | null;
955
+ /** Open Graph image CDN variants */
956
+ ogImageVariants?: ImageVariants;
929
957
  /** JSON-LD structured data */
930
958
  structuredData: StructuredData | null;
931
959
  /** Article author */
@@ -1984,6 +2012,82 @@ declare class EnhancementsService {
1984
2012
  destroy(): void;
1985
2013
  }
1986
2014
 
2015
+ /**
2016
+ * Options for building srcset URLs
2017
+ */
2018
+ interface SrcsetOptions {
2019
+ /** Image widths to include in srcset (default: [400, 800, 1200, 1920]) */
2020
+ widths?: number[];
2021
+ /** Resize fit mode (default: 'scale-down') */
2022
+ fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
2023
+ /** Image quality 1-100 (default: 80) */
2024
+ quality?: number;
2025
+ /** Focal point for crop (e.g., '0.5x0.3') */
2026
+ gravity?: string;
2027
+ }
2028
+ /**
2029
+ * Options for building a single transformed URL
2030
+ */
2031
+ interface TransformOptions {
2032
+ /** Target width in pixels */
2033
+ w?: number;
2034
+ /** Target height in pixels */
2035
+ h?: number;
2036
+ /** Resize fit mode */
2037
+ fit?: 'cover' | 'contain' | 'scale-down' | 'crop';
2038
+ /** Image quality 1-100 (default: 80) */
2039
+ quality?: number;
2040
+ /** Output format (default: 'auto') */
2041
+ format?: 'auto' | 'webp' | 'avif' | 'jpeg';
2042
+ /** Focal point for crop */
2043
+ gravity?: string;
2044
+ /** Device Pixel Ratio 1-4 */
2045
+ dpr?: number;
2046
+ }
2047
+ /**
2048
+ * Service for working with Cloudflare Image Transformation URLs.
2049
+ *
2050
+ * This service helps build optimized image URLs client-side.
2051
+ * It works with any image URL from the Lynkow API.
2052
+ *
2053
+ * @example
2054
+ * ```typescript
2055
+ * const lynkow = createClient({ siteId: '...' })
2056
+ *
2057
+ * // Build srcset for responsive images
2058
+ * const srcset = lynkow.media.srcset(content.featuredImage)
2059
+ *
2060
+ * // Build a single transformed URL
2061
+ * const url = lynkow.media.transform(content.featuredImage, { w: 800 })
2062
+ * ```
2063
+ */
2064
+ declare class MediaHelperService {
2065
+ /**
2066
+ * Generates an HTML `srcset` attribute value from an image URL.
2067
+ *
2068
+ * @param imageUrl - Original image URL from the Lynkow API
2069
+ * @param options - Srcset configuration
2070
+ * @returns srcset string ready for use in an `<img>` tag, or empty string if URL is invalid
2071
+ */
2072
+ srcset(imageUrl: string | null | undefined, options?: SrcsetOptions): string;
2073
+ /**
2074
+ * Generates a single transformed image URL.
2075
+ *
2076
+ * @param imageUrl - Original image URL from the Lynkow API
2077
+ * @param options - Transformation options
2078
+ * @returns Transformed URL, or the original URL if transformation is not possible
2079
+ */
2080
+ transform(imageUrl: string | null | undefined, options?: TransformOptions): string;
2081
+ /**
2082
+ * Extracts the CDN base and relative path from a Lynkow image URL.
2083
+ *
2084
+ * Handles both original URLs and already-transformed URLs.
2085
+ *
2086
+ * @returns Parsed URL parts, or null if the URL is not a valid Lynkow CDN URL
2087
+ */
2088
+ private parseImageUrl;
2089
+ }
2090
+
1987
2091
  /**
1988
2092
  * Lynkow SDK Client
1989
2093
  * Main entry point for the SDK
@@ -2064,6 +2168,11 @@ interface Client extends LynkowClient {
2064
2168
  * Content enhancements service (code copy, etc.)
2065
2169
  */
2066
2170
  enhancements: EnhancementsService;
2171
+ /**
2172
+ * Image transformation helpers.
2173
+ * Use these to build optimized image URLs for responsive images.
2174
+ */
2175
+ readonly media: MediaHelperService;
2067
2176
  }
2068
2177
  /**
2069
2178
  * Creates a Lynkow client instance (SDK v3)
@@ -2213,4 +2322,4 @@ declare function browserOnly<T>(fn: () => T, fallback: T): T;
2213
2322
  */
2214
2323
  declare function browserOnlyAsync<T>(fn: () => Promise<T>, fallback: T): Promise<T>;
2215
2324
 
2216
- export { type Alternate, type ApiErrorDetail, type Author, type BaseRequestOptions, type CategoriesListResponse, type Category, type CategoryDetail, type CategoryDetailResponse, type CategoryOptions, type CategoryResolveResponse, type CategoryTreeNode, type CategoryTreeResponse, type CategoryWithCount, type Client, type ClientConfig, type ConsentCategories, type ConsentLogResponse, type Content, type ContentBody, type ContentResolveResponse, type ContentSummary, type ContentsFilters, type ContentsListResponse, type CookieCategory, type CookieConfig, type CookiePreferences, type CookieTexts, EnhancementsService, type ErrorCode, type EventData, type EventName, type Form, type FormField, type FormFieldOption, type FormFieldType, type FormFieldValidation, type FormSettings, type FormSubmitData, type FormSubmitResponse, type FunnelStepData, type GlobalBlock, type GlobalBlockResponse, type LegalDocument, type LynkowClient, type LynkowConfig, LynkowError, type LynkowEvents, type Page, type PageSeo, type PageSummary, type PagesListResponse, type PageviewData, type PaginatedResponse, type PaginationMeta, type PaginationOptions, type Path, type PathsListResponse, type Redirect, type ResolveResponse, type Review, type ReviewResponse, type ReviewSettings, type ReviewSubmitData, type ReviewSubmitResponse, type ReviewsFilters, type ReviewsListResponse, type SiteConfig, type SiteConfigResponse, type SortOptions, type SubmitOptions, type Tag, type TagsListResponse, type TipTapMark, type TipTapNode, browserOnly, browserOnlyAsync, createClient, createLynkowClient, isBrowser, isCategoryResolve, isContentResolve, isLynkowError, isServer };
2325
+ export { type Alternate, type ApiErrorDetail, type Author, type BaseRequestOptions, type CategoriesListResponse, type Category, type CategoryDetail, type CategoryDetailResponse, type CategoryOptions, type CategoryResolveResponse, type CategoryTreeNode, type CategoryTreeResponse, type CategoryWithCount, type Client, type ClientConfig, type ConsentCategories, type ConsentLogResponse, type Content, type ContentBody, type ContentResolveResponse, type ContentSummary, type ContentsFilters, type ContentsListResponse, type CookieCategory, type CookieConfig, type CookiePreferences, type CookieTexts, EnhancementsService, type ErrorCode, type EventData, type EventName, type Form, type FormField, type FormFieldOption, type FormFieldType, type FormFieldValidation, type FormSettings, type FormSubmitData, type FormSubmitResponse, type FunnelStepData, type GlobalBlock, type GlobalBlockResponse, type ImageVariants, type LegalDocument, type LynkowClient, type LynkowConfig, LynkowError, type LynkowEvents, MediaHelperService, type Page, type PageSeo, type PageSummary, type PagesListResponse, type PageviewData, type PaginatedResponse, type PaginationMeta, type PaginationOptions, type Path, type PathsListResponse, type Redirect, type ResolveResponse, type Review, type ReviewResponse, type ReviewSettings, type ReviewSubmitData, type ReviewSubmitResponse, type ReviewsFilters, type ReviewsListResponse, type SiteConfig, type SiteConfigResponse, type SortOptions, type SrcsetOptions, type SubmitOptions, type Tag, type TagsListResponse, type TipTapMark, type TipTapNode, type TransformOptions, browserOnly, browserOnlyAsync, createClient, createLynkowClient, isBrowser, isCategoryResolve, isContentResolve, isLynkowError, isServer };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var C=class n extends Error{name="LynkowError";code;status;details;cause;constructor(e,t,o,r,i){super(e),this.code=t,this.status=o,this.details=r,this.cause=i,Error.captureStackTrace&&Error.captureStackTrace(this,n);}static async fromResponse(e){let t=e.status,o=`HTTP ${t}`,r;try{let s=await e.json();s.errors&&Array.isArray(s.errors)?(r=s.errors,o=s.errors[0]?.message||o):s.error?o=s.error:s.message&&(o=s.message);}catch{o=e.statusText||o;}let i=n.statusToCode(t);return new n(o,i,t,r)}static fromNetworkError(e){return e.name==="AbortError"?new n("Request timed out","TIMEOUT",void 0,void 0,e):e.name==="TypeError"?new n("Network error - please check your connection","NETWORK_ERROR",void 0,void 0,e):new n(e.message||"Unknown error","UNKNOWN",void 0,void 0,e)}static statusToCode(e){switch(e){case 400:return "VALIDATION_ERROR";case 401:return "UNAUTHORIZED";case 403:return "FORBIDDEN";case 404:return "NOT_FOUND";case 429:return "RATE_LIMITED";default:return "UNKNOWN"}}toJSON(){return {name:this.name,message:this.message,code:this.code,status:this.status,details:this.details}}};function de(n){return n instanceof C}function ge(n){switch(n){case 400:return "BAD_REQUEST";case 401:return "UNAUTHORIZED";case 403:return "FORBIDDEN";case 404:return "NOT_FOUND";case 422:return "VALIDATION_ERROR";case 429:return "TOO_MANY_REQUESTS";case 503:return "SERVICE_UNAVAILABLE";default:return "INTERNAL_ERROR"}}async function K(n,e){let t;try{t=await fetch(n,e);}catch(l){throw new C("Network error: Unable to reach the server","NETWORK_ERROR",0,[{message:l instanceof Error?l.message:"Unknown error"}])}if(t.ok)return t.json();let o={};try{o=await t.json();}catch{}let r=ge(t.status),i=o.error||o.message||`HTTP error: ${t.status}`,s=o.errors||[{message:i}];throw new C(i,r,t.status,s)}function Q(n){let e=new URLSearchParams;for(let[t,o]of Object.entries(n))o!=null&&o!==""&&e.append(t,String(o));return e.toString()}var p={SHORT:300*1e3,MEDIUM:600*1e3},u=class{config;cache;constructor(e){this.config=e,this.cache=e.cache;}buildEndpointUrl(e,t){let o=`${this.config.baseUrl}/public/${this.config.siteId}${e}`;if(t&&Object.keys(t).length>0){let r=Q(t);return `${o}?${r}`}return o}async get(e,t,o){let r=o?.locale||this.config.locale,i=r?{...t,locale:r}:t,s=this.buildEndpointUrl(e,i),l=this.mergeFetchOptions(o?.fetchOptions);return K(s,{method:"GET",...l})}async getWithCache(e,t,o,r,i=p.SHORT){return this.cache?this.cache.getOrSet(e,()=>this.get(t,o,r),i):this.get(t,o,r)}invalidateCache(e){this.cache?.invalidate(e);}async post(e,t,o){let r=this.buildEndpointUrl(e),i=this.mergeFetchOptions(o?.fetchOptions);return K(r,{method:"POST",...i,headers:{"Content-Type":"application/json",...i.headers},body:JSON.stringify(t)})}async getText(e,t){let o=this.buildEndpointUrl(e),r=this.mergeFetchOptions(t?.fetchOptions),i=await fetch(o,{method:"GET",...r});if(!i.ok)throw new Error(`HTTP error: ${i.status}`);return i.text()}mergeFetchOptions(e){return {...this.config.fetchOptions,...e,headers:{...this.config.fetchOptions.headers,...e?.headers}}}};var M="contents_",R=class extends u{async list(e,t){let o={};e?.page&&(o.page=e.page),e?.perPage&&(o.perPage=e.perPage),e?.category&&(o.category=e.category),e?.tag&&(o.tag=e.tag),e?.search&&(o.search=e.search),e?.sort&&(o.sort=e.sort),e?.order&&(o.order=e.order),e?.locale&&(o.locale=e.locale);let r=`${M}list_${JSON.stringify(e||{})}`;return this.getWithCache(r,"/contents",o,t,p.SHORT)}async getBySlug(e,t){let o=t?.locale||this.config.locale,r=`${M}slug_${e}_${o||"default"}`;return this.getWithCache(r,`/contents/slug/${encodeURIComponent(e)}`,void 0,t,p.SHORT)}clearCache(){this.invalidateCache(M);}};var D="categories_",k=class extends u{async list(e){let t=e?.locale||this.config.locale,o=`${D}list_${t||"default"}`;return this.getWithCache(o,"/categories",void 0,e,p.SHORT)}async tree(e){let t=e?.locale||this.config.locale,o=`${D}tree_${t||"default"}`;return this.getWithCache(o,"/categories/tree",void 0,e,p.SHORT)}async getBySlug(e,t){let o={};t?.page&&(o.page=t.page),t?.perPage&&(o.limit=t.perPage);let r=`${D}slug_${e}_${JSON.stringify(t||{})}`;return this.getWithCache(r,`/categories/${encodeURIComponent(e)}`,o,t,p.SHORT)}clearCache(){this.invalidateCache(D);}};var Z="tags_",x=class extends u{async list(e){let t=e?.locale||this.config.locale,o=`${Z}list_${t||"default"}`;return this.getWithCache(o,"/tags",void 0,e,p.SHORT)}clearCache(){this.invalidateCache(Z);}};var E="pages_",L=class extends u{async list(e){let t=e?.locale||this.config.locale,o={};e?.tag&&(o.tag=e.tag);let r=`${E}list_${t||"default"}_${e?.tag||"all"}`;return this.getWithCache(r,"/pages",o,e,p.SHORT)}async getBySlug(e,t){let o=t?.locale||this.config.locale,r=`${E}slug_${e}_${o||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}`,void 0,t,p.SHORT)).data}async getByPath(e,t){let o=t?.locale||this.config.locale,r=`${E}path_${e}_${o||"default"}`;return (await this.getWithCache(r,"/page-by-path",{path:e},t,p.SHORT)).data}async getJsonLd(e,t){let o=t?.locale||this.config.locale,r=`${E}jsonld_${e}_${o||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}/json-ld`,void 0,t,p.SHORT)).data}clearCache(){this.invalidateCache(E);}};var z="globals_",T=class extends u{async siteConfig(e){let t=e?.locale||this.config.locale,o=`${z}siteconfig_${t||"default"}`;return this.getWithCache(o,"/site-config",void 0,e,p.MEDIUM)}async getBySlug(e,t){let o=t?.locale||this.config.locale,r=`${z}${e}_${o||"default"}`;return this.getWithCache(r,`/global/${encodeURIComponent(e)}`,void 0,t,p.MEDIUM)}async global(e,t){return this.getBySlug(e,t)}clearCache(){this.invalidateCache(z);}};function N(n){return {_hp:"",_ts:n}}var ee="forms_",S=class extends u{sessionStartTime;constructor(e){super(e),this.sessionStartTime=Date.now();}async getBySlug(e){let t=`${ee}${e}`;return (await this.getWithCache(t,`/forms/${encodeURIComponent(e)}`,void 0,void 0,p.MEDIUM)).data}async submit(e,t,o){let r=N(this.sessionStartTime),i={data:t,honeypot:r._hp,...r};return o?.recaptchaToken&&(i.recaptchaToken=o.recaptchaToken),this.post(`/forms/${encodeURIComponent(e)}/submit`,i,o)}clearCache(){this.invalidateCache(ee);}};var O="reviews_",P=class extends u{sessionStartTime;constructor(e){super(e),this.sessionStartTime=Date.now();}async list(e,t){let o={};e?.page&&(o.page=e.page),e?.perPage&&(o.perPage=e.perPage),e?.minRating&&(o.minRating=e.minRating),e?.maxRating&&(o.maxRating=e.maxRating),e?.sort&&(o.sort=e.sort),e?.order&&(o.order=e.order);let r=`${O}list_${JSON.stringify(e||{})}`;return this.getWithCache(r,"/reviews",o,t,p.SHORT)}async getBySlug(e){let t=`${O}slug_${e}`;return (await this.getWithCache(t,`/reviews/${encodeURIComponent(e)}`,void 0,void 0,p.SHORT)).data}async settings(){let e=`${O}settings`;return this.getWithCache(e,"/reviews/settings",void 0,void 0,p.MEDIUM)}async submit(e,t){let o=N(this.sessionStartTime),r={...e,...o};t?.recaptchaToken&&(r._recaptcha_token=t.recaptchaToken);let i=await this.post("/reviews",r,t);return this.invalidateCache(O),i}clearCache(){this.invalidateCache(O);}};var te="site_",I=class extends u{async getConfig(){let e=`${te}config`;return (await this.getWithCache(e,"/site",void 0,void 0,p.MEDIUM)).data}clearCache(){this.invalidateCache(te);}};var W="legal_",B=class extends u{async list(e){let t=e?.locale||this.config.locale,o=`${W}list_${t||"default"}`;return (await this.getWithCache(o,"/pages",{tag:"legal"},e,p.SHORT)).data}async getBySlug(e,t){let o=t?.locale||this.config.locale,r=`${W}slug_${e}_${o||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}`,void 0,t,p.SHORT)).data}clearCache(){this.invalidateCache(W);}};var oe="cookies_",$=class extends u{async getConfig(){let e=`${oe}config`;return (await this.getWithCache(e,"/cookie-consent/config",void 0,void 0,p.MEDIUM)).data}async logConsent(e,t){return this.post("/cookie-consent/log",{preferences:e},t)}clearCache(){this.invalidateCache(oe);}};var A=class extends u{async sitemap(e){return this.getText("/sitemap.xml",e)}async robots(e){return this.getText("/robots.txt",e)}};var j="paths_",_=class extends u{async list(e){let t=e?.locale||this.config.locale,o=`${j}list_${t||"all"}`;return this.getWithCache(o,"/paths",void 0,e,p.SHORT)}async resolve(e,t){let o=t?.locale||this.config.locale,r=`${j}resolve_${e}_${o||"default"}`;return this.getWithCache(r,"/resolve",{path:e},t,p.SHORT)}async matchRedirect(e,t){try{return (await this.get("/redirects/match",{path:e},t)).data}catch(o){if(o instanceof C&&o.status===404)return null;throw o}}clearCache(){this.invalidateCache(j);}};var a=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",ue=!a;function me(n,e){return a?n():e}async function fe(n,e){return a?n():e}var G="lynkow-tracker",U=class{config;enabled=true;initialized=false;loading=false;loadPromise=null;constructor(e){this.config=e;}getTrackerUrl(){return `${this.config.baseUrl}/analytics/tracker.js`}loadTracker(){return !a||window.LynkowAnalytics?Promise.resolve():this.loadPromise?this.loadPromise:(this.loading=true,this.loadPromise=new Promise((e,t)=>{if(document.getElementById(G)){let r=setInterval(()=>{window.LynkowAnalytics&&(clearInterval(r),this.loading=false,e());},50);setTimeout(()=>{clearInterval(r),this.loading=false,t(new Error("Tracker script load timeout"));},1e4);return}let o=document.createElement("script");o.id=G,o.src=this.getTrackerUrl(),o.async=true,o.setAttribute("data-site-id",this.config.siteId),this.config.baseUrl&&o.setAttribute("data-api-url",this.config.baseUrl),o.onload=()=>{this.loading=false,setTimeout(()=>{window.LynkowAnalytics?e():t(new Error("Tracker script loaded but LynkowAnalytics not found"));},0);},o.onerror=()=>{this.loading=false,t(new Error("Failed to load tracker script"));},document.head.appendChild(o);}),this.loadPromise)}async init(){if(!(!a||this.initialized))try{await this.loadTracker(),window.LynkowAnalytics&&!this.initialized&&(this.initialized=!0);}catch(e){console.error("[Lynkow] Failed to initialize analytics:",e);}}async trackEvent(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.track(e));}async trackFunnelStep(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.trackFunnel(e.funnelId,e.stepNumber,e.stepName,e.funnelName));}async trackPageview(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.track({type:"pageview",path:e?.path||window.location.pathname,title:e?.title||document.title,referrer:e?.referrer||document.referrer}));}enable(){this.enabled=true;}disable(){this.enabled=false;}isEnabled(){return this.enabled}isInitialized(){return this.initialized&&!!window.LynkowAnalytics}getTracker(){if(a)return window.LynkowAnalytics}destroy(){if(!a)return;document.getElementById(G)?.remove(),this.initialized=false,this.loadPromise=null;}};var J="_lkw_consent",V={necessary:true,analytics:false,marketing:false,preferences:false},H=class{config;events;bannerElement=null;preferencesElement=null;configCache=null;constructor(e,t){this.config=e,this.events=t;}async getConfig(){if(this.configCache)return this.configCache;let e=`${this.config.baseUrl}/public/${this.config.siteId}/cookie-consent/config`,t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"},...this.config.fetchOptions});if(!t.ok)throw new Error(`Failed to fetch consent config: ${t.status}`);let o=await t.json();return this.configCache=o.data,this.configCache}async logConsent(e){let t=`${this.config.baseUrl}/public/${this.config.siteId}/cookie-consent/log`;await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({preferences:e}),...this.config.fetchOptions}).catch(()=>{});}getStoredConsent(){if(!a)return null;try{let e=localStorage.getItem(J);if(e){let t=JSON.parse(e);return t.choices?t.choices:t}}catch{}return null}saveConsent(e){if(a){try{localStorage.setItem(J,JSON.stringify({choices:e}));}catch{}this.events.emit("consent-changed",e),document.dispatchEvent(new CustomEvent("lynkow:consent:update",{detail:e}));}}show(){a&&(this.bannerElement||this.getConfig().then(e=>{if(!e.enabled)return;let t=document.createElement("div");t.innerHTML=this.createBannerHTML(e),this.bannerElement=t.firstElementChild,document.body.appendChild(this.bannerElement),this.attachBannerEvents();}));}hide(){a&&(this.bannerElement?.remove(),this.bannerElement=null);}showPreferences(){a&&(this.preferencesElement||this.getConfig().then(e=>{let t=this.getCategories(),o=document.createElement("div");o.innerHTML=this.createPreferencesHTML(e,t),this.preferencesElement=o.firstElementChild,document.body.appendChild(this.preferencesElement),this.attachPreferencesEvents(e);}));}getCategories(){return a?this.getStoredConsent()||{...V}:{...V}}hasConsented(){return a?this.getStoredConsent()!==null:false}acceptAll(){if(!a)return;let e={necessary:true,analytics:true,marketing:true,preferences:true};this.saveConsent(e),this.logConsent(e),this.hide();}rejectAll(){if(!a)return;let e={necessary:true,analytics:false,marketing:false,preferences:false};this.saveConsent(e),this.logConsent(e),this.hide();}setCategories(e){if(!a)return;let o={...this.getCategories(),...e,necessary:true};this.saveConsent(o),this.logConsent(o);}reset(){if(a){try{localStorage.removeItem(J);}catch{}this.events.emit("consent-changed",{...V}),this.show();}}createBannerHTML(e){let t=e.position||"bottom",o=e.theme||"light",r=e.layout||"banner",i=e.primaryColor||"#0066cc",s=e.borderRadius??8,l={bottom:"bottom: 0; left: 0; right: 0;",top:"top: 0; left: 0; right: 0;","bottom-left":"bottom: 0; left: 0; right: 0;","bottom-right":"bottom: 0; left: 0; right: 0;",center:"top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px);"},f={bottom:`bottom: 20px; left: 50%; transform: translateX(-50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,top:`top: 20px; left: 50%; transform: translateX(-50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-left":`bottom: 20px; left: 20px; max-width: 400px; border-radius: ${s}px;`,"bottom-right":`bottom: 20px; right: 20px; max-width: 400px; border-radius: ${s}px;`,center:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`},h={center:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,bottom:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,top:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-left":`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-right":`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`},g;r==="floating"?g=f:r==="modal"?g=h:g=l;let c=g[t]||g.bottom||"",d=o==="dark",m=d?"#1a1a1a":"#ffffff",y=d?"#ffffff":"#1a1a1a",b=e.texts||{title:"Nous utilisons des cookies",description:"Ce site utilise des cookies pour ameliorer votre experience.",acceptAll:"Accepter tout",rejectAll:"Refuser",customize:"Personnaliser"};return `
1
+ 'use strict';var C=class o extends Error{name="LynkowError";code;status;details;cause;constructor(e,t,n,r,i){super(e),this.code=t,this.status=n,this.details=r,this.cause=i,Error.captureStackTrace&&Error.captureStackTrace(this,o);}static async fromResponse(e){let t=e.status,n=`HTTP ${t}`,r;try{let s=await e.json();s.errors&&Array.isArray(s.errors)?(r=s.errors,n=s.errors[0]?.message||n):s.error?n=s.error:s.message&&(n=s.message);}catch{n=e.statusText||n;}let i=o.statusToCode(t);return new o(n,i,t,r)}static fromNetworkError(e){return e.name==="AbortError"?new o("Request timed out","TIMEOUT",void 0,void 0,e):e.name==="TypeError"?new o("Network error - please check your connection","NETWORK_ERROR",void 0,void 0,e):new o(e.message||"Unknown error","UNKNOWN",void 0,void 0,e)}static statusToCode(e){switch(e){case 400:return "VALIDATION_ERROR";case 401:return "UNAUTHORIZED";case 403:return "FORBIDDEN";case 404:return "NOT_FOUND";case 429:return "RATE_LIMITED";default:return "UNKNOWN"}}toJSON(){return {name:this.name,message:this.message,code:this.code,status:this.status,details:this.details}}};function ue(o){return o instanceof C}function ge(o){switch(o){case 400:return "BAD_REQUEST";case 401:return "UNAUTHORIZED";case 403:return "FORBIDDEN";case 404:return "NOT_FOUND";case 422:return "VALIDATION_ERROR";case 429:return "TOO_MANY_REQUESTS";case 503:return "SERVICE_UNAVAILABLE";default:return "INTERNAL_ERROR"}}async function M(o,e){let t;try{t=await fetch(o,e);}catch(l){throw new C("Network error: Unable to reach the server","NETWORK_ERROR",0,[{message:l instanceof Error?l.message:"Unknown error"}])}if(t.ok)return t.json();let n={};try{n=await t.json();}catch{}let r=ge(t.status),i=n.error||n.message||`HTTP error: ${t.status}`,s=n.errors||[{message:i}];throw new C(i,r,t.status,s)}function Z(o){let e=new URLSearchParams;for(let[t,n]of Object.entries(o))n!=null&&n!==""&&e.append(t,String(n));return e.toString()}var d={SHORT:300*1e3,MEDIUM:600*1e3},g=class{config;cache;constructor(e){this.config=e,this.cache=e.cache;}buildEndpointUrl(e,t){let n=`${this.config.baseUrl}/public/${this.config.siteId}${e}`;if(t&&Object.keys(t).length>0){let r=Z(t);return `${n}?${r}`}return n}async get(e,t,n){let r=n?.locale||this.config.locale,i=r?{...t,locale:r}:t,s=this.buildEndpointUrl(e,i),l=this.mergeFetchOptions(n?.fetchOptions);return M(s,{method:"GET",...l})}async getWithCache(e,t,n,r,i=d.SHORT){return this.cache?this.cache.getOrSet(e,()=>this.get(t,n,r),i):this.get(t,n,r)}invalidateCache(e){this.cache?.invalidate(e);}async post(e,t,n){let r=this.buildEndpointUrl(e),i=this.mergeFetchOptions(n?.fetchOptions);return M(r,{method:"POST",...i,headers:{"Content-Type":"application/json",...i.headers},body:JSON.stringify(t)})}async getText(e,t){let n=this.buildEndpointUrl(e),r=this.mergeFetchOptions(t?.fetchOptions),i=await fetch(n,{method:"GET",...r});if(!i.ok)throw new Error(`HTTP error: ${i.status}`);return i.text()}mergeFetchOptions(e){return {...this.config.fetchOptions,...e,headers:{...this.config.fetchOptions.headers,...e?.headers}}}};var z="contents_",R=class extends g{async list(e,t){let n={};e?.page&&(n.page=e.page),e?.perPage&&(n.perPage=e.perPage),e?.category&&(n.category=e.category),e?.tag&&(n.tag=e.tag),e?.search&&(n.search=e.search),e?.sort&&(n.sort=e.sort),e?.order&&(n.order=e.order),e?.locale&&(n.locale=e.locale);let r=`${z}list_${JSON.stringify(e||{})}`;return this.getWithCache(r,"/contents",n,t,d.SHORT)}async getBySlug(e,t){let n=t?.locale||this.config.locale,r=`${z}slug_${e}_${n||"default"}`;return this.getWithCache(r,`/contents/slug/${encodeURIComponent(e)}`,void 0,t,d.SHORT)}clearCache(){this.invalidateCache(z);}};var N="categories_",x=class extends g{async list(e){let t=e?.locale||this.config.locale,n=`${N}list_${t||"default"}`;return this.getWithCache(n,"/categories",void 0,e,d.SHORT)}async tree(e){let t=e?.locale||this.config.locale,n=`${N}tree_${t||"default"}`;return this.getWithCache(n,"/categories/tree",void 0,e,d.SHORT)}async getBySlug(e,t){let n={};t?.page&&(n.page=t.page),t?.perPage&&(n.limit=t.perPage);let r=`${N}slug_${e}_${JSON.stringify(t||{})}`;return this.getWithCache(r,`/categories/${encodeURIComponent(e)}`,n,t,d.SHORT)}clearCache(){this.invalidateCache(N);}};var ee="tags_",k=class extends g{async list(e){let t=e?.locale||this.config.locale,n=`${ee}list_${t||"default"}`;return this.getWithCache(n,"/tags",void 0,e,d.SHORT)}clearCache(){this.invalidateCache(ee);}};var E="pages_",L=class extends g{async list(e){let t=e?.locale||this.config.locale,n={};e?.tag&&(n.tag=e.tag);let r=`${E}list_${t||"default"}_${e?.tag||"all"}`;return this.getWithCache(r,"/pages",n,e,d.SHORT)}async getBySlug(e,t){let n=t?.locale||this.config.locale,r=`${E}slug_${e}_${n||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}`,void 0,t,d.SHORT)).data}async getByPath(e,t){let n=t?.locale||this.config.locale,r=`${E}path_${e}_${n||"default"}`;return (await this.getWithCache(r,"/page-by-path",{path:e},t,d.SHORT)).data}async getJsonLd(e,t){let n=t?.locale||this.config.locale,r=`${E}jsonld_${e}_${n||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}/json-ld`,void 0,t,d.SHORT)).data}clearCache(){this.invalidateCache(E);}};var j="globals_",T=class extends g{async siteConfig(e){let t=e?.locale||this.config.locale,n=`${j}siteconfig_${t||"default"}`;return this.getWithCache(n,"/site-config",void 0,e,d.MEDIUM)}async getBySlug(e,t){let n=t?.locale||this.config.locale,r=`${j}${e}_${n||"default"}`;return this.getWithCache(r,`/global/${encodeURIComponent(e)}`,void 0,t,d.MEDIUM)}async global(e,t){return this.getBySlug(e,t)}clearCache(){this.invalidateCache(j);}};function H(o){return {_hp:"",_ts:o}}var te="forms_",S=class extends g{sessionStartTime;constructor(e){super(e),this.sessionStartTime=Date.now();}async getBySlug(e){let t=`${te}${e}`;return (await this.getWithCache(t,`/forms/${encodeURIComponent(e)}`,void 0,void 0,d.MEDIUM)).data}async submit(e,t,n){let r=H(this.sessionStartTime),i={data:t,honeypot:r._hp,...r};return n?.recaptchaToken&&(i.recaptchaToken=n.recaptchaToken),this.post(`/forms/${encodeURIComponent(e)}/submit`,i,n)}clearCache(){this.invalidateCache(te);}};var O="reviews_",P=class extends g{sessionStartTime;constructor(e){super(e),this.sessionStartTime=Date.now();}async list(e,t){let n={};e?.page&&(n.page=e.page),e?.perPage&&(n.perPage=e.perPage),e?.minRating&&(n.minRating=e.minRating),e?.maxRating&&(n.maxRating=e.maxRating),e?.sort&&(n.sort=e.sort),e?.order&&(n.order=e.order);let r=`${O}list_${JSON.stringify(e||{})}`;return this.getWithCache(r,"/reviews",n,t,d.SHORT)}async getBySlug(e){let t=`${O}slug_${e}`;return (await this.getWithCache(t,`/reviews/${encodeURIComponent(e)}`,void 0,void 0,d.SHORT)).data}async settings(){let e=`${O}settings`;return this.getWithCache(e,"/reviews/settings",void 0,void 0,d.MEDIUM)}async submit(e,t){let n=H(this.sessionStartTime),r={...e,...n};t?.recaptchaToken&&(r._recaptcha_token=t.recaptchaToken);let i=await this.post("/reviews",r,t);return this.invalidateCache(O),i}clearCache(){this.invalidateCache(O);}};var ne="site_",I=class extends g{async getConfig(){let e=`${ne}config`;return (await this.getWithCache(e,"/site",void 0,void 0,d.MEDIUM)).data}clearCache(){this.invalidateCache(ne);}};var W="legal_",B=class extends g{async list(e){let t=e?.locale||this.config.locale,n=`${W}list_${t||"default"}`;return (await this.getWithCache(n,"/pages",{tag:"legal"},e,d.SHORT)).data}async getBySlug(e,t){let n=t?.locale||this.config.locale,r=`${W}slug_${e}_${n||"default"}`;return (await this.getWithCache(r,`/pages/${encodeURIComponent(e)}`,void 0,t,d.SHORT)).data}clearCache(){this.invalidateCache(W);}};var oe="cookies_",$=class extends g{async getConfig(){let e=`${oe}config`;return (await this.getWithCache(e,"/cookie-consent/config",void 0,void 0,d.MEDIUM)).data}async logConsent(e,t){return this.post("/cookie-consent/log",{preferences:e},t)}clearCache(){this.invalidateCache(oe);}};var A=class extends g{async sitemap(e){return this.getText("/sitemap.xml",e)}async robots(e){return this.getText("/robots.txt",e)}};var G="paths_",_=class extends g{async list(e){let t=e?.locale||this.config.locale,n=`${G}list_${t||"all"}`;return this.getWithCache(n,"/paths",void 0,e,d.SHORT)}async resolve(e,t){let n=t?.locale||this.config.locale,r=`${G}resolve_${e}_${n||"default"}`;return this.getWithCache(r,"/resolve",{path:e},t,d.SHORT)}async matchRedirect(e,t){try{return (await this.get("/redirects/match",{path:e},t)).data}catch(n){if(n instanceof C&&n.status===404)return null;throw n}}clearCache(){this.invalidateCache(G);}};var a=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",fe=!a;function me(o,e){return a?o():e}async function he(o,e){return a?o():e}var V="lynkow-tracker",q=class{config;enabled=true;initialized=false;loading=false;loadPromise=null;constructor(e){this.config=e;}getTrackerUrl(){return `${this.config.baseUrl}/analytics/tracker.js`}loadTracker(){return !a||window.LynkowAnalytics?Promise.resolve():this.loadPromise?this.loadPromise:(this.loading=true,this.loadPromise=new Promise((e,t)=>{if(document.getElementById(V)){let r=setInterval(()=>{window.LynkowAnalytics&&(clearInterval(r),this.loading=false,e());},50);setTimeout(()=>{clearInterval(r),this.loading=false,t(new Error("Tracker script load timeout"));},1e4);return}let n=document.createElement("script");n.id=V,n.src=this.getTrackerUrl(),n.async=true,n.setAttribute("data-site-id",this.config.siteId),this.config.baseUrl&&n.setAttribute("data-api-url",this.config.baseUrl),n.onload=()=>{this.loading=false,setTimeout(()=>{window.LynkowAnalytics?e():t(new Error("Tracker script loaded but LynkowAnalytics not found"));},0);},n.onerror=()=>{this.loading=false,t(new Error("Failed to load tracker script"));},document.head.appendChild(n);}),this.loadPromise)}async init(){if(!(!a||this.initialized))try{await this.loadTracker(),window.LynkowAnalytics&&!this.initialized&&(this.initialized=!0);}catch(e){console.error("[Lynkow] Failed to initialize analytics:",e);}}async trackEvent(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.track(e));}async trackFunnelStep(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.trackFunnel(e.funnelId,e.stepNumber,e.stepName,e.funnelName));}async trackPageview(e){!a||!this.enabled||(await this.init(),window.LynkowAnalytics&&window.LynkowAnalytics.track({type:"pageview",path:e?.path||window.location.pathname,title:e?.title||document.title,referrer:e?.referrer||document.referrer}));}enable(){this.enabled=true;}disable(){this.enabled=false;}isEnabled(){return this.enabled}isInitialized(){return this.initialized&&!!window.LynkowAnalytics}getTracker(){if(a)return window.LynkowAnalytics}destroy(){if(!a)return;document.getElementById(V)?.remove(),this.initialized=false,this.loadPromise=null;}};var J="_lkw_consent",X={necessary:true,analytics:false,marketing:false,preferences:false},U=class{config;events;bannerElement=null;preferencesElement=null;configCache=null;constructor(e,t){this.config=e,this.events=t;}async getConfig(){if(this.configCache)return this.configCache;let e=`${this.config.baseUrl}/public/${this.config.siteId}/cookie-consent/config`,t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"},...this.config.fetchOptions});if(!t.ok)throw new Error(`Failed to fetch consent config: ${t.status}`);let n=await t.json();return this.configCache=n.data,this.configCache}async logConsent(e){let t=`${this.config.baseUrl}/public/${this.config.siteId}/cookie-consent/log`;await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({preferences:e}),...this.config.fetchOptions}).catch(()=>{});}getStoredConsent(){if(!a)return null;try{let e=localStorage.getItem(J);if(e){let t=JSON.parse(e);return t.choices?t.choices:t}}catch{}return null}saveConsent(e){if(a){try{localStorage.setItem(J,JSON.stringify({choices:e}));}catch{}this.events.emit("consent-changed",e),document.dispatchEvent(new CustomEvent("lynkow:consent:update",{detail:e}));}}show(){a&&(this.bannerElement||this.getConfig().then(e=>{if(!e.enabled)return;let t=document.createElement("div");t.innerHTML=this.createBannerHTML(e),this.bannerElement=t.firstElementChild,document.body.appendChild(this.bannerElement),this.attachBannerEvents();}));}hide(){a&&(this.bannerElement?.remove(),this.bannerElement=null);}showPreferences(){a&&(this.preferencesElement||this.getConfig().then(e=>{let t=this.getCategories(),n=document.createElement("div");n.innerHTML=this.createPreferencesHTML(e,t),this.preferencesElement=n.firstElementChild,document.body.appendChild(this.preferencesElement),this.attachPreferencesEvents(e);}));}getCategories(){return a?this.getStoredConsent()||{...X}:{...X}}hasConsented(){return a?this.getStoredConsent()!==null:false}acceptAll(){if(!a)return;let e={necessary:true,analytics:true,marketing:true,preferences:true};this.saveConsent(e),this.logConsent(e),this.hide();}rejectAll(){if(!a)return;let e={necessary:true,analytics:false,marketing:false,preferences:false};this.saveConsent(e),this.logConsent(e),this.hide();}setCategories(e){if(!a)return;let n={...this.getCategories(),...e,necessary:true};this.saveConsent(n),this.logConsent(n);}reset(){if(a){try{localStorage.removeItem(J);}catch{}this.events.emit("consent-changed",{...X}),this.show();}}createBannerHTML(e){let t=e.position||"bottom",n=e.theme||"light",r=e.layout||"banner",i=e.primaryColor||"#0066cc",s=e.borderRadius??8,l={bottom:"bottom: 0; left: 0; right: 0;",top:"top: 0; left: 0; right: 0;","bottom-left":"bottom: 0; left: 0; right: 0;","bottom-right":"bottom: 0; left: 0; right: 0;",center:"top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px);"},f={bottom:`bottom: 20px; left: 50%; transform: translateX(-50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,top:`top: 20px; left: 50%; transform: translateX(-50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-left":`bottom: 20px; left: 20px; max-width: 400px; border-radius: ${s}px;`,"bottom-right":`bottom: 20px; right: 20px; max-width: 400px; border-radius: ${s}px;`,center:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`},h={center:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,bottom:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,top:`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-left":`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`,"bottom-right":`top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 500px; width: calc(100% - 40px); border-radius: ${s}px;`},u;r==="floating"?u=f:r==="modal"?u=h:u=l;let c=u[t]||u.bottom||"",p=n==="dark",m=p?"#1a1a1a":"#ffffff",y=p?"#ffffff":"#1a1a1a",b=e.texts||{title:"Nous utilisons des cookies",description:"Ce site utilise des cookies pour ameliorer votre experience.",acceptAll:"Accepter tout",rejectAll:"Refuser",customize:"Personnaliser"};return `
2
2
  ${r==="modal"?`
3
3
  <div id="lynkow-consent-backdrop" style="
4
4
  position: fixed;
@@ -57,21 +57,21 @@
57
57
  </div>
58
58
  </div>
59
59
  </div>
60
- `}createPreferencesHTML(e,t){let o=e.theme||"light",r=e.primaryColor||"#0066cc",i=e.borderRadius??8,s=o==="dark",l=s?"#1a1a1a":"#ffffff",f=s?"#ffffff":"#1a1a1a",h=e.texts||{title:"Preferences de cookies",save:"Enregistrer"},c=(e.categories||[]).map(d=>`
61
- <label style="display: flex; align-items: flex-start; gap: 10px; margin: 15px 0; cursor: ${d.required?"not-allowed":"pointer"};">
60
+ `}createPreferencesHTML(e,t){let n=e.theme||"light",r=e.primaryColor||"#0066cc",i=e.borderRadius??8,s=n==="dark",l=s?"#1a1a1a":"#ffffff",f=s?"#ffffff":"#1a1a1a",h=e.texts||{title:"Preferences de cookies",save:"Enregistrer"},c=(e.categories||[]).map(p=>`
61
+ <label style="display: flex; align-items: flex-start; gap: 10px; margin: 15px 0; cursor: ${p.required?"not-allowed":"pointer"};">
62
62
  <input
63
63
  type="checkbox"
64
- name="${d.id}"
65
- ${t[d.id]?"checked":""}
66
- ${d.required?"disabled checked":""}
64
+ name="${p.id}"
65
+ ${t[p.id]?"checked":""}
66
+ ${p.required?"disabled checked":""}
67
67
  style="width: 18px; height: 18px; margin-top: 2px; accent-color: ${r};"
68
68
  />
69
69
  <div style="flex: 1;">
70
- <strong style="opacity: ${d.required?"0.6":"1"};">
71
- ${d.name}${d.required?" (requis)":""}
70
+ <strong style="opacity: ${p.required?"0.6":"1"};">
71
+ ${p.name}${p.required?" (requis)":""}
72
72
  </strong>
73
73
  <p style="margin: 5px 0 0 0; font-size: 13px; opacity: 0.8;">
74
- ${d.description}
74
+ ${p.description}
75
75
  </p>
76
76
  </div>
77
77
  </label>
@@ -127,8 +127,8 @@
127
127
  </form>
128
128
  </div>
129
129
  </div>
130
- `}attachBannerEvents(){let e=document.getElementById("lynkow-consent-accept"),t=document.getElementById("lynkow-consent-reject"),o=document.getElementById("lynkow-consent-preferences");e?.addEventListener("click",()=>{this.acceptAll();}),t?.addEventListener("click",()=>{this.rejectAll();}),o?.addEventListener("click",()=>{this.showPreferences();});}attachPreferencesEvents(e){let t=document.getElementById("lynkow-consent-form"),o=document.getElementById("lynkow-consent-close"),r=document.getElementById("lynkow-consent-preferences-modal");t?.addEventListener("submit",i=>{i.preventDefault();let s=new FormData(t),l={necessary:true,analytics:s.has("analytics"),marketing:s.has("marketing"),preferences:s.has("preferences")};this.setCategories(l),this.hide(),this.preferencesElement?.remove(),this.preferencesElement=null;}),o?.addEventListener("click",()=>{this.preferencesElement?.remove(),this.preferencesElement=null;}),r?.addEventListener("click",i=>{i.target===r&&(this.preferencesElement?.remove(),this.preferencesElement=null);});}destroy(){this.hide(),this.preferencesElement?.remove(),this.preferencesElement=null;}};var w="lynkow-badge",X="lynkow-badge-styles",he=`
131
- #${w} {
130
+ `}attachBannerEvents(){let e=document.getElementById("lynkow-consent-accept"),t=document.getElementById("lynkow-consent-reject"),n=document.getElementById("lynkow-consent-preferences");e?.addEventListener("click",()=>{this.acceptAll();}),t?.addEventListener("click",()=>{this.rejectAll();}),n?.addEventListener("click",()=>{this.showPreferences();});}attachPreferencesEvents(e){let t=document.getElementById("lynkow-consent-form"),n=document.getElementById("lynkow-consent-close"),r=document.getElementById("lynkow-consent-preferences-modal");t?.addEventListener("submit",i=>{i.preventDefault();let s=new FormData(t),l={necessary:true,analytics:s.has("analytics"),marketing:s.has("marketing"),preferences:s.has("preferences")};this.setCategories(l),this.hide(),this.preferencesElement?.remove(),this.preferencesElement=null;}),n?.addEventListener("click",()=>{this.preferencesElement?.remove(),this.preferencesElement=null;}),r?.addEventListener("click",i=>{i.target===r&&(this.preferencesElement?.remove(),this.preferencesElement=null);});}destroy(){this.hide(),this.preferencesElement?.remove(),this.preferencesElement=null;}};var v="lynkow-badge",Y="lynkow-badge-styles",ye=`
131
+ #${v} {
132
132
  position: fixed;
133
133
  bottom: 16px;
134
134
  right: 16px;
@@ -145,13 +145,13 @@
145
145
  line-height: 1;
146
146
  }
147
147
 
148
- #${w}:hover {
148
+ #${v}:hover {
149
149
  opacity: 1;
150
150
  color: #fff;
151
151
  }
152
152
 
153
153
  @media (max-width: 480px) {
154
- #${w} {
154
+ #${v} {
155
155
  bottom: 10px;
156
156
  right: 10px;
157
157
  font-size: 10px;
@@ -160,16 +160,16 @@
160
160
  }
161
161
 
162
162
  @media (prefers-color-scheme: light) {
163
- #${w} {
163
+ #${v} {
164
164
  background: #f5f5f5;
165
165
  color: #666;
166
166
  }
167
167
 
168
- #${w}:hover {
168
+ #${v}:hover {
169
169
  color: #1a1a1a;
170
170
  }
171
171
  }
172
- `,q=class{badgeElement=null;injectStyles(){if(document.getElementById(X))return;let e=document.createElement("style");e.id=X,e.textContent=he,document.head.appendChild(e);}inject(){if(!a||document.getElementById(w))return;this.injectStyles();let e=document.createElement("a");e.id=w,e.href="https://www.lynkow.com?ref=badge",e.target="_blank",e.rel="noopener noreferrer",e.textContent="Powered by Lynkow",e.setAttribute("aria-label","Powered by Lynkow - Visit lynkow.com"),document.body.appendChild(e),this.badgeElement=e;}remove(){a&&(this.badgeElement?.remove(),this.badgeElement=null,document.getElementById(X)?.remove());}isVisible(){return a?document.getElementById(w)!==null:false}destroy(){this.remove();}};var Y="lynkow-enhancements-styles",ye='<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>',Ce='<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',we=`
172
+ `,K=class{badgeElement=null;injectStyles(){if(document.getElementById(Y))return;let e=document.createElement("style");e.id=Y,e.textContent=ye,document.head.appendChild(e);}inject(){if(!a||document.getElementById(v))return;this.injectStyles();let e=document.createElement("a");e.id=v,e.href="https://www.lynkow.com?ref=badge",e.target="_blank",e.rel="noopener noreferrer",e.textContent="Powered by Lynkow",e.setAttribute("aria-label","Powered by Lynkow - Visit lynkow.com"),document.body.appendChild(e),this.badgeElement=e;}remove(){a&&(this.badgeElement?.remove(),this.badgeElement=null,document.getElementById(Y)?.remove());}isVisible(){return a?document.getElementById(v)!==null:false}destroy(){this.remove();}};var Q="lynkow-enhancements-styles",Ce='<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>',ve='<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',we=`
173
173
  /*
174
174
  * Lynkow Content Enhancements
175
175
  * These styles ensure that content from the Lynkow API is displayed correctly,
@@ -285,6 +285,6 @@
285
285
  color: #1a1a1a;
286
286
  }
287
287
  }
288
- `,F=class{initialized=false;observer=null;injectStyles(){if(!a||document.getElementById(Y))return;let e=document.createElement("style");e.id=Y,e.textContent=we,document.head.appendChild(e);}async handleCopyClick(e){let t=e.closest(".code-block");if(!t)return;let o=t.querySelector("code");if(!o)return;let r=o.textContent||"";try{await navigator.clipboard.writeText(r),e.classList.add("copied"),e.innerHTML=Ce,setTimeout(()=>{e.classList.remove("copied"),e.innerHTML=ye;},2e3);}catch(i){console.error("Lynkow SDK: Failed to copy code",i);}}bindCodeBlockCopy(){if(!a)return;document.querySelectorAll("[data-copy-code]").forEach(t=>{t.dataset.lynkowBound||(t.dataset.lynkowBound="true",t.addEventListener("click",o=>{o.preventDefault(),this.handleCopyClick(t);}));});}init(){a&&(this.injectStyles(),this.bindCodeBlockCopy(),this.observer||(this.observer=new MutationObserver(e=>{let t=false;for(let o of e)if(o.addedNodes.length>0){t=true;break}t&&this.bindCodeBlockCopy();}),this.observer.observe(document.body,{childList:true,subtree:true})),this.initialized=true);}isInitialized(){return this.initialized}destroy(){a&&(this.observer&&(this.observer.disconnect(),this.observer=null),document.getElementById(Y)?.remove(),this.initialized=false);}};var ve=300*1e3,be="lynkow_cache_",v=new Map;function ne(n={}){let e=n.defaultTtl??ve,t=n.prefix??be;function o(g){return `${t}${g}`}function r(g){return Date.now()>g.expiresAt}function i(g){let c=o(g);if(a)try{let m=localStorage.getItem(c);if(!m)return null;let y=JSON.parse(m);return r(y)?(localStorage.removeItem(c),null):y.value}catch{return null}let d=v.get(c);return d?r(d)?(v.delete(c),null):d.value:null}function s(g,c,d=e){let m=o(g),y={value:c,expiresAt:Date.now()+d};if(a){try{localStorage.setItem(m,JSON.stringify(y));}catch{}return}v.set(m,y);}function l(g){let c=o(g);if(a){try{localStorage.removeItem(c);}catch{}return}v.delete(c);}function f(g){if(a){try{let c=[];for(let d=0;d<localStorage.length;d++){let m=localStorage.key(d);m&&m.startsWith(t)&&(!g||m.includes(g))&&c.push(m);}c.forEach(d=>localStorage.removeItem(d));}catch{}return}if(g)for(let c of v.keys())c.startsWith(t)&&c.includes(g)&&v.delete(c);else for(let c of v.keys())c.startsWith(t)&&v.delete(c);}async function h(g,c,d=e){let m=i(g);if(m!==null)return m;let y=await c();return s(g,y,d),y}return {get:i,set:s,remove:l,invalidate:f,getOrSet:h}}function re(n){let e=n.prefix||"[Lynkow]";return {debug(...t){n.debug&&console.debug(e,...t);},info(...t){console.info(e,...t);},warn(...t){console.warn(e,...t);},error(...t){console.error(e,...t);},log(t,...o){switch(t){case "debug":this.debug(...o);break;case "info":this.info(...o);break;case "warn":this.warn(...o);break;case "error":this.error(...o);break}}}}function se(){let n=new Map;function e(s,l){return n.has(s)||n.set(s,new Set),n.get(s).add(l),()=>t(s,l)}function t(s,l){let f=n.get(s);f&&f.delete(l);}function o(s,l){let f=n.get(s);if(f)for(let h of f)try{h(l);}catch(g){console.error(`[Lynkow] Error in event listener for "${s}":`,g);}}function r(s,l){let f=(h=>{t(s,f),l(h);});return e(s,f)}function i(s){s?n.delete(s):n.clear();}return {on:e,off:t,emit:o,once:r,removeAllListeners:i}}var ie="lynkow_locale";function ae(n,e){if(!a)return e;let t=Re();if(t&&n.includes(t))return t;let o=ke(n);if(o)return o;let r=document.documentElement.lang;if(r){let i=r.split("-")[0]?.toLowerCase();if(i&&n.includes(i))return i}return e}function Re(){if(!a)return null;try{return localStorage.getItem(ie)}catch{return null}}function ce(n){if(a)try{localStorage.setItem(ie,n);}catch{}}function ke(n){if(!a)return null;let t=window.location.pathname.split("/").filter(Boolean);if(t.length>0){let o=t[0]?.toLowerCase();if(o&&n.includes(o))return o}return null}function le(n,e){return e.includes(n)}var pe="https://api.lynkow.com";function xe(n){if(!n.siteId)throw new Error("Lynkow SDK: siteId is required");let e=ne(),t=re({debug:n.debug??false}),o=se(),r=(n.baseUrl||pe).replace(/\/$/,""),i={siteId:n.siteId,baseUrl:r,locale:n.locale,fetchOptions:n.fetchOptions||{},cache:e},s={locale:n.locale||"fr",availableLocales:["fr"],siteConfig:null,initialized:false},l={contents:new R(i),categories:new k(i),tags:new x(i),pages:new L(i),blocks:new T(i),forms:new S(i),reviews:new P(i),site:new I(i),legal:new B(i),cookies:new $(i),seo:new A(i),paths:new _(i),analytics:new U(i),consent:new H(i,o),branding:new q,enhancements:new F};function f(c){i.locale=c;}async function h(){if(!s.initialized)try{let c=await l.site.getConfig();s.siteConfig=c;let d=c.defaultLocale||"fr";if(s.availableLocales=c.enabledLocales||[d],a&&!n.locale){let m=ae(s.availableLocales,d);s.locale=m,f(m);}s.initialized=!0,t.debug("Client initialized",{locale:s.locale,availableLocales:s.availableLocales}),a&&(l.analytics.init(),l.consent.hasConsented()||l.consent.show(),c.showBranding&&l.branding.inject(),l.enhancements.init()),o.emit("ready",void 0);}catch(c){t.error("Failed to initialize client",c),o.emit("error",c);}}return a&&setTimeout(()=>h(),0),{...l,globals:l.blocks,config:Object.freeze({siteId:n.siteId,baseUrl:r,debug:n.debug??false}),get locale(){return s.locale},get availableLocales(){return [...s.availableLocales]},setLocale(c){if(!le(c,s.availableLocales)){t.warn(`Locale "${c}" is not available. Available: ${s.availableLocales.join(", ")}`);return}c!==s.locale&&(s.locale=c,f(c),a&&ce(c),e.invalidate(),o.emit("locale-changed",c),t.debug("Locale changed to",c));},clearCache(){e.invalidate(),t.debug("Cache cleared");},destroy(){l.analytics.destroy(),l.consent.destroy(),l.branding.destroy(),l.enhancements.destroy(),e.invalidate(),o.removeAllListeners(),t.debug("Client destroyed");},on(c,d){return o.on(c,d)}}}function Ee(n){if(!n.siteId)throw new Error("Lynkow SDK: siteId is required");let e={siteId:n.siteId,baseUrl:(n.baseUrl||pe).replace(/\/$/,""),locale:n.locale,fetchOptions:n.fetchOptions||{}};return {contents:new R(e),categories:new k(e),tags:new x(e),pages:new L(e),blocks:new T(e),forms:new S(e),reviews:new P(e),site:new I(e),legal:new B(e),cookies:new $(e),seo:new A(e),paths:new _(e)}}function Le(n){return n.type==="content"}function Te(n){return n.type==="category"}
289
- exports.EnhancementsService=F;exports.LynkowError=C;exports.browserOnly=me;exports.browserOnlyAsync=fe;exports.createClient=xe;exports.createLynkowClient=Ee;exports.isBrowser=a;exports.isCategoryResolve=Te;exports.isContentResolve=Le;exports.isLynkowError=de;exports.isServer=ue;//# sourceMappingURL=index.js.map
288
+ `,F=class{initialized=false;observer=null;injectStyles(){if(!a||document.getElementById(Q))return;let e=document.createElement("style");e.id=Q,e.textContent=we,document.head.appendChild(e);}async handleCopyClick(e){let t=e.closest(".code-block");if(!t)return;let n=t.querySelector("code");if(!n)return;let r=n.textContent||"";try{await navigator.clipboard.writeText(r),e.classList.add("copied"),e.innerHTML=ve,setTimeout(()=>{e.classList.remove("copied"),e.innerHTML=Ce;},2e3);}catch(i){console.error("Lynkow SDK: Failed to copy code",i);}}bindCodeBlockCopy(){if(!a)return;document.querySelectorAll("[data-copy-code]").forEach(t=>{t.dataset.lynkowBound||(t.dataset.lynkowBound="true",t.addEventListener("click",n=>{n.preventDefault(),this.handleCopyClick(t);}));});}init(){a&&(this.injectStyles(),this.bindCodeBlockCopy(),this.observer||(this.observer=new MutationObserver(e=>{let t=false;for(let n of e)if(n.addedNodes.length>0){t=true;break}t&&this.bindCodeBlockCopy();}),this.observer.observe(document.body,{childList:true,subtree:true})),this.initialized=true);}isInitialized(){return this.initialized}destroy(){a&&(this.observer&&(this.observer.disconnect(),this.observer=null),document.getElementById(Q)?.remove(),this.initialized=false);}};var D=class{srcset(e,t={}){if(!e)return "";let{widths:n=[400,800,1200,1920],fit:r="scale-down",quality:i=80,gravity:s}=t,l=this.parseImageUrl(e);return l?n.map(f=>{let h=[`w=${f}`,`fit=${r}`,"format=auto",`quality=${i}`,s&&`gravity=${s}`].filter(Boolean).join(",");return `${l.cdnBase}/cdn-cgi/image/${h}/${l.relativePath} ${f}w`}).join(", "):""}transform(e,t={}){if(!e)return "";let n=this.parseImageUrl(e);if(!n)return e||"";let r=[t.w&&`w=${t.w}`,t.h&&`h=${t.h}`,`fit=${t.fit||"scale-down"}`,`format=${t.format||"auto"}`,`quality=${t.quality||80}`,t.gravity&&`gravity=${t.gravity}`,t.dpr&&`dpr=${t.dpr}`].filter(Boolean).join(",");return `${n.cdnBase}/cdn-cgi/image/${r}/${n.relativePath}`}parseImageUrl(e){let t=e.indexOf("/cdn-cgi/image/");if(t!==-1){let i=e.substring(0,t),s=e.substring(t+15),l=s.indexOf("/");if(l===-1)return null;let f=s.substring(l+1);return {cdnBase:i,relativePath:f}}let n=e.indexOf("/sites/");if(n!==-1){let i=e.substring(0,n),s=e.substring(n+1);return {cdnBase:i,relativePath:s}}let r=e.indexOf("/avatars/");if(r!==-1){let i=e.substring(0,r),s=e.substring(r+1);return {cdnBase:i,relativePath:s}}return null}};var be=300*1e3,Re="lynkow_cache_",w=new Map;function re(o={}){let e=o.defaultTtl??be,t=o.prefix??Re;function n(u){return `${t}${u}`}function r(u){return Date.now()>u.expiresAt}function i(u){let c=n(u);if(a)try{let m=localStorage.getItem(c);if(!m)return null;let y=JSON.parse(m);return r(y)?(localStorage.removeItem(c),null):y.value}catch{return null}let p=w.get(c);return p?r(p)?(w.delete(c),null):p.value:null}function s(u,c,p=e){let m=n(u),y={value:c,expiresAt:Date.now()+p};if(a){try{localStorage.setItem(m,JSON.stringify(y));}catch{}return}w.set(m,y);}function l(u){let c=n(u);if(a){try{localStorage.removeItem(c);}catch{}return}w.delete(c);}function f(u){if(a){try{let c=[];for(let p=0;p<localStorage.length;p++){let m=localStorage.key(p);m&&m.startsWith(t)&&(!u||m.includes(u))&&c.push(m);}c.forEach(p=>localStorage.removeItem(p));}catch{}return}if(u)for(let c of w.keys())c.startsWith(t)&&c.includes(u)&&w.delete(c);else for(let c of w.keys())c.startsWith(t)&&w.delete(c);}async function h(u,c,p=e){let m=i(u);if(m!==null)return m;let y=await c();return s(u,y,p),y}return {get:i,set:s,remove:l,invalidate:f,getOrSet:h}}function se(o){let e=o.prefix||"[Lynkow]";return {debug(...t){o.debug&&console.debug(e,...t);},info(...t){console.info(e,...t);},warn(...t){console.warn(e,...t);},error(...t){console.error(e,...t);},log(t,...n){switch(t){case "debug":this.debug(...n);break;case "info":this.info(...n);break;case "warn":this.warn(...n);break;case "error":this.error(...n);break}}}}function ie(){let o=new Map;function e(s,l){return o.has(s)||o.set(s,new Set),o.get(s).add(l),()=>t(s,l)}function t(s,l){let f=o.get(s);f&&f.delete(l);}function n(s,l){let f=o.get(s);if(f)for(let h of f)try{h(l);}catch(u){console.error(`[Lynkow] Error in event listener for "${s}":`,u);}}function r(s,l){let f=(h=>{t(s,f),l(h);});return e(s,f)}function i(s){s?o.delete(s):o.clear();}return {on:e,off:t,emit:n,once:r,removeAllListeners:i}}var ae="lynkow_locale";function ce(o,e){if(!a)return e;let t=xe();if(t&&o.includes(t))return t;let n=ke(o);if(n)return n;let r=document.documentElement.lang;if(r){let i=r.split("-")[0]?.toLowerCase();if(i&&o.includes(i))return i}return e}function xe(){if(!a)return null;try{return localStorage.getItem(ae)}catch{return null}}function le(o){if(a)try{localStorage.setItem(ae,o);}catch{}}function ke(o){if(!a)return null;let t=window.location.pathname.split("/").filter(Boolean);if(t.length>0){let n=t[0]?.toLowerCase();if(n&&o.includes(n))return n}return null}function de(o,e){return e.includes(o)}var pe="https://api.lynkow.com";function Ee(o){if(!o.siteId)throw new Error("Lynkow SDK: siteId is required");let e=re(),t=se({debug:o.debug??false}),n=ie(),r=(o.baseUrl||pe).replace(/\/$/,""),i={siteId:o.siteId,baseUrl:r,locale:o.locale,fetchOptions:o.fetchOptions||{},cache:e},s={locale:o.locale||"fr",availableLocales:["fr"],siteConfig:null,initialized:false},l={contents:new R(i),categories:new x(i),tags:new k(i),pages:new L(i),blocks:new T(i),forms:new S(i),reviews:new P(i),site:new I(i),legal:new B(i),cookies:new $(i),seo:new A(i),paths:new _(i),analytics:new q(i),consent:new U(i,n),branding:new K,enhancements:new F,media:new D};function f(c){i.locale=c;}async function h(){if(!s.initialized)try{let c=await l.site.getConfig();s.siteConfig=c;let p=c.defaultLocale||"fr";if(s.availableLocales=c.enabledLocales||[p],a&&!o.locale){let m=ce(s.availableLocales,p);s.locale=m,f(m);}s.initialized=!0,t.debug("Client initialized",{locale:s.locale,availableLocales:s.availableLocales}),a&&(l.analytics.init(),l.consent.hasConsented()||l.consent.show(),c.showBranding&&l.branding.inject(),l.enhancements.init()),n.emit("ready",void 0);}catch(c){t.error("Failed to initialize client",c),n.emit("error",c);}}return a&&setTimeout(()=>h(),0),{...l,globals:l.blocks,config:Object.freeze({siteId:o.siteId,baseUrl:r,debug:o.debug??false}),get locale(){return s.locale},get availableLocales(){return [...s.availableLocales]},setLocale(c){if(!de(c,s.availableLocales)){t.warn(`Locale "${c}" is not available. Available: ${s.availableLocales.join(", ")}`);return}c!==s.locale&&(s.locale=c,f(c),a&&le(c),e.invalidate(),n.emit("locale-changed",c),t.debug("Locale changed to",c));},clearCache(){e.invalidate(),t.debug("Cache cleared");},destroy(){l.analytics.destroy(),l.consent.destroy(),l.branding.destroy(),l.enhancements.destroy(),e.invalidate(),n.removeAllListeners(),t.debug("Client destroyed");},on(c,p){return n.on(c,p)}}}function Le(o){if(!o.siteId)throw new Error("Lynkow SDK: siteId is required");let e={siteId:o.siteId,baseUrl:(o.baseUrl||pe).replace(/\/$/,""),locale:o.locale,fetchOptions:o.fetchOptions||{}};return {contents:new R(e),categories:new x(e),tags:new k(e),pages:new L(e),blocks:new T(e),forms:new S(e),reviews:new P(e),site:new I(e),legal:new B(e),cookies:new $(e),seo:new A(e),paths:new _(e)}}function Te(o){return o.type==="content"}function Se(o){return o.type==="category"}
289
+ exports.EnhancementsService=F;exports.LynkowError=C;exports.MediaHelperService=D;exports.browserOnly=me;exports.browserOnlyAsync=he;exports.createClient=Ee;exports.createLynkowClient=Le;exports.isBrowser=a;exports.isCategoryResolve=Se;exports.isContentResolve=Te;exports.isLynkowError=ue;exports.isServer=fe;//# sourceMappingURL=index.js.map
290
290
  //# sourceMappingURL=index.js.map