@crayonscodetech/cms-sdk 1.0.9 → 1.0.11
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 +11 -8
- package/dist/index.cjs +40 -17
- package/dist/index.d.cts +42 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +42 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +41 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -777,11 +777,11 @@ Different page types follow different rendering strategies. Understanding these
|
|
|
777
777
|
| `[[...slug]]` CMS pages | `page` (+ inline `page.sections`) | `fetchPageByUrl(siteId, urlPath)` |
|
|
778
778
|
| `/about` | `page` + `about-us` | `fetchPageByUrl(siteId, "/about")` + `fetchAboutUs(siteId)` |
|
|
779
779
|
| `/services` | `page` + `services` | `fetchPageByUrl(siteId, "/services")` + `fetchServices(siteId)` |
|
|
780
|
-
| `/services/[slug]` | `services` | `
|
|
780
|
+
| `/services/[slug]` | `services` | `fetchServiceBySlug(siteId, slug)` |
|
|
781
781
|
| `/blog` or `/news` | `page` + `blog` | `fetchPageByUrl(siteId, "/blog")` (or your CMS-defined base url) + `fetchBlogs(siteId, params)` |
|
|
782
782
|
| `/blog/[slug]` | `blog` | `fetchBlogBySlug(siteId, slug)` |
|
|
783
783
|
| `/events` | `page` + `events` | `fetchPageByUrl(siteId, "/events")` + `fetchEvents(siteId, params)` |
|
|
784
|
-
| `/events/[slug]` | `events` | `
|
|
784
|
+
| `/events/[slug]` | `events` | `fetchEventBySlug(siteId, slug)` |
|
|
785
785
|
| `/gallery` | `page` + `albums` | `fetchPageByUrl(siteId, "/gallery")` + `fetchAlbums(siteId, params)` |
|
|
786
786
|
| `/gallery/[slug]` | `albums` + `album-items` | `fetchAlbums(siteId, { limit })` + `fetchAlbumItems(siteId, { album: slug })` |
|
|
787
787
|
| `/team/[slug]` | `team-members` | `fetchTeamMembers(siteId)` (slug lookup) or custom `fetch` |
|
|
@@ -2663,13 +2663,13 @@ export interface FetchOptions extends RequestInit {
|
|
|
2663
2663
|
|
|
2664
2664
|
### Other Entities
|
|
2665
2665
|
|
|
2666
|
-
- `fetchServices(siteId, options?)`: Returns
|
|
2667
|
-
- `
|
|
2666
|
+
- `fetchServices(siteId, params?, options?)`: Returns paginated services. Params: `{ page, limit }`. Only published services are returned — the backend filters on `is_published`, and each item carries `is_published` plus a nullable `published_at`.
|
|
2667
|
+
- `fetchServiceBySlug(siteId, slug, options?)`: Returns a single published service by slug, including its `extra.sections`. Returns `null` if not found or unpublished.
|
|
2668
2668
|
- `fetchTeamMembers(siteId, params?, options?)`: Returns paginated team members. Params: `{ page, limit }`. Default limit: 20.
|
|
2669
2669
|
- `fetchTeamMembersByCategory(siteId, params, options?)`: Returns paginated team members filtered by category. Params: `{ categoryId, page?, limit? }`. Default limit: 20. **Note:** `categoryId` is now inside the params object.
|
|
2670
2670
|
- `fetchTestimonials(siteId, params?, options?)`: Returns paginated testimonials. Params: `{ type?, page?, limit? }`. Default limit: 20.
|
|
2671
2671
|
- `fetchEvents(siteId, params?, options?)`: Returns paginated events. Params: `{ page, limit, search }`.
|
|
2672
|
-
- `
|
|
2672
|
+
- `fetchEventBySlug(siteId, slug, options?)`: Returns a single published event by slug. Returns `null` if not found or unpublished.
|
|
2673
2673
|
- `fetchAlbums(siteId, params?, options?)`: Returns paginated albums. Params: `{ page, limit, search }`.
|
|
2674
2674
|
- `fetchAlbumItems(siteId, params, options?)`: Returns paginated items for an album. Params: `{ album?, album_id?, page?, limit? }`. Default limit: 20.
|
|
2675
2675
|
|
|
@@ -2709,7 +2709,7 @@ export interface FetchOptions extends RequestInit {
|
|
|
2709
2709
|
}
|
|
2710
2710
|
```
|
|
2711
2711
|
- **Attachments** (optional): `File[]`. Sending them switches the request to multipart.
|
|
2712
|
-
Caps, enforced server-side and pre-checked client-side: max 3 files,
|
|
2712
|
+
Caps, enforced server-side and pre-checked client-side: max 3 files, 3 MiB total, and a
|
|
2713
2713
|
MIME allowlist (PDF, PNG, JPEG, WebP, GIF, plain text, DOC, DOCX).
|
|
2714
2714
|
- **Throws `CmsError` instead of returning `null`.** Unlike the read methods, a form needs
|
|
2715
2715
|
to distinguish rejection kinds, so failures throw with `error.status`:
|
|
@@ -2733,8 +2733,9 @@ export interface FetchOptions extends RequestInit {
|
|
|
2733
2733
|
|
|
2734
2734
|
> All store methods use the `/api/public/store/` API prefix, not `/api/public/cms/`.
|
|
2735
2735
|
|
|
2736
|
-
- `
|
|
2737
|
-
- `
|
|
2736
|
+
- `fetchStoreSettings(siteId, options?)`: Returns `{ currency, price_visibility, is_store_enabled }`. Fetch this first — when `price_visibility` is false the API strips `price`, `sale_price` and `cost_price` from every variant, so the storefront must render an inquiry flow rather than prices.
|
|
2737
|
+
- `fetchProductCategories(siteId, params?, options?)`: Returns paginated product categories. Params: `{ page, limit, search, ordering, parent_id }`.
|
|
2738
|
+
- `fetchProductBrands(siteId, params?, options?)`: Returns paginated product brands. Params: `{ page, limit, search, ordering }`.
|
|
2738
2739
|
- `fetchProducts(siteId, params?, options?)`: Returns paginated products. Params: `{ page, limit, search, category_id, tag_id, brand_id, is_featured }`.
|
|
2739
2740
|
- `category_id` is hierarchy-aware on the backend and includes child/grandchild categories.
|
|
2740
2741
|
- `fetchProductDetail(siteId, slug, options?)`: Returns a single product by slug, **including `variants`**.
|
|
@@ -2743,7 +2744,9 @@ export interface FetchOptions extends RequestInit {
|
|
|
2743
2744
|
- Params: `{ page, limit, category_id }`
|
|
2744
2745
|
- Works for both manual and smart collections
|
|
2745
2746
|
- `fetchCollectionDetailById(siteId, id, params?, options?)`: Same as `fetchCollectionDetail`, but keyed by collection ID for CMS-driven product sections.
|
|
2747
|
+
- `fetchProductsByTag(siteId, tag, params?, options?)`: Returns paginated products carrying a tag. Params: `{ page, limit }`.
|
|
2746
2748
|
- `placeOrder(siteId, payload, options?)`: Places an order. Call from a server API route — never client-side.
|
|
2749
|
+
- `metadata` on the payload must be a **flat `Record<string, string>`** — the API validates it on a strict schema, so nested objects, numbers and arrays are rejected with a 400.
|
|
2747
2750
|
|
|
2748
2751
|
---
|
|
2749
2752
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#region src/constants/pageTypes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Page type identifiers. Mirrors cms-backend/src/constants/pageTypes.ts.
|
|
5
|
+
*
|
|
6
|
+
* `pageTypes` are the singleton types — a site may have at most one page of
|
|
7
|
+
* each, enforced on create by the backend (cms/page/page.routes.ts). Attempting
|
|
8
|
+
* a second one is rejected with "A page with type "<type>" already exists for
|
|
9
|
+
* this site". `custom` is the only repeatable type.
|
|
10
|
+
*/
|
|
3
11
|
const pageTypes = [
|
|
4
12
|
"home",
|
|
5
13
|
"about",
|
|
6
|
-
"contact"
|
|
7
|
-
];
|
|
8
|
-
const defaultPageTypes = [
|
|
9
|
-
...pageTypes,
|
|
10
|
-
"services",
|
|
11
|
-
"blog",
|
|
12
|
-
"team",
|
|
13
|
-
"gallery",
|
|
14
|
-
"events"
|
|
15
|
-
];
|
|
16
|
-
const allPageTypes = [
|
|
17
|
-
...pageTypes,
|
|
18
|
-
"custom",
|
|
14
|
+
"contact",
|
|
19
15
|
"services",
|
|
20
16
|
"blog",
|
|
21
17
|
"team",
|
|
22
18
|
"gallery",
|
|
23
|
-
"events"
|
|
19
|
+
"events",
|
|
20
|
+
"clients-partners",
|
|
21
|
+
"testimonial",
|
|
22
|
+
"faq"
|
|
24
23
|
];
|
|
24
|
+
/** The full set accepted by the backend's page validator. */
|
|
25
|
+
const allPageTypes = [...pageTypes, "custom"];
|
|
25
26
|
//#endregion
|
|
26
27
|
//#region src/constants/index.ts
|
|
27
28
|
const PAGINATION = {
|
|
@@ -84,7 +85,16 @@ const MEDIA = {
|
|
|
84
85
|
//#region src/types/contact.ts
|
|
85
86
|
/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */
|
|
86
87
|
const MAX_CONTACT_ATTACHMENTS = 3;
|
|
87
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Total attachment budget, measured on RAW bytes.
|
|
90
|
+
*
|
|
91
|
+
* Attachments are forwarded onto the notification email, so the ceiling is
|
|
92
|
+
* Cloudflare Email's 5 MiB message limit — but the wire format is base64, 4/3
|
|
93
|
+
* the size. 3 MiB raw leaves headroom; 4 MiB encoded to ~5.33 MiB and was
|
|
94
|
+
* already over. Keep in step with MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES in
|
|
95
|
+
* cms-backend/src/constants/limits.ts.
|
|
96
|
+
*/
|
|
97
|
+
const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES = 3145728;
|
|
88
98
|
const CONTACT_ATTACHMENT_MIME_ALLOWLIST = [
|
|
89
99
|
"application/pdf",
|
|
90
100
|
"image/png",
|
|
@@ -245,6 +255,19 @@ function createCmsClient(config) {
|
|
|
245
255
|
...options
|
|
246
256
|
});
|
|
247
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* The site's single published page of a given type, with its sections — the
|
|
260
|
+
* same payload as `fetchPageByUrl`. Prefer this when you know which kind of
|
|
261
|
+
* page you want but not its url, since an editor can rename the url at any
|
|
262
|
+
* time. Returns null when the site has no published page of that type.
|
|
263
|
+
*/
|
|
264
|
+
async function fetchPageByType(siteId, pageType, options) {
|
|
265
|
+
return cmsFetch(`/api/public/cms/${siteId}/page/by-type/${encodeURIComponent(pageType)}/`, {
|
|
266
|
+
revalidate: CACHE.SHORT,
|
|
267
|
+
tags: ["pages", `page-type-${pageType}`],
|
|
268
|
+
...options
|
|
269
|
+
});
|
|
270
|
+
}
|
|
248
271
|
function fetchAboutUs(siteId, options) {
|
|
249
272
|
return cmsFetch(`/api/public/cms/${siteId}/about-us/`, {
|
|
250
273
|
revalidate: CACHE.MEDIUM,
|
|
@@ -398,7 +421,7 @@ function createCmsClient(config) {
|
|
|
398
421
|
const url = `${baseUrl}/api/public/cms/${siteId}/contact/`;
|
|
399
422
|
if (attachments?.length) {
|
|
400
423
|
if (attachments.length > 3) throw new CmsError(`At most 3 attachments are allowed`, 400, url);
|
|
401
|
-
if (attachments.reduce((sum, f) => sum + f.size, 0) >
|
|
424
|
+
if (attachments.reduce((sum, f) => sum + f.size, 0) > 3145728) throw new CmsError(`Attachments exceed the ${MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES / 1048576} MiB total size limit`, 400, url);
|
|
402
425
|
for (const f of attachments) if (!CONTACT_ATTACHMENT_MIME_ALLOWLIST.includes(f.type)) throw new CmsError(`Attachment type not allowed: ${f.type || "unknown"}`, 400, url);
|
|
403
426
|
}
|
|
404
427
|
let body;
|
|
@@ -665,6 +688,7 @@ function createCmsClient(config) {
|
|
|
665
688
|
fetchSiteConfig,
|
|
666
689
|
fetchPages,
|
|
667
690
|
fetchPageByUrl,
|
|
691
|
+
fetchPageByType,
|
|
668
692
|
fetchAboutUs,
|
|
669
693
|
fetchServices,
|
|
670
694
|
fetchServiceBySlug,
|
|
@@ -833,5 +857,4 @@ exports.PAGINATION = PAGINATION;
|
|
|
833
857
|
exports.SEARCH = SEARCH;
|
|
834
858
|
exports.allPageTypes = allPageTypes;
|
|
835
859
|
exports.createCmsClient = createCmsClient;
|
|
836
|
-
exports.defaultPageTypes = defaultPageTypes;
|
|
837
860
|
exports.pageTypes = pageTypes;
|
package/dist/index.d.cts
CHANGED
|
@@ -96,10 +96,18 @@ interface SiteConfig {
|
|
|
96
96
|
}
|
|
97
97
|
//#endregion
|
|
98
98
|
//#region src/constants/pageTypes.d.ts
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Page type identifiers. Mirrors cms-backend/src/constants/pageTypes.ts.
|
|
101
|
+
*
|
|
102
|
+
* `pageTypes` are the singleton types — a site may have at most one page of
|
|
103
|
+
* each, enforced on create by the backend (cms/page/page.routes.ts). Attempting
|
|
104
|
+
* a second one is rejected with "A page with type "<type>" already exists for
|
|
105
|
+
* this site". `custom` is the only repeatable type.
|
|
106
|
+
*/
|
|
107
|
+
declare const pageTypes: readonly ["home", "about", "contact", "services", "blog", "team", "gallery", "events", "clients-partners", "testimonial", "faq"];
|
|
108
|
+
/** The full set accepted by the backend's page validator. */
|
|
109
|
+
declare const allPageTypes: readonly ["home", "about", "contact", "services", "blog", "team", "gallery", "events", "clients-partners", "testimonial", "faq", "custom"];
|
|
110
|
+
type PageType = (typeof allPageTypes)[number];
|
|
103
111
|
//#endregion
|
|
104
112
|
//#region src/types/cms-page.d.ts
|
|
105
113
|
interface CTA {
|
|
@@ -488,7 +496,10 @@ interface Category {
|
|
|
488
496
|
slug: string;
|
|
489
497
|
description?: string | null;
|
|
490
498
|
order: number;
|
|
491
|
-
|
|
499
|
+
seo?: ProductSEO | null;
|
|
500
|
+
extra?: (Record<string, unknown> & {
|
|
501
|
+
sections?: Section[];
|
|
502
|
+
}) | null;
|
|
492
503
|
created_at: string;
|
|
493
504
|
updated_at: string;
|
|
494
505
|
}
|
|
@@ -535,7 +546,9 @@ interface Album {
|
|
|
535
546
|
created_at: string;
|
|
536
547
|
updated_at: string;
|
|
537
548
|
items?: AlbumItem[];
|
|
538
|
-
extra?: Record<string, unknown>
|
|
549
|
+
extra?: (Record<string, unknown> & {
|
|
550
|
+
sections?: Section[];
|
|
551
|
+
}) | null;
|
|
539
552
|
}
|
|
540
553
|
interface AlbumItem {
|
|
541
554
|
id: string;
|
|
@@ -559,7 +572,10 @@ interface BrandGroup {
|
|
|
559
572
|
order: number;
|
|
560
573
|
created_at: string;
|
|
561
574
|
updated_at: string;
|
|
562
|
-
|
|
575
|
+
seo?: ProductSEO | null;
|
|
576
|
+
extra?: (Record<string, unknown> & {
|
|
577
|
+
sections?: Section[];
|
|
578
|
+
}) | null;
|
|
563
579
|
brands?: Brand[];
|
|
564
580
|
}
|
|
565
581
|
interface Brand {
|
|
@@ -611,6 +627,7 @@ interface Event {
|
|
|
611
627
|
location_name?: string | null;
|
|
612
628
|
address?: string | null;
|
|
613
629
|
link?: string | null;
|
|
630
|
+
link_text?: string | null;
|
|
614
631
|
image_url?: string | null;
|
|
615
632
|
image_alt?: string | null;
|
|
616
633
|
description?: string | null;
|
|
@@ -650,6 +667,10 @@ interface FaqGroup {
|
|
|
650
667
|
description: string | null;
|
|
651
668
|
order: number;
|
|
652
669
|
faqs: Faq[];
|
|
670
|
+
seo?: ProductSEO | null;
|
|
671
|
+
extra?: {
|
|
672
|
+
sections: Section[];
|
|
673
|
+
} | null;
|
|
653
674
|
created_at: string;
|
|
654
675
|
updated_at: string;
|
|
655
676
|
}
|
|
@@ -727,6 +748,15 @@ interface PublicContactConfig {
|
|
|
727
748
|
}
|
|
728
749
|
/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */
|
|
729
750
|
declare const MAX_CONTACT_ATTACHMENTS = 3;
|
|
751
|
+
/**
|
|
752
|
+
* Total attachment budget, measured on RAW bytes.
|
|
753
|
+
*
|
|
754
|
+
* Attachments are forwarded onto the notification email, so the ceiling is
|
|
755
|
+
* Cloudflare Email's 5 MiB message limit — but the wire format is base64, 4/3
|
|
756
|
+
* the size. 3 MiB raw leaves headroom; 4 MiB encoded to ~5.33 MiB and was
|
|
757
|
+
* already over. Keep in step with MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES in
|
|
758
|
+
* cms-backend/src/constants/limits.ts.
|
|
759
|
+
*/
|
|
730
760
|
declare const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES: number;
|
|
731
761
|
declare const CONTACT_ATTACHMENT_MIME_ALLOWLIST: readonly string[];
|
|
732
762
|
//#endregion
|
|
@@ -907,7 +937,9 @@ interface PlaceOrderPayload {
|
|
|
907
937
|
customer_phone?: string | null;
|
|
908
938
|
notes?: string | null;
|
|
909
939
|
discount?: number | null;
|
|
910
|
-
|
|
940
|
+
/** Flat string map only — the API validates `Record<string, string>` on a
|
|
941
|
+
* strict schema, so nested objects, numbers and arrays are rejected (400). */
|
|
942
|
+
metadata?: Record<string, string>;
|
|
911
943
|
}
|
|
912
944
|
interface CartItem {
|
|
913
945
|
variant: ProductVariant;
|
|
@@ -1025,6 +1057,7 @@ declare function createCmsClient(config: CmsClientConfig): {
|
|
|
1025
1057
|
page?: number;
|
|
1026
1058
|
}, options?: FetchOptions) => Promise<PaginatedResponse<PageListItem>>;
|
|
1027
1059
|
fetchPageByUrl: (siteId: string, urlPath: string, options?: FetchOptions) => Promise<Page | null>;
|
|
1060
|
+
fetchPageByType: (siteId: string, pageType: PageType, options?: FetchOptions) => Promise<Page | null>;
|
|
1028
1061
|
fetchAboutUs: (siteId: string, options?: FetchOptions) => Promise<AboutUsData | null>;
|
|
1029
1062
|
fetchServices: (siteId: string, params?: {
|
|
1030
1063
|
page?: number;
|
|
@@ -1287,5 +1320,5 @@ interface UpdateSitePayload {
|
|
|
1287
1320
|
declare const ICON_NAMES: readonly ["Home", "User", "Settings", "Mail", "Bell", "Calendar", "Star", "Heart", "Bookmark", "Search", "Filter", "Download", "Upload", "Trash", "Edit", "Plus", "Minus", "Check", "X", "ChevronRight", "ChevronLeft", "ChevronUp", "ChevronDown", "ChevronsUpDown", "ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown", "File", "Folder", "Image", "Video", "Music", "Lock", "Unlock", "Eye", "EyeOff", "Sun", "Moon", "Cloud", "Zap", "Activity", "TrendingUp", "TrendingDown", "BarChart", "PieChart", "Database", "Server", "Wifi", "Battery", "Camera", "Mic", "Phone", "MessageSquare", "Send", "Share", "Link", "ExternalLink", "Globe", "MapPin", "Users", "ShoppingCart", "CreditCard", "Package", "Briefcase", "Target", "Flag", "Clipboard", "List", "Grid", "Layout", "Layers", "Copy", "Save", "RefreshCw", "Maximize", "Code", "AlertCircle", "Info", "HelpCircle", "CheckCircle", "XCircle", "Menu", "MoreVertical", "MoreHorizontal", "PlayCircle", "PauseCircle", "LogIn", "LogOut", "UserPlus", "UserMinus", "Tag", "Award", "Gift", "Truck", "Clock", "Handshake", "Stethoscope", "Microscope", "GraduationCap", "BookOpen", "Building2", "Trees", "HeartHandshake", "Brain", "Lightbulb"];
|
|
1288
1321
|
type IconName = (typeof ICON_NAMES)[number];
|
|
1289
1322
|
//#endregion
|
|
1290
|
-
export { ANIMATION, APIResponse, AboutSection, AboutStat, AboutUsData, AboutValue, Album, AlbumGroupSection, AlbumItem, Blog, BlogSection, Brand, BrandGroup, Branding, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CTA, CTAContent, CartItem, Category, ClientsSection, CmsClientConfig, CmsError, Collection, CollectionDetail, CollectionGroupSection, CollectionItem, CollectionListItem, CompanyInfo, Contact, ContactConfig, ContactPayload, CreateSitePayload, Cta, CustomContent, Event, Faq, FaqGroup, FaqSection, FetchOptions, Footer, FooterNavChild, FooterNavGroup, FooterNavGroupLink, GallerySection, GenericSection, HTTP_STATUS, Header, HeroContent, HistoryItem, HistorySection, ICON_NAMES, IconName, Image, LocationConfig, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, MarqueeItem, MarqueeSection, MultiValueItem, MultiValueSection, NavChild, NavGrandChild, NavLink, Order, OrderItem, OrderStatus, PAGINATION, Page, PageListItem, PageType, PaginatedResponse, PaginationInfo, PaginationMeta, PlaceOrderPayload, Product, ProductBrand, ProductCategory, ProductExtraData, ProductImage, ProductListItem, ProductSEO, ProductSectionFilter, ProductStatus, ProductVariant, ProductVariantListItem, ProductsSection, PublicContactConfig, PublicProductVariant, Redirect, Redirect404Log, RedirectStatusCode, ResolvedRedirect, RichContentSection, SEARCH, SEO, Section, Service, ServicesSection, ShippingAddress, SingleDataAPIResponse, Site, SiteConfig, SitemapAlbumItem, SitemapBlogItem, SitemapBrandGroupItem, SitemapCollectionItem, SitemapEventItem, SitemapItem, SitemapPageItem, SitemapProductBrandItem, SitemapProductCategoryItem, SitemapProductItem, SitemapResource, SitemapResourceMap, SitemapServiceItem, SitemapTeamCategoryItem, SitemapTeamMemberItem, Social, SocialLink, StoreSettings, TeamMember, TeamSection, Testimonial, TestimonialsSection, UpdateSitePayload, UserSiteRole, WorkingHours, allPageTypes, createCmsClient,
|
|
1323
|
+
export { ANIMATION, APIResponse, AboutSection, AboutStat, AboutUsData, AboutValue, Album, AlbumGroupSection, AlbumItem, Blog, BlogSection, Brand, BrandGroup, Branding, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CTA, CTAContent, CartItem, Category, ClientsSection, CmsClientConfig, CmsError, Collection, CollectionDetail, CollectionGroupSection, CollectionItem, CollectionListItem, CompanyInfo, Contact, ContactConfig, ContactPayload, CreateSitePayload, Cta, CustomContent, Event, Faq, FaqGroup, FaqSection, FetchOptions, Footer, FooterNavChild, FooterNavGroup, FooterNavGroupLink, GallerySection, GenericSection, HTTP_STATUS, Header, HeroContent, HistoryItem, HistorySection, ICON_NAMES, IconName, Image, LocationConfig, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, MarqueeItem, MarqueeSection, MultiValueItem, MultiValueSection, NavChild, NavGrandChild, NavLink, Order, OrderItem, OrderStatus, PAGINATION, Page, PageListItem, PageType, PaginatedResponse, PaginationInfo, PaginationMeta, PlaceOrderPayload, Product, ProductBrand, ProductCategory, ProductExtraData, ProductImage, ProductListItem, ProductSEO, ProductSectionFilter, ProductStatus, ProductVariant, ProductVariantListItem, ProductsSection, PublicContactConfig, PublicProductVariant, Redirect, Redirect404Log, RedirectStatusCode, ResolvedRedirect, RichContentSection, SEARCH, SEO, Section, Service, ServicesSection, ShippingAddress, SingleDataAPIResponse, Site, SiteConfig, SitemapAlbumItem, SitemapBlogItem, SitemapBrandGroupItem, SitemapCollectionItem, SitemapEventItem, SitemapItem, SitemapPageItem, SitemapProductBrandItem, SitemapProductCategoryItem, SitemapProductItem, SitemapResource, SitemapResourceMap, SitemapServiceItem, SitemapTeamCategoryItem, SitemapTeamMemberItem, Social, SocialLink, StoreSettings, TeamMember, TeamSection, Testimonial, TestimonialsSection, UpdateSitePayload, UserSiteRole, WorkingHours, allPageTypes, createCmsClient, pageTypes };
|
|
1291
1324
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/pagination.ts","../src/types/header.ts","../src/types/footer.ts","../src/types/site-config.ts","../src/constants/pageTypes.ts","../src/types/cms-page.ts","../src/types/about.ts","../src/types/seo.ts","../src/types/service.ts","../src/types/blog.ts","../src/types/category.ts","../src/types/team-member.ts","../src/types/album.ts","../src/types/brand.ts","../src/types/testimonials.ts","../src/types/event.ts","../src/types/faq.ts","../src/types/faq-group.ts","../src/types/redirect.ts","../src/types/contact.ts","../src/types/product.ts","../src/types/product-category.ts","../src/types/product-brand.ts","../src/types/collection.ts","../src/types/order.ts","../src/types/store-setting.ts","../src/types/sitemap.ts","../src/core/client.ts","../src/constants/index.ts","../src/types/api-response.ts","../src/types/company-info.ts","../src/types/site.ts","../src/types/icon.ts"],"mappings":";UAAiB;EACf;EACA;EACA;;KAIU,iBAAiB;UAEZ,kBAAkB;EACjC,MAAM;EACN,YAAY;;;;UCXG;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;EACX,MAAM;EACN,OAAO;;;;UC3BQ;EACf;EACA;;UAGe;EACf;EACA;EACA,UAAU;;UAGK;EACf;EACA,OAAO;;UAGQ;EACf;EACA;EACA,YAAY;EACZ,OAAO;;;;UCpBQ;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAWe;EACf;EACA;EACA,SAAS;EACT,WAAW;EACX,gBAAgB;;UAGD;EACf;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/pagination.ts","../src/types/header.ts","../src/types/footer.ts","../src/types/site-config.ts","../src/constants/pageTypes.ts","../src/types/cms-page.ts","../src/types/about.ts","../src/types/seo.ts","../src/types/service.ts","../src/types/blog.ts","../src/types/category.ts","../src/types/team-member.ts","../src/types/album.ts","../src/types/brand.ts","../src/types/testimonials.ts","../src/types/event.ts","../src/types/faq.ts","../src/types/faq-group.ts","../src/types/redirect.ts","../src/types/contact.ts","../src/types/product.ts","../src/types/product-category.ts","../src/types/product-brand.ts","../src/types/collection.ts","../src/types/order.ts","../src/types/store-setting.ts","../src/types/sitemap.ts","../src/core/client.ts","../src/constants/index.ts","../src/types/api-response.ts","../src/types/company-info.ts","../src/types/site.ts","../src/types/icon.ts"],"mappings":";UAAiB;EACf;EACA;EACA;;KAIU,iBAAiB;UAEZ,kBAAkB;EACjC,MAAM;EACN,YAAY;;;;UCXG;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;EACX,MAAM;EACN,OAAO;;;;UC3BQ;EACf;EACA;;UAGe;EACf;EACA;EACA,UAAU;;UAGK;EACf;EACA,OAAO;;UAGQ;EACf;EACA;EACA,YAAY;EACZ,OAAO;;;;UCpBQ;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAWe;EACf;EACA;EACA,SAAS;EACT,WAAW;EACX,gBAAgB;;UAGD;EACf;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;;;;;;;;;;;;cCtCE;;cAeA;KAED,mBAAmB;;;UCvBd;EACf;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,KAAK;EACL;EACA;IACE;IACA;;;UAIa;EACf;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;IACN;IACA;IACA;IACA;IACA;;;UAIa;EACf;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe,oBAAoB;EACnC;EACA;;UAGe,uBAAuB;EACtC;;UAGe,mBAAmB;EAClC;;UAGe,oBAAoB;EACnC;;UAGe,uBAAuB;EACtC;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,KAAK;;UAGU;EACf;EACA;EACA,OAAO;EACP,MAAM,QAAQ;EACd;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,QAAQ;EACR,QAAQ;;UAGO;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA,OAAO;;KAGG;UAEK;EACf;EACA;EACA;EACA,SAAS;EACT;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;KAGU;EACN;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAgB,SAAS;;EAC9D;EAAY;EAAyB;EAAa,SAAS;;EAC3D;EAAY;EAAyB;EAAqB,SAAS;;EACnE;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAqB,SAAS;;EACnE;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAe,SAAS;;EAC7D;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAsB,SAAS;;EACpE;EAAY;EAAyB;EAAe,SAAS;;EAC7D;EAAY;EAAyB;EAAa,SAAS;;EAC3D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAkB,SAAS;;EAEhE;EACA;EACA;EACA,SAAS;;EAGT;EACA;EACA;EACA,SAAS;;UAGE;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA,UAAU;EACV,WAAW;EACX;EACA,KAAK;EACL,UAAU;EACV,QAAQ;EACR;EACA;;KAIU,eAAe,KAAK;;;UCrPf;EACf;IAAU;IAAc;;EACxB;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;;;;UCzBO;EACf;EACA;EACA;EACA;;UAGe,yBAAyB;;;UCJzB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL;IACE,UAAU;;;;;UCrBG;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE,UAAU;IACV;MACE;MACA;MACA;;;;;;UCzBW;EACf;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;IAA4B,WAAW;;EAChD;EACA;;;;UCbe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA,QAAQ;EACR;EACA;;;;UCnBe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,SAAS;IAA4B,WAAW;;;UAGjC;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC3Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;IAA4B,WAAW;;EAChD,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC5Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OAAO;;;;UCdQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE,UAAU;;;;;UCjCG;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UCJe;EACf;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,MAAM;EACN;IACE,UAAU;;EAEZ;EACA;;;;KChBU;UAEK;EACf;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA;EACA;;UAGe;EACf,UAAU;EACV;EACA,QAAQ;EACR;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC7Be;EACf;EACA;EACA;EACA;EACA;;;;;;;;;EASA;;UAGe,gBAAgB;EAC/B;EACA;EACA;EACA;EACA;;;;;;;;;;;;;UAce;EACf;IACE;IACA;;;;cAKS;;;;;;;;;;cAUA;cACA;;;KCrDD;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA,iBAAiB,eAAe;EAChC;EACA;EACA;EACA;EACA,QAAQ;;KAIE,uBAAuB,KAAK;EACtC;EACA;;KAIU,yBAAyB,KACnC;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA,WAAW;;UAGI,gBAAgB,KAAK;EACpC;EACA;EACA;EACA;EACA;EACA,WAAW;;;;UCtEI;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;EACA;;;;UCZe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;;;;UCRe;EACf;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;EACA;EACA;IAAW;;;UAGI,yBAAyB,KAAK;EAC7C,OAAO;EACP,aAAa;;KAGH,aAAa;;;KChCb;UAQK;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA,kBAAkB;EAClB,QAAQ;EACR;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA,OAAO;;UAGQ;EACf;EACA;EACA,kBAAkB;EAClB,OAAO;IACL;IACA;;EAEF;EACA;EACA;;;EAGA,WAAW;;UAGI;EACf,SAAS;EACT,SAAS;EACT;;;;UCvEe;EACf;EACA;EACA;;;;UCHQ;EACR;;UAGe,wBAAwB;EACvC;EACA;EACA;;UAGe,wBAAwB;EACvC;EACA;;UAKe,2BAA2B;EAC1C;EACA;EACA;;UA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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -96,10 +96,18 @@ interface SiteConfig {
|
|
|
96
96
|
}
|
|
97
97
|
//#endregion
|
|
98
98
|
//#region src/constants/pageTypes.d.ts
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Page type identifiers. Mirrors cms-backend/src/constants/pageTypes.ts.
|
|
101
|
+
*
|
|
102
|
+
* `pageTypes` are the singleton types — a site may have at most one page of
|
|
103
|
+
* each, enforced on create by the backend (cms/page/page.routes.ts). Attempting
|
|
104
|
+
* a second one is rejected with "A page with type "<type>" already exists for
|
|
105
|
+
* this site". `custom` is the only repeatable type.
|
|
106
|
+
*/
|
|
107
|
+
declare const pageTypes: readonly ["home", "about", "contact", "services", "blog", "team", "gallery", "events", "clients-partners", "testimonial", "faq"];
|
|
108
|
+
/** The full set accepted by the backend's page validator. */
|
|
109
|
+
declare const allPageTypes: readonly ["home", "about", "contact", "services", "blog", "team", "gallery", "events", "clients-partners", "testimonial", "faq", "custom"];
|
|
110
|
+
type PageType = (typeof allPageTypes)[number];
|
|
103
111
|
//#endregion
|
|
104
112
|
//#region src/types/cms-page.d.ts
|
|
105
113
|
interface CTA {
|
|
@@ -488,7 +496,10 @@ interface Category {
|
|
|
488
496
|
slug: string;
|
|
489
497
|
description?: string | null;
|
|
490
498
|
order: number;
|
|
491
|
-
|
|
499
|
+
seo?: ProductSEO | null;
|
|
500
|
+
extra?: (Record<string, unknown> & {
|
|
501
|
+
sections?: Section[];
|
|
502
|
+
}) | null;
|
|
492
503
|
created_at: string;
|
|
493
504
|
updated_at: string;
|
|
494
505
|
}
|
|
@@ -535,7 +546,9 @@ interface Album {
|
|
|
535
546
|
created_at: string;
|
|
536
547
|
updated_at: string;
|
|
537
548
|
items?: AlbumItem[];
|
|
538
|
-
extra?: Record<string, unknown>
|
|
549
|
+
extra?: (Record<string, unknown> & {
|
|
550
|
+
sections?: Section[];
|
|
551
|
+
}) | null;
|
|
539
552
|
}
|
|
540
553
|
interface AlbumItem {
|
|
541
554
|
id: string;
|
|
@@ -559,7 +572,10 @@ interface BrandGroup {
|
|
|
559
572
|
order: number;
|
|
560
573
|
created_at: string;
|
|
561
574
|
updated_at: string;
|
|
562
|
-
|
|
575
|
+
seo?: ProductSEO | null;
|
|
576
|
+
extra?: (Record<string, unknown> & {
|
|
577
|
+
sections?: Section[];
|
|
578
|
+
}) | null;
|
|
563
579
|
brands?: Brand[];
|
|
564
580
|
}
|
|
565
581
|
interface Brand {
|
|
@@ -611,6 +627,7 @@ interface Event {
|
|
|
611
627
|
location_name?: string | null;
|
|
612
628
|
address?: string | null;
|
|
613
629
|
link?: string | null;
|
|
630
|
+
link_text?: string | null;
|
|
614
631
|
image_url?: string | null;
|
|
615
632
|
image_alt?: string | null;
|
|
616
633
|
description?: string | null;
|
|
@@ -650,6 +667,10 @@ interface FaqGroup {
|
|
|
650
667
|
description: string | null;
|
|
651
668
|
order: number;
|
|
652
669
|
faqs: Faq[];
|
|
670
|
+
seo?: ProductSEO | null;
|
|
671
|
+
extra?: {
|
|
672
|
+
sections: Section[];
|
|
673
|
+
} | null;
|
|
653
674
|
created_at: string;
|
|
654
675
|
updated_at: string;
|
|
655
676
|
}
|
|
@@ -727,6 +748,15 @@ interface PublicContactConfig {
|
|
|
727
748
|
}
|
|
728
749
|
/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */
|
|
729
750
|
declare const MAX_CONTACT_ATTACHMENTS = 3;
|
|
751
|
+
/**
|
|
752
|
+
* Total attachment budget, measured on RAW bytes.
|
|
753
|
+
*
|
|
754
|
+
* Attachments are forwarded onto the notification email, so the ceiling is
|
|
755
|
+
* Cloudflare Email's 5 MiB message limit — but the wire format is base64, 4/3
|
|
756
|
+
* the size. 3 MiB raw leaves headroom; 4 MiB encoded to ~5.33 MiB and was
|
|
757
|
+
* already over. Keep in step with MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES in
|
|
758
|
+
* cms-backend/src/constants/limits.ts.
|
|
759
|
+
*/
|
|
730
760
|
declare const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES: number;
|
|
731
761
|
declare const CONTACT_ATTACHMENT_MIME_ALLOWLIST: readonly string[];
|
|
732
762
|
//#endregion
|
|
@@ -907,7 +937,9 @@ interface PlaceOrderPayload {
|
|
|
907
937
|
customer_phone?: string | null;
|
|
908
938
|
notes?: string | null;
|
|
909
939
|
discount?: number | null;
|
|
910
|
-
|
|
940
|
+
/** Flat string map only — the API validates `Record<string, string>` on a
|
|
941
|
+
* strict schema, so nested objects, numbers and arrays are rejected (400). */
|
|
942
|
+
metadata?: Record<string, string>;
|
|
911
943
|
}
|
|
912
944
|
interface CartItem {
|
|
913
945
|
variant: ProductVariant;
|
|
@@ -1025,6 +1057,7 @@ declare function createCmsClient(config: CmsClientConfig): {
|
|
|
1025
1057
|
page?: number;
|
|
1026
1058
|
}, options?: FetchOptions) => Promise<PaginatedResponse<PageListItem>>;
|
|
1027
1059
|
fetchPageByUrl: (siteId: string, urlPath: string, options?: FetchOptions) => Promise<Page | null>;
|
|
1060
|
+
fetchPageByType: (siteId: string, pageType: PageType, options?: FetchOptions) => Promise<Page | null>;
|
|
1028
1061
|
fetchAboutUs: (siteId: string, options?: FetchOptions) => Promise<AboutUsData | null>;
|
|
1029
1062
|
fetchServices: (siteId: string, params?: {
|
|
1030
1063
|
page?: number;
|
|
@@ -1287,5 +1320,5 @@ interface UpdateSitePayload {
|
|
|
1287
1320
|
declare const ICON_NAMES: readonly ["Home", "User", "Settings", "Mail", "Bell", "Calendar", "Star", "Heart", "Bookmark", "Search", "Filter", "Download", "Upload", "Trash", "Edit", "Plus", "Minus", "Check", "X", "ChevronRight", "ChevronLeft", "ChevronUp", "ChevronDown", "ChevronsUpDown", "ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown", "File", "Folder", "Image", "Video", "Music", "Lock", "Unlock", "Eye", "EyeOff", "Sun", "Moon", "Cloud", "Zap", "Activity", "TrendingUp", "TrendingDown", "BarChart", "PieChart", "Database", "Server", "Wifi", "Battery", "Camera", "Mic", "Phone", "MessageSquare", "Send", "Share", "Link", "ExternalLink", "Globe", "MapPin", "Users", "ShoppingCart", "CreditCard", "Package", "Briefcase", "Target", "Flag", "Clipboard", "List", "Grid", "Layout", "Layers", "Copy", "Save", "RefreshCw", "Maximize", "Code", "AlertCircle", "Info", "HelpCircle", "CheckCircle", "XCircle", "Menu", "MoreVertical", "MoreHorizontal", "PlayCircle", "PauseCircle", "LogIn", "LogOut", "UserPlus", "UserMinus", "Tag", "Award", "Gift", "Truck", "Clock", "Handshake", "Stethoscope", "Microscope", "GraduationCap", "BookOpen", "Building2", "Trees", "HeartHandshake", "Brain", "Lightbulb"];
|
|
1288
1321
|
type IconName = (typeof ICON_NAMES)[number];
|
|
1289
1322
|
//#endregion
|
|
1290
|
-
export { ANIMATION, APIResponse, AboutSection, AboutStat, AboutUsData, AboutValue, Album, AlbumGroupSection, AlbumItem, Blog, BlogSection, Brand, BrandGroup, Branding, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CTA, CTAContent, CartItem, Category, ClientsSection, CmsClientConfig, CmsError, Collection, CollectionDetail, CollectionGroupSection, CollectionItem, CollectionListItem, CompanyInfo, Contact, ContactConfig, ContactPayload, CreateSitePayload, Cta, CustomContent, Event, Faq, FaqGroup, FaqSection, FetchOptions, Footer, FooterNavChild, FooterNavGroup, FooterNavGroupLink, GallerySection, GenericSection, HTTP_STATUS, Header, HeroContent, HistoryItem, HistorySection, ICON_NAMES, IconName, Image, LocationConfig, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, MarqueeItem, MarqueeSection, MultiValueItem, MultiValueSection, NavChild, NavGrandChild, NavLink, Order, OrderItem, OrderStatus, PAGINATION, Page, PageListItem, PageType, PaginatedResponse, PaginationInfo, PaginationMeta, PlaceOrderPayload, Product, ProductBrand, ProductCategory, ProductExtraData, ProductImage, ProductListItem, ProductSEO, ProductSectionFilter, ProductStatus, ProductVariant, ProductVariantListItem, ProductsSection, PublicContactConfig, PublicProductVariant, Redirect, Redirect404Log, RedirectStatusCode, ResolvedRedirect, RichContentSection, SEARCH, SEO, Section, Service, ServicesSection, ShippingAddress, SingleDataAPIResponse, Site, SiteConfig, SitemapAlbumItem, SitemapBlogItem, SitemapBrandGroupItem, SitemapCollectionItem, SitemapEventItem, SitemapItem, SitemapPageItem, SitemapProductBrandItem, SitemapProductCategoryItem, SitemapProductItem, SitemapResource, SitemapResourceMap, SitemapServiceItem, SitemapTeamCategoryItem, SitemapTeamMemberItem, Social, SocialLink, StoreSettings, TeamMember, TeamSection, Testimonial, TestimonialsSection, UpdateSitePayload, UserSiteRole, WorkingHours, allPageTypes, createCmsClient,
|
|
1323
|
+
export { ANIMATION, APIResponse, AboutSection, AboutStat, AboutUsData, AboutValue, Album, AlbumGroupSection, AlbumItem, Blog, BlogSection, Brand, BrandGroup, Branding, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CTA, CTAContent, CartItem, Category, ClientsSection, CmsClientConfig, CmsError, Collection, CollectionDetail, CollectionGroupSection, CollectionItem, CollectionListItem, CompanyInfo, Contact, ContactConfig, ContactPayload, CreateSitePayload, Cta, CustomContent, Event, Faq, FaqGroup, FaqSection, FetchOptions, Footer, FooterNavChild, FooterNavGroup, FooterNavGroupLink, GallerySection, GenericSection, HTTP_STATUS, Header, HeroContent, HistoryItem, HistorySection, ICON_NAMES, IconName, Image, LocationConfig, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, MarqueeItem, MarqueeSection, MultiValueItem, MultiValueSection, NavChild, NavGrandChild, NavLink, Order, OrderItem, OrderStatus, PAGINATION, Page, PageListItem, PageType, PaginatedResponse, PaginationInfo, PaginationMeta, PlaceOrderPayload, Product, ProductBrand, ProductCategory, ProductExtraData, ProductImage, ProductListItem, ProductSEO, ProductSectionFilter, ProductStatus, ProductVariant, ProductVariantListItem, ProductsSection, PublicContactConfig, PublicProductVariant, Redirect, Redirect404Log, RedirectStatusCode, ResolvedRedirect, RichContentSection, SEARCH, SEO, Section, Service, ServicesSection, ShippingAddress, SingleDataAPIResponse, Site, SiteConfig, SitemapAlbumItem, SitemapBlogItem, SitemapBrandGroupItem, SitemapCollectionItem, SitemapEventItem, SitemapItem, SitemapPageItem, SitemapProductBrandItem, SitemapProductCategoryItem, SitemapProductItem, SitemapResource, SitemapResourceMap, SitemapServiceItem, SitemapTeamCategoryItem, SitemapTeamMemberItem, Social, SocialLink, StoreSettings, TeamMember, TeamSection, Testimonial, TestimonialsSection, UpdateSitePayload, UserSiteRole, WorkingHours, allPageTypes, createCmsClient, pageTypes };
|
|
1291
1324
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/pagination.ts","../src/types/header.ts","../src/types/footer.ts","../src/types/site-config.ts","../src/constants/pageTypes.ts","../src/types/cms-page.ts","../src/types/about.ts","../src/types/seo.ts","../src/types/service.ts","../src/types/blog.ts","../src/types/category.ts","../src/types/team-member.ts","../src/types/album.ts","../src/types/brand.ts","../src/types/testimonials.ts","../src/types/event.ts","../src/types/faq.ts","../src/types/faq-group.ts","../src/types/redirect.ts","../src/types/contact.ts","../src/types/product.ts","../src/types/product-category.ts","../src/types/product-brand.ts","../src/types/collection.ts","../src/types/order.ts","../src/types/store-setting.ts","../src/types/sitemap.ts","../src/core/client.ts","../src/constants/index.ts","../src/types/api-response.ts","../src/types/company-info.ts","../src/types/site.ts","../src/types/icon.ts"],"mappings":";UAAiB;EACf;EACA;EACA;;KAIU,iBAAiB;UAEZ,kBAAkB;EACjC,MAAM;EACN,YAAY;;;;UCXG;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;EACX,MAAM;EACN,OAAO;;;;UC3BQ;EACf;EACA;;UAGe;EACf;EACA;EACA,UAAU;;UAGK;EACf;EACA,OAAO;;UAGQ;EACf;EACA;EACA,YAAY;EACZ,OAAO;;;;UCpBQ;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAWe;EACf;EACA;EACA,SAAS;EACT,WAAW;EACX,gBAAgB;;UAGD;EACf;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/pagination.ts","../src/types/header.ts","../src/types/footer.ts","../src/types/site-config.ts","../src/constants/pageTypes.ts","../src/types/cms-page.ts","../src/types/about.ts","../src/types/seo.ts","../src/types/service.ts","../src/types/blog.ts","../src/types/category.ts","../src/types/team-member.ts","../src/types/album.ts","../src/types/brand.ts","../src/types/testimonials.ts","../src/types/event.ts","../src/types/faq.ts","../src/types/faq-group.ts","../src/types/redirect.ts","../src/types/contact.ts","../src/types/product.ts","../src/types/product-category.ts","../src/types/product-brand.ts","../src/types/collection.ts","../src/types/order.ts","../src/types/store-setting.ts","../src/types/sitemap.ts","../src/core/client.ts","../src/constants/index.ts","../src/types/api-response.ts","../src/types/company-info.ts","../src/types/site.ts","../src/types/icon.ts"],"mappings":";UAAiB;EACf;EACA;EACA;;KAIU,iBAAiB;UAEZ,kBAAkB;EACjC,MAAM;EACN,YAAY;;;;UCXG;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;EACX,MAAM;EACN,OAAO;;;;UC3BQ;EACf;EACA;;UAGe;EACf;EACA;EACA,UAAU;;UAGK;EACf;EACA,OAAO;;UAGQ;EACf;EACA;EACA,YAAY;EACZ,OAAO;;;;UCpBQ;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAWe;EACf;EACA;EACA,SAAS;EACT,WAAW;EACX,gBAAgB;;UAGD;EACf;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;;;;;;;;;;;;cCtCE;;cAeA;KAED,mBAAmB;;;UCvBd;EACf;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,KAAK;EACL;EACA;IACE;IACA;;;UAIa;EACf;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;IACN;IACA;IACA;IACA;IACA;;;UAIa;EACf;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe,oBAAoB;EACnC;EACA;;UAGe,uBAAuB;EACtC;;UAGe,mBAAmB;EAClC;;UAGe,oBAAoB;EACnC;;UAGe,uBAAuB;EACtC;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,KAAK;;UAGU;EACf;EACA;EACA,OAAO;EACP,MAAM,QAAQ;EACd;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,QAAQ;EACR,QAAQ;;UAGO;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA,OAAO;;KAGG;UAEK;EACf;EACA;EACA;EACA,SAAS;EACT;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;KAGU;EACN;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAgB,SAAS;;EAC9D;EAAY;EAAyB;EAAa,SAAS;;EAC3D;EAAY;EAAyB;EAAqB,SAAS;;EACnE;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAqB,SAAS;;EACnE;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAe,SAAS;;EAC7D;EAAY;EAAyB;EAAc,SAAS;;EAC5D;EAAY;EAAyB;EAAsB,SAAS;;EACpE;EAAY;EAAyB;EAAe,SAAS;;EAC7D;EAAY;EAAyB;EAAa,SAAS;;EAC3D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAiB,SAAS;;EAC/D;EAAY;EAAyB;EAAkB,SAAS;;EAEhE;EACA;EACA;EACA,SAAS;;EAGT;EACA;EACA;EACA,SAAS;;UAGE;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA,UAAU;EACV,WAAW;EACX;EACA,KAAK;EACL,UAAU;EACV,QAAQ;EACR;EACA;;KAIU,eAAe,KAAK;;;UCrPf;EACf;IAAU;IAAc;;EACxB;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;;;;UCzBO;EACf;EACA;EACA;EACA;;UAGe,yBAAyB;;;UCJzB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL;IACE,UAAU;;;;;UCrBG;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE,UAAU;IACV;MACE;MACA;MACA;;;;;;UCzBW;EACf;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;IAA4B,WAAW;;EAChD;EACA;;;;UCbe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA,QAAQ;EACR;EACA;;;;UCnBe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,SAAS;IAA4B,WAAW;;;UAGjC;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC3Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,SAAS;IAA4B,WAAW;;EAChD,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC5Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OAAO;;;;UCdQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE,UAAU;;;;;UCjCG;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UCJe;EACf;EACA;EACA;EACA;EACA;EACA,MAAM;EACN,MAAM;EACN;IACE,UAAU;;EAEZ;EACA;;;;KChBU;UAEK;EACf;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA;EACA;;UAGe;EACf,UAAU;EACV;EACA,QAAQ;EACR;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;UC7Be;EACf;EACA;EACA;EACA;EACA;;;;;;;;;EASA;;UAGe,gBAAgB;EAC/B;EACA;EACA;EACA;EACA;;;;;;;;;;;;;UAce;EACf;IACE;IACA;;;;cAKS;;;;;;;;;;cAUA;cACA;;;KCrDD;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA,iBAAiB,eAAe;EAChC;EACA;EACA;EACA;EACA,QAAQ;;KAIE,uBAAuB,KAAK;EACtC;EACA;;KAIU,yBAAyB,KACnC;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA,WAAW;;UAGI,gBAAgB,KAAK;EACpC;EACA;EACA;EACA;EACA;EACA,WAAW;;;;UCtEI;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;EACA;;;;UCZe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;;;;UCRe;EACf;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;EACL,OAAO;EACP;EACA;EACA;EACA;IAAW;;;UAGI,yBAAyB,KAAK;EAC7C,OAAO;EACP,aAAa;;KAGH,aAAa;;;KChCb;UAQK;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA,kBAAkB;EAClB,QAAQ;EACR;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA,OAAO;;UAGQ;EACf;EACA;EACA,kBAAkB;EAClB,OAAO;IACL;IACA;;EAEF;EACA;EACA;;;EAGA,WAAW;;UAGI;EACf,SAAS;EACT,SAAS;EACT;;;;UCvEe;EACf;EACA;EACA;;;;UCHQ;EACR;;UAGe,wBAAwB;EACvC;EACA;EACA;;UAGe,wBAAwB;EACvC;EACA;;UAKe,2BAA2B;EAC1C;EACA;EACA;;UA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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
//#region src/constants/pageTypes.ts
|
|
2
|
+
/**
|
|
3
|
+
* Page type identifiers. Mirrors cms-backend/src/constants/pageTypes.ts.
|
|
4
|
+
*
|
|
5
|
+
* `pageTypes` are the singleton types — a site may have at most one page of
|
|
6
|
+
* each, enforced on create by the backend (cms/page/page.routes.ts). Attempting
|
|
7
|
+
* a second one is rejected with "A page with type "<type>" already exists for
|
|
8
|
+
* this site". `custom` is the only repeatable type.
|
|
9
|
+
*/
|
|
2
10
|
const pageTypes = [
|
|
3
11
|
"home",
|
|
4
12
|
"about",
|
|
5
|
-
"contact"
|
|
6
|
-
];
|
|
7
|
-
const defaultPageTypes = [
|
|
8
|
-
...pageTypes,
|
|
9
|
-
"services",
|
|
10
|
-
"blog",
|
|
11
|
-
"team",
|
|
12
|
-
"gallery",
|
|
13
|
-
"events"
|
|
14
|
-
];
|
|
15
|
-
const allPageTypes = [
|
|
16
|
-
...pageTypes,
|
|
17
|
-
"custom",
|
|
13
|
+
"contact",
|
|
18
14
|
"services",
|
|
19
15
|
"blog",
|
|
20
16
|
"team",
|
|
21
17
|
"gallery",
|
|
22
|
-
"events"
|
|
18
|
+
"events",
|
|
19
|
+
"clients-partners",
|
|
20
|
+
"testimonial",
|
|
21
|
+
"faq"
|
|
23
22
|
];
|
|
23
|
+
/** The full set accepted by the backend's page validator. */
|
|
24
|
+
const allPageTypes = [...pageTypes, "custom"];
|
|
24
25
|
//#endregion
|
|
25
26
|
//#region src/constants/index.ts
|
|
26
27
|
const PAGINATION = {
|
|
@@ -83,7 +84,16 @@ const MEDIA = {
|
|
|
83
84
|
//#region src/types/contact.ts
|
|
84
85
|
/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */
|
|
85
86
|
const MAX_CONTACT_ATTACHMENTS = 3;
|
|
86
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Total attachment budget, measured on RAW bytes.
|
|
89
|
+
*
|
|
90
|
+
* Attachments are forwarded onto the notification email, so the ceiling is
|
|
91
|
+
* Cloudflare Email's 5 MiB message limit — but the wire format is base64, 4/3
|
|
92
|
+
* the size. 3 MiB raw leaves headroom; 4 MiB encoded to ~5.33 MiB and was
|
|
93
|
+
* already over. Keep in step with MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES in
|
|
94
|
+
* cms-backend/src/constants/limits.ts.
|
|
95
|
+
*/
|
|
96
|
+
const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES = 3145728;
|
|
87
97
|
const CONTACT_ATTACHMENT_MIME_ALLOWLIST = [
|
|
88
98
|
"application/pdf",
|
|
89
99
|
"image/png",
|
|
@@ -244,6 +254,19 @@ function createCmsClient(config) {
|
|
|
244
254
|
...options
|
|
245
255
|
});
|
|
246
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* The site's single published page of a given type, with its sections — the
|
|
259
|
+
* same payload as `fetchPageByUrl`. Prefer this when you know which kind of
|
|
260
|
+
* page you want but not its url, since an editor can rename the url at any
|
|
261
|
+
* time. Returns null when the site has no published page of that type.
|
|
262
|
+
*/
|
|
263
|
+
async function fetchPageByType(siteId, pageType, options) {
|
|
264
|
+
return cmsFetch(`/api/public/cms/${siteId}/page/by-type/${encodeURIComponent(pageType)}/`, {
|
|
265
|
+
revalidate: CACHE.SHORT,
|
|
266
|
+
tags: ["pages", `page-type-${pageType}`],
|
|
267
|
+
...options
|
|
268
|
+
});
|
|
269
|
+
}
|
|
247
270
|
function fetchAboutUs(siteId, options) {
|
|
248
271
|
return cmsFetch(`/api/public/cms/${siteId}/about-us/`, {
|
|
249
272
|
revalidate: CACHE.MEDIUM,
|
|
@@ -397,7 +420,7 @@ function createCmsClient(config) {
|
|
|
397
420
|
const url = `${baseUrl}/api/public/cms/${siteId}/contact/`;
|
|
398
421
|
if (attachments?.length) {
|
|
399
422
|
if (attachments.length > 3) throw new CmsError(`At most 3 attachments are allowed`, 400, url);
|
|
400
|
-
if (attachments.reduce((sum, f) => sum + f.size, 0) >
|
|
423
|
+
if (attachments.reduce((sum, f) => sum + f.size, 0) > 3145728) throw new CmsError(`Attachments exceed the ${MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES / 1048576} MiB total size limit`, 400, url);
|
|
401
424
|
for (const f of attachments) if (!CONTACT_ATTACHMENT_MIME_ALLOWLIST.includes(f.type)) throw new CmsError(`Attachment type not allowed: ${f.type || "unknown"}`, 400, url);
|
|
402
425
|
}
|
|
403
426
|
let body;
|
|
@@ -664,6 +687,7 @@ function createCmsClient(config) {
|
|
|
664
687
|
fetchSiteConfig,
|
|
665
688
|
fetchPages,
|
|
666
689
|
fetchPageByUrl,
|
|
690
|
+
fetchPageByType,
|
|
667
691
|
fetchAboutUs,
|
|
668
692
|
fetchServices,
|
|
669
693
|
fetchServiceBySlug,
|
|
@@ -818,6 +842,6 @@ const ICON_NAMES = [
|
|
|
818
842
|
"Lightbulb"
|
|
819
843
|
];
|
|
820
844
|
//#endregion
|
|
821
|
-
export { ANIMATION, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CmsError, HTTP_STATUS, ICON_NAMES, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, PAGINATION, SEARCH, allPageTypes, createCmsClient,
|
|
845
|
+
export { ANIMATION, CACHE, CONTACT_ATTACHMENT_MIME_ALLOWLIST, CONTACT_SUBJECTS, CmsError, HTTP_STATUS, ICON_NAMES, MAX_CONTACT_ATTACHMENTS, MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES, MEDIA, PAGINATION, SEARCH, allPageTypes, createCmsClient, pageTypes };
|
|
822
846
|
|
|
823
847
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants/pageTypes.ts","../src/constants/index.ts","../src/types/contact.ts","../src/core/client.ts","../src/types/icon.ts"],"sourcesContent":["export const pageTypes = [\"home\", \"about\", \"contact\"] as const;\n\nexport const defaultPageTypes = [\n ...pageTypes,\n \"services\",\n \"blog\",\n \"team\",\n \"gallery\",\n \"events\",\n] as const;\n\nexport const allPageTypes = [\n ...pageTypes,\n \"custom\",\n \"services\",\n \"blog\",\n \"team\",\n \"gallery\",\n \"events\",\n] as const;\n\nexport type PageType = typeof allPageTypes[number];\n","export * from \"./pageTypes\";\n\nexport const PAGINATION = {\n DEFAULT_PAGE: 1,\n DEFAULT_LIMIT: 10,\n LIST_DEFAULT_LIMIT: 20,\n BLOGS_PER_PAGE: 9,\n EVENTS_PER_PAGE: 9,\n ALBUMS_PER_PAGE: 9,\n MAX_ITEMS_FOR_SSG: 200,\n} as const;\n\nexport const SEARCH = {\n DEBOUNCE_MS: 500,\n MIN_QUERY_LENGTH: 2,\n} as const;\n\nexport const CACHE = {\n NO_CACHE: 0,\n SHORT: 60, // 1 minute\n MEDIUM: 300, // 5 minutes\n LONG: 3600, // 1 hour\n STATIC: 86400, // 24 hours\n} as const;\n\nexport const ANIMATION = {\n FAST: 0.2,\n NORMAL: 0.3,\n SLOW: 0.6,\n} as const;\n\nexport const CONTACT_SUBJECTS = [\n \"General Inquiry\",\n \"Project Proposal\",\n \"Careers\",\n \"Other\",\n] as const;\n\nexport const HTTP_STATUS = {\n OK: 200,\n CREATED: 201,\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n INTERNAL_ERROR: 500,\n} as const;\n\nexport const MEDIA = {\n IMAGE_EXTENSIONS: [\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".svg\"],\n VIDEO_EXTENSIONS: [\".mp4\", \".webm\", \".ogg\"],\n MAX_IMAGE_SIZE: 5 * 1024 * 1024,\n} as const;\n","export interface ContactPayload {\n name: string;\n email?: string | null;\n subject?: string | null;\n message: string;\n type?: string;\n /**\n * Cloudflare Turnstile token from the widget on your form.\n *\n * Required whenever the site has Turnstile enabled — check with\n * `fetchContactConfig(siteId)`. Submitting without one is rejected with 403\n * (`CmsError`), and the token is single-use: on a failed submit, reset the\n * widget before retrying rather than resending the same value.\n */\n turnstile_token?: string;\n}\n\nexport interface Contact extends ContactPayload {\n id: string;\n site_id: string;\n is_read: boolean;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Public Turnstile settings for a site's contact form, from\n * GET /:site_id/contact-config/.\n *\n * Named to avoid colliding with `ContactConfig` in ./site-config, which is the\n * site's displayed contact details (phone, email, socials) and unrelated.\n *\n * `enabled` with a null `site_key` means the site is misconfigured: the widget\n * cannot render and submissions will be rejected. Treat it as \"do not show the\n * form\" rather than \"no captcha needed\".\n */\nexport interface PublicContactConfig {\n turnstile: {\n enabled: boolean;\n site_key: string | null;\n };\n}\n\n/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */\nexport const MAX_CONTACT_ATTACHMENTS = 3;\nexport const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES = 4 * 1024 * 1024;\nexport const CONTACT_ATTACHMENT_MIME_ALLOWLIST: readonly string[] = [\n \"application/pdf\",\n \"image/png\",\n \"image/jpeg\",\n \"image/webp\",\n \"image/gif\",\n \"text/plain\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n];\n","import { CACHE, PAGINATION } from \"../constants\";\nimport type { PaginatedResponse } from \"../types/pagination\";\nimport type { Header } from \"../types/header\";\nimport type { Footer } from \"../types/footer\";\nimport type { SiteConfig } from \"../types/site-config\";\nimport type { Page, PageListItem } from \"../types/cms-page\";\nimport type { AboutUsData } from \"../types/about\";\nimport type { Service } from \"../types/service\";\nimport type { Blog } from \"../types/blog\";\nimport type { Category } from \"../types/category\";\nimport type { TeamMember } from \"../types/team-member\";\nimport type { Album, AlbumItem } from \"../types/album\";\nimport type { BrandGroup, Brand } from \"../types/brand\";\nimport type { Testimonial } from \"../types/testimonials\";\nimport type { Event } from \"../types/event\";\nimport type { Faq } from \"../types/faq\";\nimport type { FaqGroup } from \"../types/faq-group\";\nimport type { Redirect, Redirect404Log, ResolvedRedirect } from \"../types/redirect\";\nimport type {\n ContactPayload,\n Contact,\n PublicContactConfig,\n} from \"../types/contact\";\nimport {\n MAX_CONTACT_ATTACHMENTS,\n MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES,\n CONTACT_ATTACHMENT_MIME_ALLOWLIST,\n} from \"../types/contact\";\nimport type { Product, ProductListItem, ProductVariant } from \"../types/product\";\nimport type { ProductCategory } from \"../types/product-category\";\nimport type { ProductBrand } from \"../types/product-brand\";\nimport type { Collection, CollectionDetail } from \"../types/collection\";\nimport type { Order, PlaceOrderPayload } from \"../types/order\";\nimport type { StoreSettings } from \"../types/store-setting\";\nimport type {\n SitemapBlogItem,\n SitemapPageItem,\n SitemapProductItem,\n SitemapCollectionItem,\n SitemapResource,\n SitemapResourceMap,\n} from \"../types/sitemap\";\n\nexport interface FetchOptions extends RequestInit {\n revalidate?: number;\n tags?: string[];\n retries?: number;\n}\n\nexport interface CmsClientConfig {\n baseUrl: string;\n defaultOptions?: FetchOptions;\n}\n\nexport class CmsError extends Error {\n constructor(\n public message: string,\n public status?: number,\n public url?: string,\n ) {\n super(message);\n this.name = \"CmsError\";\n }\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport function createCmsClient(config: CmsClientConfig) {\n const { baseUrl, defaultOptions = {} } = config;\n\n async function cmsFetch<T>(\n endpoint: string,\n options: FetchOptions = {},\n ): Promise<T | null> {\n const url = `${baseUrl}${endpoint}`;\n const {\n revalidate = CACHE.NO_CACHE,\n tags,\n retries = 1,\n ...rest\n } = { ...defaultOptions, ...options };\n\n const fetchConfig: RequestInit & {\n next?: { revalidate?: number; tags?: string[] };\n } = {\n ...rest,\n next: {\n revalidate,\n ...(tags && { tags }),\n },\n };\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, fetchConfig);\n\n if (!response.ok) {\n // Retry on transient server errors (502, 503, 504)\n if (attempt < retries && [502, 503, 504].includes(response.status)) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n let errorMsg = `API request failed: ${response.status} ${url}`;\n try {\n const body = await response.json();\n if (body?.message) errorMsg = body.message;\n } catch {\n // body not JSON, keep fallback\n }\n throw new CmsError(errorMsg, response.status, url);\n }\n\n // 204 / empty body — nothing to parse\n if (response.status === 204) {\n return null;\n }\n\n const result = await response.json();\n return result.data ?? result;\n } catch (error) {\n if (error instanceof CmsError) throw error;\n\n if (attempt < retries) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n const msg =\n error instanceof Error ? error.message : String(error);\n throw new CmsError(`Request failed: ${msg}`, undefined, url);\n }\n }\n\n throw new CmsError(`Request failed after ${retries + 1} attempts`, undefined, url);\n }\n\n async function cmsFetchPaginated<T>(\n endpoint: string,\n options: FetchOptions = {},\n ): Promise<PaginatedResponse<T>> {\n const url = `${baseUrl}${endpoint}`;\n const {\n revalidate = CACHE.NO_CACHE,\n tags,\n retries = 1,\n ...rest\n } = { ...defaultOptions, ...options };\n\n const fetchConfig: RequestInit & {\n next?: { revalidate?: number; tags?: string[] };\n } = {\n ...rest,\n next: {\n revalidate,\n ...(tags && { tags }),\n },\n };\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, fetchConfig);\n\n if (!response.ok) {\n if (attempt < retries && [502, 503, 504].includes(response.status)) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n let errorMsg = `API request failed: ${response.status} ${url}`;\n try {\n const body = await response.json();\n if (body?.message) errorMsg = body.message;\n } catch {\n // body not JSON, keep fallback\n }\n throw new CmsError(errorMsg, response.status, url);\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof CmsError) throw error;\n\n if (attempt < retries) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n const msg =\n error instanceof Error ? error.message : String(error);\n throw new CmsError(`Request failed: ${msg}`, undefined, url);\n }\n }\n\n throw new CmsError(`Request failed after ${retries + 1} attempts`, undefined, url);\n }\n\n function buildQueryString(\n params: Record<string, string | number | string[] | number[] | undefined | null>,\n ): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n value.forEach((v) => query.append(key, String(v)));\n } else {\n query.append(key, String(value));\n }\n }\n });\n return query.toString();\n }\n\n // Default page size for list endpoints (categories, team, brands, testimonials,\n // faq-groups, faqs). Matches the backend's getPaginationParamsWithoutLimit(c, 20).\n // Album-items is NOT one of these: it uses getPaginationParams(c, 100), so its\n // server-side default is 10 and callers should pass an explicit `limit`.\n const LIST_DEFAULT_LIMIT = PAGINATION.LIST_DEFAULT_LIMIT;\n\n // ============================================================================\n // Header, Footer, Site Config\n // ============================================================================\n\n function fetchHeader(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Header | null> {\n return cmsFetch<Header>(`/api/public/cms/${siteId}/header/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"header\"],\n ...options,\n });\n }\n\n function fetchFooter(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Footer | null> {\n return cmsFetch<Footer>(`/api/public/cms/${siteId}/footer/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"footer\"],\n ...options,\n });\n }\n\n function fetchSiteConfig(\n siteId: string,\n options?: FetchOptions,\n ): Promise<SiteConfig | null> {\n return cmsFetch<SiteConfig>(`/api/public/cms/${siteId}/site-config/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"site-config\"],\n ...options,\n });\n }\n\n // ============================================================================\n // Pages\n // ============================================================================\n\n function fetchPages(\n siteId: string,\n params: { page?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<PageListItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<PageListItem>(\n `/api/public/cms/${siteId}/page/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"pages\"],\n ...options,\n },\n );\n }\n\n async function fetchPageByUrl(\n siteId: string,\n urlPath: string,\n options?: FetchOptions,\n ): Promise<Page | null> {\n const targetUrl =\n urlPath === \"/\" || urlPath === \"\"\n ? \"/\"\n : `/${urlPath.replace(/^\\/|\\/$/g, \"\")}`;\n\n return cmsFetch<Page>(\n `/api/public/cms/${siteId}/page/by-url/?url=${encodeURIComponent(targetUrl)}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"pages\", `page-${targetUrl || \"root\"}`],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // About Us\n // ============================================================================\n\n function fetchAboutUs(\n siteId: string,\n options?: FetchOptions,\n ): Promise<AboutUsData | null> {\n return cmsFetch<AboutUsData>(`/api/public/cms/${siteId}/about-us/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"about\"],\n ...options,\n });\n }\n\n // ============================================================================\n // Services\n // ============================================================================\n\n async function fetchServices(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Service>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Service>(\n `/api/public/cms/${siteId}/services/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"services\"],\n ...options,\n },\n );\n }\n\n function fetchServiceBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Service | null> {\n return cmsFetch<Service>(`/api/public/cms/${siteId}/services/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"services\", `service-${slug}`],\n ...options,\n });\n }\n\n // ============================================================================\n // Blogs\n // ============================================================================\n\n function fetchBlogs(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Blog>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Blog>(`/api/public/cms/${siteId}/blog/?${query}`, {\n revalidate: CACHE.SHORT,\n tags: [\"blogs\"],\n ...options,\n });\n }\n\n function fetchBlogBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Blog | null> {\n return cmsFetch<Blog>(`/api/public/cms/${siteId}/blog/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"blogs\", `blog-${slug}`],\n ...options,\n });\n }\n\n // Backwards-compatible alias. Backend route resolves by slug.\n function fetchBlogById(\n siteId: string,\n idOrSlug: number | string,\n options?: FetchOptions,\n ): Promise<Blog | null> {\n return fetchBlogBySlug(siteId, String(idOrSlug), options);\n }\n\n // ============================================================================\n // Categories\n // ============================================================================\n\n function fetchCategories(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Category>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Category>(\n `/api/public/cms/${siteId}/categories/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"categories\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Team Members\n // ============================================================================\n\n function fetchTeamMembers(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<TeamMember>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<TeamMember>(\n `/api/public/cms/${siteId}/team-members/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"team\"],\n ...options,\n },\n );\n }\n\n function fetchTeamMembersByCategory(\n siteId: string,\n params: { categoryId: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<TeamMember>> {\n const query = buildQueryString({\n category_id: params.categoryId,\n page: params.page,\n limit: params.limit,\n });\n return cmsFetchPaginated<TeamMember>(\n `/api/public/cms/${siteId}/team-members/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"team\", `team-category-${params.categoryId}`],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Albums\n // ============================================================================\n\n function fetchAlbums(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Album>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Album>(\n `/api/public/cms/${siteId}/albums/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"albums\"],\n ...options,\n },\n );\n }\n\n function fetchAlbumItems(\n siteId: string,\n params: {\n /** Album slug. */\n album?: string;\n /** Comma-separated list of album IDs (e.g., \"id1,id2\") */\n album_id?: string;\n page?: number;\n /**\n * Defaults to 10 server-side (max 100) — pass an explicit value to get a\n * whole album, or several albums' worth for an album-group section.\n */\n limit?: number;\n },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<AlbumItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<AlbumItem>(\n `/api/public/cms/${siteId}/albums/album-items/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"album-items\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Brands\n // ============================================================================\n\n function fetchBrandGroups(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<BrandGroup>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<BrandGroup>(\n `/api/public/cms/${siteId}/brand-groups/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"brand-groups\"],\n ...options,\n },\n );\n }\n\n function fetchBrands(\n siteId: string,\n params: { group?: string; group_id?: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Brand>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Brand>(\n `/api/public/cms/${siteId}/brand-groups/brands/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"brands\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Testimonials\n // ============================================================================\n\n function fetchTestimonials(\n siteId: string,\n params?: { type?: \"testimonial\" | \"review\" | string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Testimonial>> {\n const query = buildQueryString({\n type: params?.type,\n page: params?.page,\n limit: params?.limit,\n });\n return cmsFetchPaginated<Testimonial>(\n `/api/public/cms/${siteId}/testimonials/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"testimonials\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Events\n // ============================================================================\n\n function fetchEvents(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Event>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Event>(\n `/api/public/cms/${siteId}/events/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"events\"],\n ...options,\n },\n );\n }\n\n function fetchEventBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Event | null> {\n return cmsFetch<Event>(`/api/public/cms/${siteId}/events/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"events\", `event-${slug}`],\n ...options,\n });\n }\n\n // ============================================================================\n // FAQ Groups\n // ============================================================================\n\n function fetchFaqGroups(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<FaqGroup>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<FaqGroup>(\n `/api/public/cms/${siteId}/faq-groups/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"faq-groups\"],\n ...options,\n },\n );\n }\n\n /**\n * Public Turnstile settings for the site's contact form.\n *\n * Call this before rendering the form: when `turnstile.enabled` is true the\n * widget must be rendered with `turnstile.site_key` and its token passed to\n * `submitContactForm`, or every submission is rejected.\n */\n function fetchContactConfig(\n siteId: string,\n options?: FetchOptions,\n ): Promise<PublicContactConfig | null> {\n return cmsFetch<PublicContactConfig>(\n `/api/public/cms/${siteId}/contact-config/`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"contact-config\"],\n ...options,\n },\n );\n }\n\n /**\n * Submit the contact form.\n *\n * Unlike the read methods, this THROWS `CmsError` on a rejection rather than\n * returning null — a form needs to tell \"captcha failed, reset the widget\"\n * (403) apart from \"rate limited\" (429) and a network blip, and a single\n * `null` cannot carry that. `error.status` holds the HTTP status.\n *\n * Pass `attachments` to send files; the request then goes out as multipart\n * instead of JSON. Caps are enforced server-side and pre-checked here.\n */\n async function submitContactForm(\n siteId: string,\n payload: ContactPayload,\n attachments?: File[],\n options?: FetchOptions,\n ): Promise<Contact> {\n const url = `${baseUrl}/api/public/cms/${siteId}/contact/`;\n\n if (attachments?.length) {\n if (attachments.length > MAX_CONTACT_ATTACHMENTS) {\n throw new CmsError(\n `At most ${MAX_CONTACT_ATTACHMENTS} attachments are allowed`,\n 400,\n url,\n );\n }\n const totalBytes = attachments.reduce((sum, f) => sum + f.size, 0);\n if (totalBytes > MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES) {\n throw new CmsError(\n \"Attachments exceed the 4 MiB total size limit\",\n 400,\n url,\n );\n }\n for (const f of attachments) {\n if (!CONTACT_ATTACHMENT_MIME_ALLOWLIST.includes(f.type)) {\n throw new CmsError(\n `Attachment type not allowed: ${f.type || \"unknown\"}`,\n 400,\n url,\n );\n }\n }\n }\n\n let body: BodyInit;\n const headers: Record<string, string> = {};\n if (attachments?.length) {\n // multipart — the runtime must set Content-Type so the boundary is right,\n // so no Content-Type header is set here.\n const form = new FormData();\n for (const [key, value] of Object.entries(payload)) {\n if (value !== undefined && value !== null) form.append(key, String(value));\n }\n for (const file of attachments) form.append(\"attachments\", file, file.name);\n body = form;\n } else {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(payload);\n }\n\n // No retries: the body may be a consumed stream, a resend would duplicate\n // the submission, and the one retryable-looking status here (503, a\n // misconfigured Turnstile) is a deployment fault that will not self-heal —\n // retrying it just burns the 1-per-60s write budget.\n let response: Response;\n try {\n response = await fetch(url, {\n ...options,\n method: \"POST\",\n headers: { ...headers, ...(options?.headers as Record<string, string>) },\n body,\n });\n } catch (error) {\n throw new CmsError(\n error instanceof Error ? error.message : \"Network request failed\",\n undefined,\n url,\n );\n }\n\n if (!response.ok) {\n // The API answers errors as { message }; fall back to the status text\n // when the body is not JSON (a proxy error page, say).\n let message = `Request failed with status ${response.status}`;\n try {\n const parsed = (await response.json()) as { message?: string };\n if (parsed?.message) message = parsed.message;\n } catch {\n // keep the fallback\n }\n throw new CmsError(message, response.status, url);\n }\n\n const result = await response.json();\n return (result.data ?? result) as Contact;\n }\n\n function fetchFaqs(\n siteId: string,\n params?: { group_id?: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Faq>> {\n const query = buildQueryString({\n group_id: params?.group_id,\n page: params?.page,\n limit: params?.limit,\n });\n return cmsFetchPaginated<Faq>(\n `/api/public/cms/${siteId}/faqs/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"faqs\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Redirects\n // ============================================================================\n\n async function fetchRedirects(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Redirect[]> {\n const result = await cmsFetch<Redirect[]>(\n `/api/public/cms/${siteId}/redirects/`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"redirects\"],\n ...options,\n },\n );\n return result ?? [];\n }\n\n function resolveRedirect(\n siteId: string,\n sourcePath: string,\n options?: FetchOptions,\n ): Promise<ResolvedRedirect | null> {\n return cmsFetch<ResolvedRedirect>(\n `/api/public/cms/${siteId}/redirects/resolve/?sourcePath=${encodeURIComponent(sourcePath)}`,\n {\n revalidate: CACHE.NO_CACHE,\n tags: [\"redirects\", `redirect-${sourcePath}`],\n ...options,\n },\n );\n }\n\n function reportRedirect404(\n siteId: string,\n sourcePath: string,\n referrer?: string,\n options?: FetchOptions,\n ): Promise<Redirect404Log | null> {\n const headers = {\n \"Content-Type\": \"application/json\",\n ...(options?.headers ?? {}),\n };\n\n return cmsFetch<Redirect404Log>(\n `/api/public/cms/${siteId}/redirects/404-logs/`,\n {\n method: \"POST\",\n ...options,\n headers,\n body: JSON.stringify({\n source_path: sourcePath,\n referrer,\n }),\n revalidate: CACHE.NO_CACHE,\n tags: [\"redirects\", \"redirect-404-logs\"],\n retries: 0,\n },\n );\n }\n\n // ============================================================================\n // Store — Products, Categories, Brands, Collections, Orders\n // Note: Uses /api/public/store/ prefix (NOT /api/public/cms/)\n // ============================================================================\n\n function fetchStoreSettings(\n siteId: string,\n options?: FetchOptions,\n ): Promise<StoreSettings | null> {\n return cmsFetch<StoreSettings>(`/api/public/store/${siteId}/settings/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"store-settings\"],\n ...options,\n });\n }\n\n function fetchProductCategories(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n ordering?: string;\n parent_id?: string | null;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductCategory>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductCategory>(\n `/api/public/store/${siteId}/categories/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"product-categories\"],\n ...options,\n },\n );\n }\n\n function fetchProductBrands(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n ordering?: string;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductBrand>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductBrand>(\n `/api/public/store/${siteId}/brands/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"product-brands\"],\n ...options,\n },\n );\n }\n\n function fetchProducts(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n category_id?: string;\n tag_id?: string;\n brand_id?: string;\n is_featured?: \"true\" | \"false\";\n sort?: \"price_asc\" | \"price_desc\";\n min_price?: number;\n max_price?: number;\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductListItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductListItem>(\n `/api/public/store/${siteId}/products/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"products\"],\n ...options,\n },\n );\n }\n\n function fetchProductDetail(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Product | null> {\n return cmsFetch<Product>(`/api/public/store/${siteId}/products/${slug}/`, {\n revalidate: CACHE.SHORT,\n tags: [\"products\", `product-${slug}`],\n ...options,\n });\n }\n\n function fetchProductsByTag(\n siteId: string,\n tag: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<{ item: unknown; product: Product }> | null> {\n const query = buildQueryString({ tag, ...params });\n return cmsFetch<PaginatedResponse<{ item: unknown; product: Product }>>(\n `/api/public/store/${siteId}/products/by-tag/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"products\", `products-tag-${tag}`],\n ...options,\n },\n );\n }\n\n function fetchCollections(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n /** Comma-separated list of collection IDs (e.g., \"id1,id2\") */\n id?: string;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Collection>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Collection>(\n `/api/public/store/${siteId}/collections/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\"],\n ...options,\n },\n );\n }\n\n function fetchCollectionDetail(\n siteId: string,\n slug: string,\n params: {\n page?: number;\n limit?: number;\n category_id?: string;\n sort?: \"name_asc\" | \"name_desc\";\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<CollectionDetail | null> {\n const query = buildQueryString(params);\n return cmsFetch<CollectionDetail>(\n `/api/public/store/${siteId}/collections/${slug}/${\n query ? `?${query}` : \"\"\n }`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\", `collection-${slug}`],\n ...options,\n },\n );\n }\n\n function fetchCollectionDetailById(\n siteId: string,\n id: string,\n params: {\n page?: number;\n limit?: number;\n category_id?: string;\n sort?: \"name_asc\" | \"name_desc\";\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<CollectionDetail | null> {\n const query = buildQueryString(params);\n return cmsFetch<CollectionDetail>(\n `/api/public/store/${siteId}/collections/id/${id}/${\n query ? `?${query}` : \"\"\n }`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\", `collection-${id}`],\n ...options,\n },\n );\n }\n\n function placeOrder(\n siteId: string,\n payload: PlaceOrderPayload,\n options?: FetchOptions,\n ): Promise<Order | null> {\n return cmsFetch<Order>(`/api/public/store/${siteId}/orders/`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n revalidate: CACHE.NO_CACHE,\n retries: 0,\n ...options,\n });\n }\n\n // ============================================================================\n // Sitemap — public endpoints for XML sitemap generation (fetch once per day)\n // ============================================================================\n\n function fetchSitemapBlogs(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapBlogItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapBlogItem>(\n `/api/public/cms/${siteId}/sitemap/blogs/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-blogs\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapPages(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapPageItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapPageItem>(\n `/api/public/cms/${siteId}/sitemap/pages/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-pages\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapProducts(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapProductItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapProductItem>(\n `/api/public/store/${siteId}/sitemap/products/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-products\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapCollections(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapCollectionItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapCollectionItem>(\n `/api/public/store/${siteId}/sitemap/collections/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-collections\"],\n ...options,\n },\n );\n }\n\n // Resource key -> backend path. Store resources are namespaced under\n // /store/ and their keys are prefixed to avoid colliding with the CMS\n // `categories` route, which is a different resource entirely.\n const SITEMAP_ROUTES: Record<\n SitemapResource,\n { segment: string; store: boolean }\n > = {\n blogs: { segment: \"blogs\", store: false },\n pages: { segment: \"pages\", store: false },\n services: { segment: \"services\", store: false },\n events: { segment: \"events\", store: false },\n albums: { segment: \"albums\", store: false },\n \"team-members\": { segment: \"team-members\", store: false },\n \"team-categories\": { segment: \"team-categories\", store: false },\n \"brand-groups\": { segment: \"brand-groups\", store: false },\n products: { segment: \"products\", store: true },\n collections: { segment: \"collections\", store: true },\n \"product-categories\": { segment: \"categories\", store: true },\n \"product-brands\": { segment: \"brands\", store: true },\n };\n\n /**\n * Fetch any sitemap resource. Returns slug/url, title/name, image (where\n * the content type has one) and `updatedAt` for `lastModified`.\n */\n function fetchSitemap<R extends SitemapResource>(\n siteId: string,\n resource: R,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapResourceMap[R]>> {\n const { segment, store } = SITEMAP_ROUTES[resource];\n const namespace = store ? \"store\" : \"cms\";\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapResourceMap[R]>(\n `/api/public/${namespace}/${siteId}/sitemap/${segment}/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", `sitemap-${resource}`],\n ...options,\n },\n );\n }\n\n return {\n // Default page size for list endpoints (categories, team, brands, testimonials, etc.)\n LIST_DEFAULT_LIMIT,\n // Header, Footer, Site Config\n fetchHeader,\n fetchFooter,\n fetchSiteConfig,\n // Pages\n fetchPages,\n fetchPageByUrl,\n // About\n fetchAboutUs,\n // Services\n fetchServices,\n fetchServiceBySlug,\n // Blogs\n fetchBlogs,\n fetchBlogBySlug,\n fetchBlogById,\n // Categories\n fetchCategories,\n // Team Members\n fetchTeamMembers,\n fetchTeamMembersByCategory,\n // Albums\n fetchAlbums,\n fetchAlbumItems,\n // Brands\n fetchBrandGroups,\n fetchBrands,\n // Testimonials\n fetchTestimonials,\n // Events\n fetchEvents,\n fetchEventBySlug,\n // FAQ Groups\n fetchFaqGroups,\n fetchFaqs,\n // Redirects\n fetchRedirects,\n resolveRedirect,\n reportRedirect404,\n // Contact\n submitContactForm,\n fetchContactConfig,\n // Store\n fetchStoreSettings,\n fetchProductCategories,\n fetchProductBrands,\n fetchProducts,\n fetchProductDetail,\n fetchProductsByTag,\n fetchCollections,\n fetchCollectionDetail,\n fetchCollectionDetailById,\n placeOrder,\n // Sitemap\n fetchSitemap,\n fetchSitemapBlogs,\n fetchSitemapPages,\n fetchSitemapProducts,\n fetchSitemapCollections,\n // Generic fetch utilities\n fetch: cmsFetch,\n fetchPaginated: cmsFetchPaginated,\n utils: {\n buildQueryString,\n },\n };\n}\n","export const ICON_NAMES = [\n \"Home\",\n \"User\",\n \"Settings\",\n \"Mail\",\n \"Bell\",\n \"Calendar\",\n \"Star\",\n \"Heart\",\n \"Bookmark\",\n \"Search\",\n \"Filter\",\n \"Download\",\n \"Upload\",\n \"Trash\",\n \"Edit\",\n \"Plus\",\n \"Minus\",\n \"Check\",\n \"X\",\n \"ChevronRight\",\n \"ChevronLeft\",\n \"ChevronUp\",\n \"ChevronDown\",\n \"ChevronsUpDown\",\n \"ArrowRight\",\n \"ArrowLeft\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"File\",\n \"Folder\",\n \"Image\",\n \"Video\",\n \"Music\",\n \"Lock\",\n \"Unlock\",\n \"Eye\",\n \"EyeOff\",\n \"Sun\",\n \"Moon\",\n \"Cloud\",\n \"Zap\",\n \"Activity\",\n \"TrendingUp\",\n \"TrendingDown\",\n \"BarChart\",\n \"PieChart\",\n \"Database\",\n \"Server\",\n \"Wifi\",\n \"Battery\",\n \"Camera\",\n \"Mic\",\n \"Phone\",\n \"MessageSquare\",\n \"Send\",\n \"Share\",\n \"Link\",\n \"ExternalLink\",\n \"Globe\",\n \"MapPin\",\n \"Users\",\n \"ShoppingCart\",\n \"CreditCard\",\n \"Package\",\n \"Briefcase\",\n \"Target\",\n \"Flag\",\n \"Clipboard\",\n \"List\",\n \"Grid\",\n \"Layout\",\n \"Layers\",\n \"Copy\",\n \"Save\",\n \"RefreshCw\",\n \"Maximize\",\n \"Code\",\n \"AlertCircle\",\n \"Info\",\n \"HelpCircle\",\n \"CheckCircle\",\n \"XCircle\",\n \"Menu\",\n \"MoreVertical\",\n \"MoreHorizontal\",\n \"PlayCircle\",\n \"PauseCircle\",\n \"LogIn\",\n \"LogOut\",\n \"UserPlus\",\n \"UserMinus\",\n \"Tag\",\n \"Award\",\n \"Gift\",\n \"Truck\",\n \"Clock\",\n \"Handshake\",\n \"Stethoscope\",\n \"Microscope\",\n \"GraduationCap\",\n \"BookOpen\",\n \"Building2\",\n \"Trees\",\n \"HeartHandshake\",\n \"Brain\",\n \"Lightbulb\",\n] as const;\n\nexport type IconName = (typeof ICON_NAMES)[number];\n"],"mappings":"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U,MAC/E;GACE,YAAY,MAAM;GAClB,MAAM,CAAC,WAAW,WAAW,UAAU;GACvC,GAAG;EACL,CACF;CACF;CAEA,OAAO;EAEL;EAEA;EACA;EACA;EAEA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA,OAAO;EACP,gBAAgB;EAChB,OAAO,EACL,iBACF;CACF;AACF;;;AClqCA,MAAa,aAAa;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants/pageTypes.ts","../src/constants/index.ts","../src/types/contact.ts","../src/core/client.ts","../src/types/icon.ts"],"sourcesContent":["/**\n * Page type identifiers. Mirrors cms-backend/src/constants/pageTypes.ts.\n *\n * `pageTypes` are the singleton types — a site may have at most one page of\n * each, enforced on create by the backend (cms/page/page.routes.ts). Attempting\n * a second one is rejected with \"A page with type \"<type>\" already exists for\n * this site\". `custom` is the only repeatable type.\n */\nexport const pageTypes = [\n \"home\",\n \"about\",\n \"contact\",\n \"services\",\n \"blog\",\n \"team\",\n \"gallery\",\n \"events\",\n \"clients-partners\",\n \"testimonial\",\n \"faq\",\n] as const;\n\n/** The full set accepted by the backend's page validator. */\nexport const allPageTypes = [...pageTypes, \"custom\"] as const;\n\nexport type PageType = (typeof allPageTypes)[number];\n","export * from \"./pageTypes\";\n\nexport const PAGINATION = {\n DEFAULT_PAGE: 1,\n DEFAULT_LIMIT: 10,\n LIST_DEFAULT_LIMIT: 20,\n BLOGS_PER_PAGE: 9,\n EVENTS_PER_PAGE: 9,\n ALBUMS_PER_PAGE: 9,\n MAX_ITEMS_FOR_SSG: 200,\n} as const;\n\nexport const SEARCH = {\n DEBOUNCE_MS: 500,\n MIN_QUERY_LENGTH: 2,\n} as const;\n\nexport const CACHE = {\n NO_CACHE: 0,\n SHORT: 60, // 1 minute\n MEDIUM: 300, // 5 minutes\n LONG: 3600, // 1 hour\n STATIC: 86400, // 24 hours\n} as const;\n\nexport const ANIMATION = {\n FAST: 0.2,\n NORMAL: 0.3,\n SLOW: 0.6,\n} as const;\n\nexport const CONTACT_SUBJECTS = [\n \"General Inquiry\",\n \"Project Proposal\",\n \"Careers\",\n \"Other\",\n] as const;\n\nexport const HTTP_STATUS = {\n OK: 200,\n CREATED: 201,\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n INTERNAL_ERROR: 500,\n} as const;\n\nexport const MEDIA = {\n IMAGE_EXTENSIONS: [\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".svg\"],\n VIDEO_EXTENSIONS: [\".mp4\", \".webm\", \".ogg\"],\n MAX_IMAGE_SIZE: 5 * 1024 * 1024,\n} as const;\n","export interface ContactPayload {\n name: string;\n email?: string | null;\n subject?: string | null;\n message: string;\n type?: string;\n /**\n * Cloudflare Turnstile token from the widget on your form.\n *\n * Required whenever the site has Turnstile enabled — check with\n * `fetchContactConfig(siteId)`. Submitting without one is rejected with 403\n * (`CmsError`), and the token is single-use: on a failed submit, reset the\n * widget before retrying rather than resending the same value.\n */\n turnstile_token?: string;\n}\n\nexport interface Contact extends ContactPayload {\n id: string;\n site_id: string;\n is_read: boolean;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Public Turnstile settings for a site's contact form, from\n * GET /:site_id/contact-config/.\n *\n * Named to avoid colliding with `ContactConfig` in ./site-config, which is the\n * site's displayed contact details (phone, email, socials) and unrelated.\n *\n * `enabled` with a null `site_key` means the site is misconfigured: the widget\n * cannot render and submissions will be rejected. Treat it as \"do not show the\n * form\" rather than \"no captcha needed\".\n */\nexport interface PublicContactConfig {\n turnstile: {\n enabled: boolean;\n site_key: string | null;\n };\n}\n\n/** Attachment caps enforced by the API; mirrored here to fail fast client-side. */\nexport const MAX_CONTACT_ATTACHMENTS = 3;\n/**\n * Total attachment budget, measured on RAW bytes.\n *\n * Attachments are forwarded onto the notification email, so the ceiling is\n * Cloudflare Email's 5 MiB message limit — but the wire format is base64, 4/3\n * the size. 3 MiB raw leaves headroom; 4 MiB encoded to ~5.33 MiB and was\n * already over. Keep in step with MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES in\n * cms-backend/src/constants/limits.ts.\n */\nexport const MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES = 3 * 1024 * 1024;\nexport const CONTACT_ATTACHMENT_MIME_ALLOWLIST: readonly string[] = [\n \"application/pdf\",\n \"image/png\",\n \"image/jpeg\",\n \"image/webp\",\n \"image/gif\",\n \"text/plain\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n];\n","import { CACHE, PAGINATION } from \"../constants\";\nimport type { PaginatedResponse } from \"../types/pagination\";\nimport type { Header } from \"../types/header\";\nimport type { Footer } from \"../types/footer\";\nimport type { SiteConfig } from \"../types/site-config\";\nimport type { Page, PageListItem } from \"../types/cms-page\";\nimport type { PageType } from \"../constants/pageTypes\";\nimport type { AboutUsData } from \"../types/about\";\nimport type { Service } from \"../types/service\";\nimport type { Blog } from \"../types/blog\";\nimport type { Category } from \"../types/category\";\nimport type { TeamMember } from \"../types/team-member\";\nimport type { Album, AlbumItem } from \"../types/album\";\nimport type { BrandGroup, Brand } from \"../types/brand\";\nimport type { Testimonial } from \"../types/testimonials\";\nimport type { Event } from \"../types/event\";\nimport type { Faq } from \"../types/faq\";\nimport type { FaqGroup } from \"../types/faq-group\";\nimport type { Redirect, Redirect404Log, ResolvedRedirect } from \"../types/redirect\";\nimport type {\n ContactPayload,\n Contact,\n PublicContactConfig,\n} from \"../types/contact\";\nimport {\n MAX_CONTACT_ATTACHMENTS,\n MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES,\n CONTACT_ATTACHMENT_MIME_ALLOWLIST,\n} from \"../types/contact\";\nimport type { Product, ProductListItem, ProductVariant } from \"../types/product\";\nimport type { ProductCategory } from \"../types/product-category\";\nimport type { ProductBrand } from \"../types/product-brand\";\nimport type { Collection, CollectionDetail } from \"../types/collection\";\nimport type { Order, PlaceOrderPayload } from \"../types/order\";\nimport type { StoreSettings } from \"../types/store-setting\";\nimport type {\n SitemapBlogItem,\n SitemapPageItem,\n SitemapProductItem,\n SitemapCollectionItem,\n SitemapResource,\n SitemapResourceMap,\n} from \"../types/sitemap\";\n\nexport interface FetchOptions extends RequestInit {\n revalidate?: number;\n tags?: string[];\n retries?: number;\n}\n\nexport interface CmsClientConfig {\n baseUrl: string;\n defaultOptions?: FetchOptions;\n}\n\nexport class CmsError extends Error {\n constructor(\n public message: string,\n public status?: number,\n public url?: string,\n ) {\n super(message);\n this.name = \"CmsError\";\n }\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport function createCmsClient(config: CmsClientConfig) {\n const { baseUrl, defaultOptions = {} } = config;\n\n async function cmsFetch<T>(\n endpoint: string,\n options: FetchOptions = {},\n ): Promise<T | null> {\n const url = `${baseUrl}${endpoint}`;\n const {\n revalidate = CACHE.NO_CACHE,\n tags,\n retries = 1,\n ...rest\n } = { ...defaultOptions, ...options };\n\n const fetchConfig: RequestInit & {\n next?: { revalidate?: number; tags?: string[] };\n } = {\n ...rest,\n next: {\n revalidate,\n ...(tags && { tags }),\n },\n };\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, fetchConfig);\n\n if (!response.ok) {\n // Retry on transient server errors (502, 503, 504)\n if (attempt < retries && [502, 503, 504].includes(response.status)) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n let errorMsg = `API request failed: ${response.status} ${url}`;\n try {\n const body = await response.json();\n if (body?.message) errorMsg = body.message;\n } catch {\n // body not JSON, keep fallback\n }\n throw new CmsError(errorMsg, response.status, url);\n }\n\n // 204 / empty body — nothing to parse\n if (response.status === 204) {\n return null;\n }\n\n const result = await response.json();\n return result.data ?? result;\n } catch (error) {\n if (error instanceof CmsError) throw error;\n\n if (attempt < retries) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n const msg =\n error instanceof Error ? error.message : String(error);\n throw new CmsError(`Request failed: ${msg}`, undefined, url);\n }\n }\n\n throw new CmsError(`Request failed after ${retries + 1} attempts`, undefined, url);\n }\n\n async function cmsFetchPaginated<T>(\n endpoint: string,\n options: FetchOptions = {},\n ): Promise<PaginatedResponse<T>> {\n const url = `${baseUrl}${endpoint}`;\n const {\n revalidate = CACHE.NO_CACHE,\n tags,\n retries = 1,\n ...rest\n } = { ...defaultOptions, ...options };\n\n const fetchConfig: RequestInit & {\n next?: { revalidate?: number; tags?: string[] };\n } = {\n ...rest,\n next: {\n revalidate,\n ...(tags && { tags }),\n },\n };\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const response = await fetch(url, fetchConfig);\n\n if (!response.ok) {\n if (attempt < retries && [502, 503, 504].includes(response.status)) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n let errorMsg = `API request failed: ${response.status} ${url}`;\n try {\n const body = await response.json();\n if (body?.message) errorMsg = body.message;\n } catch {\n // body not JSON, keep fallback\n }\n throw new CmsError(errorMsg, response.status, url);\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof CmsError) throw error;\n\n if (attempt < retries) {\n await sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n const msg =\n error instanceof Error ? error.message : String(error);\n throw new CmsError(`Request failed: ${msg}`, undefined, url);\n }\n }\n\n throw new CmsError(`Request failed after ${retries + 1} attempts`, undefined, url);\n }\n\n function buildQueryString(\n params: Record<string, string | number | string[] | number[] | undefined | null>,\n ): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n value.forEach((v) => query.append(key, String(v)));\n } else {\n query.append(key, String(value));\n }\n }\n });\n return query.toString();\n }\n\n // Default page size for list endpoints (categories, team, brands, testimonials,\n // faq-groups, faqs). Matches the backend's getPaginationParamsWithoutLimit(c, 20).\n // Album-items is NOT one of these: it uses getPaginationParams(c, 100), so its\n // server-side default is 10 and callers should pass an explicit `limit`.\n const LIST_DEFAULT_LIMIT = PAGINATION.LIST_DEFAULT_LIMIT;\n\n // ============================================================================\n // Header, Footer, Site Config\n // ============================================================================\n\n function fetchHeader(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Header | null> {\n return cmsFetch<Header>(`/api/public/cms/${siteId}/header/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"header\"],\n ...options,\n });\n }\n\n function fetchFooter(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Footer | null> {\n return cmsFetch<Footer>(`/api/public/cms/${siteId}/footer/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"footer\"],\n ...options,\n });\n }\n\n function fetchSiteConfig(\n siteId: string,\n options?: FetchOptions,\n ): Promise<SiteConfig | null> {\n return cmsFetch<SiteConfig>(`/api/public/cms/${siteId}/site-config/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"site-config\"],\n ...options,\n });\n }\n\n // ============================================================================\n // Pages\n // ============================================================================\n\n function fetchPages(\n siteId: string,\n params: { page?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<PageListItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<PageListItem>(\n `/api/public/cms/${siteId}/page/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"pages\"],\n ...options,\n },\n );\n }\n\n async function fetchPageByUrl(\n siteId: string,\n urlPath: string,\n options?: FetchOptions,\n ): Promise<Page | null> {\n const targetUrl =\n urlPath === \"/\" || urlPath === \"\"\n ? \"/\"\n : `/${urlPath.replace(/^\\/|\\/$/g, \"\")}`;\n\n return cmsFetch<Page>(\n `/api/public/cms/${siteId}/page/by-url/?url=${encodeURIComponent(targetUrl)}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"pages\", `page-${targetUrl || \"root\"}`],\n ...options,\n },\n );\n }\n\n /**\n * The site's single published page of a given type, with its sections — the\n * same payload as `fetchPageByUrl`. Prefer this when you know which kind of\n * page you want but not its url, since an editor can rename the url at any\n * time. Returns null when the site has no published page of that type.\n */\n async function fetchPageByType(\n siteId: string,\n pageType: PageType,\n options?: FetchOptions,\n ): Promise<Page | null> {\n return cmsFetch<Page>(\n `/api/public/cms/${siteId}/page/by-type/${encodeURIComponent(pageType)}/`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"pages\", `page-type-${pageType}`],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // About Us\n // ============================================================================\n\n function fetchAboutUs(\n siteId: string,\n options?: FetchOptions,\n ): Promise<AboutUsData | null> {\n return cmsFetch<AboutUsData>(`/api/public/cms/${siteId}/about-us/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"about\"],\n ...options,\n });\n }\n\n // ============================================================================\n // Services\n // ============================================================================\n\n async function fetchServices(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Service>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Service>(\n `/api/public/cms/${siteId}/services/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"services\"],\n ...options,\n },\n );\n }\n\n function fetchServiceBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Service | null> {\n return cmsFetch<Service>(`/api/public/cms/${siteId}/services/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"services\", `service-${slug}`],\n ...options,\n });\n }\n\n // ============================================================================\n // Blogs\n // ============================================================================\n\n function fetchBlogs(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Blog>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Blog>(`/api/public/cms/${siteId}/blog/?${query}`, {\n revalidate: CACHE.SHORT,\n tags: [\"blogs\"],\n ...options,\n });\n }\n\n function fetchBlogBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Blog | null> {\n return cmsFetch<Blog>(`/api/public/cms/${siteId}/blog/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"blogs\", `blog-${slug}`],\n ...options,\n });\n }\n\n // Backwards-compatible alias. Backend route resolves by slug.\n function fetchBlogById(\n siteId: string,\n idOrSlug: number | string,\n options?: FetchOptions,\n ): Promise<Blog | null> {\n return fetchBlogBySlug(siteId, String(idOrSlug), options);\n }\n\n // ============================================================================\n // Categories\n // ============================================================================\n\n function fetchCategories(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Category>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Category>(\n `/api/public/cms/${siteId}/categories/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"categories\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Team Members\n // ============================================================================\n\n function fetchTeamMembers(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<TeamMember>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<TeamMember>(\n `/api/public/cms/${siteId}/team-members/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"team\"],\n ...options,\n },\n );\n }\n\n function fetchTeamMembersByCategory(\n siteId: string,\n params: { categoryId: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<TeamMember>> {\n const query = buildQueryString({\n category_id: params.categoryId,\n page: params.page,\n limit: params.limit,\n });\n return cmsFetchPaginated<TeamMember>(\n `/api/public/cms/${siteId}/team-members/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"team\", `team-category-${params.categoryId}`],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Albums\n // ============================================================================\n\n function fetchAlbums(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Album>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Album>(\n `/api/public/cms/${siteId}/albums/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"albums\"],\n ...options,\n },\n );\n }\n\n function fetchAlbumItems(\n siteId: string,\n params: {\n /** Album slug. */\n album?: string;\n /** Comma-separated list of album IDs (e.g., \"id1,id2\") */\n album_id?: string;\n page?: number;\n /**\n * Defaults to 10 server-side (max 100) — pass an explicit value to get a\n * whole album, or several albums' worth for an album-group section.\n */\n limit?: number;\n },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<AlbumItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<AlbumItem>(\n `/api/public/cms/${siteId}/albums/album-items/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"album-items\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Brands\n // ============================================================================\n\n function fetchBrandGroups(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<BrandGroup>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<BrandGroup>(\n `/api/public/cms/${siteId}/brand-groups/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"brand-groups\"],\n ...options,\n },\n );\n }\n\n function fetchBrands(\n siteId: string,\n params: { group?: string; group_id?: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Brand>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Brand>(\n `/api/public/cms/${siteId}/brand-groups/brands/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"brands\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Testimonials\n // ============================================================================\n\n function fetchTestimonials(\n siteId: string,\n params?: { type?: \"testimonial\" | \"review\" | string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Testimonial>> {\n const query = buildQueryString({\n type: params?.type,\n page: params?.page,\n limit: params?.limit,\n });\n return cmsFetchPaginated<Testimonial>(\n `/api/public/cms/${siteId}/testimonials/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"testimonials\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Events\n // ============================================================================\n\n function fetchEvents(\n siteId: string,\n params: { page?: number; limit?: number; search?: string } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Event>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Event>(\n `/api/public/cms/${siteId}/events/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"events\"],\n ...options,\n },\n );\n }\n\n function fetchEventBySlug(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Event | null> {\n return cmsFetch<Event>(`/api/public/cms/${siteId}/events/${slug}`, {\n revalidate: CACHE.SHORT,\n tags: [\"events\", `event-${slug}`],\n ...options,\n });\n }\n\n // ============================================================================\n // FAQ Groups\n // ============================================================================\n\n function fetchFaqGroups(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<FaqGroup>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<FaqGroup>(\n `/api/public/cms/${siteId}/faq-groups/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"faq-groups\"],\n ...options,\n },\n );\n }\n\n /**\n * Public Turnstile settings for the site's contact form.\n *\n * Call this before rendering the form: when `turnstile.enabled` is true the\n * widget must be rendered with `turnstile.site_key` and its token passed to\n * `submitContactForm`, or every submission is rejected.\n */\n function fetchContactConfig(\n siteId: string,\n options?: FetchOptions,\n ): Promise<PublicContactConfig | null> {\n return cmsFetch<PublicContactConfig>(\n `/api/public/cms/${siteId}/contact-config/`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"contact-config\"],\n ...options,\n },\n );\n }\n\n /**\n * Submit the contact form.\n *\n * Unlike the read methods, this THROWS `CmsError` on a rejection rather than\n * returning null — a form needs to tell \"captcha failed, reset the widget\"\n * (403) apart from \"rate limited\" (429) and a network blip, and a single\n * `null` cannot carry that. `error.status` holds the HTTP status.\n *\n * Pass `attachments` to send files; the request then goes out as multipart\n * instead of JSON. Caps are enforced server-side and pre-checked here.\n */\n async function submitContactForm(\n siteId: string,\n payload: ContactPayload,\n attachments?: File[],\n options?: FetchOptions,\n ): Promise<Contact> {\n const url = `${baseUrl}/api/public/cms/${siteId}/contact/`;\n\n if (attachments?.length) {\n if (attachments.length > MAX_CONTACT_ATTACHMENTS) {\n throw new CmsError(\n `At most ${MAX_CONTACT_ATTACHMENTS} attachments are allowed`,\n 400,\n url,\n );\n }\n const totalBytes = attachments.reduce((sum, f) => sum + f.size, 0);\n if (totalBytes > MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES) {\n throw new CmsError(\n `Attachments exceed the ${\n MAX_CONTACT_ATTACHMENTS_TOTAL_BYTES / (1024 * 1024)\n } MiB total size limit`,\n 400,\n url,\n );\n }\n for (const f of attachments) {\n if (!CONTACT_ATTACHMENT_MIME_ALLOWLIST.includes(f.type)) {\n throw new CmsError(\n `Attachment type not allowed: ${f.type || \"unknown\"}`,\n 400,\n url,\n );\n }\n }\n }\n\n let body: BodyInit;\n const headers: Record<string, string> = {};\n if (attachments?.length) {\n // multipart — the runtime must set Content-Type so the boundary is right,\n // so no Content-Type header is set here.\n const form = new FormData();\n for (const [key, value] of Object.entries(payload)) {\n if (value !== undefined && value !== null) form.append(key, String(value));\n }\n for (const file of attachments) form.append(\"attachments\", file, file.name);\n body = form;\n } else {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(payload);\n }\n\n // No retries: the body may be a consumed stream, a resend would duplicate\n // the submission, and the one retryable-looking status here (503, a\n // misconfigured Turnstile) is a deployment fault that will not self-heal —\n // retrying it just burns the 1-per-60s write budget.\n let response: Response;\n try {\n response = await fetch(url, {\n ...options,\n method: \"POST\",\n headers: { ...headers, ...(options?.headers as Record<string, string>) },\n body,\n });\n } catch (error) {\n throw new CmsError(\n error instanceof Error ? error.message : \"Network request failed\",\n undefined,\n url,\n );\n }\n\n if (!response.ok) {\n // The API answers errors as { message }; fall back to the status text\n // when the body is not JSON (a proxy error page, say).\n let message = `Request failed with status ${response.status}`;\n try {\n const parsed = (await response.json()) as { message?: string };\n if (parsed?.message) message = parsed.message;\n } catch {\n // keep the fallback\n }\n throw new CmsError(message, response.status, url);\n }\n\n const result = await response.json();\n return (result.data ?? result) as Contact;\n }\n\n function fetchFaqs(\n siteId: string,\n params?: { group_id?: string; page?: number; limit?: number },\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Faq>> {\n const query = buildQueryString({\n group_id: params?.group_id,\n page: params?.page,\n limit: params?.limit,\n });\n return cmsFetchPaginated<Faq>(\n `/api/public/cms/${siteId}/faqs/?${query}`,\n {\n revalidate: CACHE.MEDIUM,\n tags: [\"faqs\"],\n ...options,\n },\n );\n }\n\n // ============================================================================\n // Redirects\n // ============================================================================\n\n async function fetchRedirects(\n siteId: string,\n options?: FetchOptions,\n ): Promise<Redirect[]> {\n const result = await cmsFetch<Redirect[]>(\n `/api/public/cms/${siteId}/redirects/`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"redirects\"],\n ...options,\n },\n );\n return result ?? [];\n }\n\n function resolveRedirect(\n siteId: string,\n sourcePath: string,\n options?: FetchOptions,\n ): Promise<ResolvedRedirect | null> {\n return cmsFetch<ResolvedRedirect>(\n `/api/public/cms/${siteId}/redirects/resolve/?sourcePath=${encodeURIComponent(sourcePath)}`,\n {\n revalidate: CACHE.NO_CACHE,\n tags: [\"redirects\", `redirect-${sourcePath}`],\n ...options,\n },\n );\n }\n\n function reportRedirect404(\n siteId: string,\n sourcePath: string,\n referrer?: string,\n options?: FetchOptions,\n ): Promise<Redirect404Log | null> {\n const headers = {\n \"Content-Type\": \"application/json\",\n ...(options?.headers ?? {}),\n };\n\n return cmsFetch<Redirect404Log>(\n `/api/public/cms/${siteId}/redirects/404-logs/`,\n {\n method: \"POST\",\n ...options,\n headers,\n body: JSON.stringify({\n source_path: sourcePath,\n referrer,\n }),\n revalidate: CACHE.NO_CACHE,\n tags: [\"redirects\", \"redirect-404-logs\"],\n retries: 0,\n },\n );\n }\n\n // ============================================================================\n // Store — Products, Categories, Brands, Collections, Orders\n // Note: Uses /api/public/store/ prefix (NOT /api/public/cms/)\n // ============================================================================\n\n function fetchStoreSettings(\n siteId: string,\n options?: FetchOptions,\n ): Promise<StoreSettings | null> {\n return cmsFetch<StoreSettings>(`/api/public/store/${siteId}/settings/`, {\n revalidate: CACHE.MEDIUM,\n tags: [\"store-settings\"],\n ...options,\n });\n }\n\n function fetchProductCategories(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n ordering?: string;\n parent_id?: string | null;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductCategory>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductCategory>(\n `/api/public/store/${siteId}/categories/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"product-categories\"],\n ...options,\n },\n );\n }\n\n function fetchProductBrands(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n ordering?: string;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductBrand>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductBrand>(\n `/api/public/store/${siteId}/brands/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"product-brands\"],\n ...options,\n },\n );\n }\n\n function fetchProducts(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n category_id?: string;\n tag_id?: string;\n brand_id?: string;\n is_featured?: \"true\" | \"false\";\n sort?: \"price_asc\" | \"price_desc\";\n min_price?: number;\n max_price?: number;\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<ProductListItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<ProductListItem>(\n `/api/public/store/${siteId}/products/?${query}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"products\"],\n ...options,\n },\n );\n }\n\n function fetchProductDetail(\n siteId: string,\n slug: string,\n options?: FetchOptions,\n ): Promise<Product | null> {\n return cmsFetch<Product>(`/api/public/store/${siteId}/products/${slug}/`, {\n revalidate: CACHE.SHORT,\n tags: [\"products\", `product-${slug}`],\n ...options,\n });\n }\n\n function fetchProductsByTag(\n siteId: string,\n tag: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<{ item: unknown; product: Product }> | null> {\n const query = buildQueryString({ tag, ...params });\n return cmsFetch<PaginatedResponse<{ item: unknown; product: Product }>>(\n `/api/public/store/${siteId}/products/by-tag/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"products\", `products-tag-${tag}`],\n ...options,\n },\n );\n }\n\n function fetchCollections(\n siteId: string,\n params: {\n page?: number;\n limit?: number;\n search?: string;\n /** Comma-separated list of collection IDs (e.g., \"id1,id2\") */\n id?: string;\n } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<Collection>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<Collection>(\n `/api/public/store/${siteId}/collections/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\"],\n ...options,\n },\n );\n }\n\n function fetchCollectionDetail(\n siteId: string,\n slug: string,\n params: {\n page?: number;\n limit?: number;\n category_id?: string;\n sort?: \"name_asc\" | \"name_desc\";\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<CollectionDetail | null> {\n const query = buildQueryString(params);\n return cmsFetch<CollectionDetail>(\n `/api/public/store/${siteId}/collections/${slug}/${\n query ? `?${query}` : \"\"\n }`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\", `collection-${slug}`],\n ...options,\n },\n );\n }\n\n function fetchCollectionDetailById(\n siteId: string,\n id: string,\n params: {\n page?: number;\n limit?: number;\n category_id?: string;\n sort?: \"name_asc\" | \"name_desc\";\n availability?: \"in_stock\" | \"out_of_stock\";\n } = {},\n options?: FetchOptions,\n ): Promise<CollectionDetail | null> {\n const query = buildQueryString(params);\n return cmsFetch<CollectionDetail>(\n `/api/public/store/${siteId}/collections/id/${id}/${\n query ? `?${query}` : \"\"\n }`,\n {\n revalidate: CACHE.SHORT,\n tags: [\"collections\", `collection-${id}`],\n ...options,\n },\n );\n }\n\n function placeOrder(\n siteId: string,\n payload: PlaceOrderPayload,\n options?: FetchOptions,\n ): Promise<Order | null> {\n return cmsFetch<Order>(`/api/public/store/${siteId}/orders/`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n revalidate: CACHE.NO_CACHE,\n retries: 0,\n ...options,\n });\n }\n\n // ============================================================================\n // Sitemap — public endpoints for XML sitemap generation (fetch once per day)\n // ============================================================================\n\n function fetchSitemapBlogs(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapBlogItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapBlogItem>(\n `/api/public/cms/${siteId}/sitemap/blogs/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-blogs\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapPages(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapPageItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapPageItem>(\n `/api/public/cms/${siteId}/sitemap/pages/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-pages\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapProducts(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapProductItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapProductItem>(\n `/api/public/store/${siteId}/sitemap/products/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-products\"],\n ...options,\n },\n );\n }\n\n function fetchSitemapCollections(\n siteId: string,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapCollectionItem>> {\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapCollectionItem>(\n `/api/public/store/${siteId}/sitemap/collections/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", \"sitemap-collections\"],\n ...options,\n },\n );\n }\n\n // Resource key -> backend path. Store resources are namespaced under\n // /store/ and their keys are prefixed to avoid colliding with the CMS\n // `categories` route, which is a different resource entirely.\n const SITEMAP_ROUTES: Record<\n SitemapResource,\n { segment: string; store: boolean }\n > = {\n blogs: { segment: \"blogs\", store: false },\n pages: { segment: \"pages\", store: false },\n services: { segment: \"services\", store: false },\n events: { segment: \"events\", store: false },\n albums: { segment: \"albums\", store: false },\n \"team-members\": { segment: \"team-members\", store: false },\n \"team-categories\": { segment: \"team-categories\", store: false },\n \"brand-groups\": { segment: \"brand-groups\", store: false },\n products: { segment: \"products\", store: true },\n collections: { segment: \"collections\", store: true },\n \"product-categories\": { segment: \"categories\", store: true },\n \"product-brands\": { segment: \"brands\", store: true },\n };\n\n /**\n * Fetch any sitemap resource. Returns slug/url, title/name, image (where\n * the content type has one) and `updatedAt` for `lastModified`.\n */\n function fetchSitemap<R extends SitemapResource>(\n siteId: string,\n resource: R,\n params: { page?: number; limit?: number } = {},\n options?: FetchOptions,\n ): Promise<PaginatedResponse<SitemapResourceMap[R]>> {\n const { segment, store } = SITEMAP_ROUTES[resource];\n const namespace = store ? \"store\" : \"cms\";\n const query = buildQueryString(params);\n return cmsFetchPaginated<SitemapResourceMap[R]>(\n `/api/public/${namespace}/${siteId}/sitemap/${segment}/${query ? `?${query}` : \"\"}`,\n {\n revalidate: CACHE.STATIC,\n tags: [\"sitemap\", `sitemap-${resource}`],\n ...options,\n },\n );\n }\n\n return {\n // Default page size for list endpoints (categories, team, brands, testimonials, etc.)\n LIST_DEFAULT_LIMIT,\n // Header, Footer, Site Config\n fetchHeader,\n fetchFooter,\n fetchSiteConfig,\n // Pages\n fetchPages,\n fetchPageByUrl,\n fetchPageByType,\n // About\n fetchAboutUs,\n // Services\n fetchServices,\n fetchServiceBySlug,\n // Blogs\n fetchBlogs,\n fetchBlogBySlug,\n fetchBlogById,\n // Categories\n fetchCategories,\n // Team Members\n fetchTeamMembers,\n fetchTeamMembersByCategory,\n // Albums\n fetchAlbums,\n fetchAlbumItems,\n // Brands\n fetchBrandGroups,\n fetchBrands,\n // Testimonials\n fetchTestimonials,\n // Events\n fetchEvents,\n fetchEventBySlug,\n // FAQ Groups\n fetchFaqGroups,\n fetchFaqs,\n // Redirects\n fetchRedirects,\n resolveRedirect,\n reportRedirect404,\n // Contact\n submitContactForm,\n fetchContactConfig,\n // Store\n fetchStoreSettings,\n fetchProductCategories,\n fetchProductBrands,\n fetchProducts,\n fetchProductDetail,\n fetchProductsByTag,\n fetchCollections,\n fetchCollectionDetail,\n fetchCollectionDetailById,\n placeOrder,\n // Sitemap\n fetchSitemap,\n fetchSitemapBlogs,\n fetchSitemapPages,\n fetchSitemapProducts,\n fetchSitemapCollections,\n // Generic fetch utilities\n fetch: cmsFetch,\n fetchPaginated: cmsFetchPaginated,\n utils: {\n buildQueryString,\n },\n };\n}\n","export const ICON_NAMES = [\n \"Home\",\n \"User\",\n \"Settings\",\n \"Mail\",\n \"Bell\",\n \"Calendar\",\n \"Star\",\n \"Heart\",\n \"Bookmark\",\n \"Search\",\n \"Filter\",\n \"Download\",\n \"Upload\",\n \"Trash\",\n \"Edit\",\n \"Plus\",\n \"Minus\",\n \"Check\",\n \"X\",\n \"ChevronRight\",\n \"ChevronLeft\",\n \"ChevronUp\",\n \"ChevronDown\",\n \"ChevronsUpDown\",\n \"ArrowRight\",\n \"ArrowLeft\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"File\",\n \"Folder\",\n \"Image\",\n \"Video\",\n \"Music\",\n \"Lock\",\n \"Unlock\",\n \"Eye\",\n \"EyeOff\",\n \"Sun\",\n \"Moon\",\n \"Cloud\",\n \"Zap\",\n \"Activity\",\n \"TrendingUp\",\n \"TrendingDown\",\n \"BarChart\",\n \"PieChart\",\n \"Database\",\n \"Server\",\n \"Wifi\",\n \"Battery\",\n \"Camera\",\n \"Mic\",\n \"Phone\",\n \"MessageSquare\",\n \"Send\",\n \"Share\",\n \"Link\",\n \"ExternalLink\",\n \"Globe\",\n \"MapPin\",\n \"Users\",\n \"ShoppingCart\",\n \"CreditCard\",\n \"Package\",\n \"Briefcase\",\n \"Target\",\n \"Flag\",\n \"Clipboard\",\n \"List\",\n \"Grid\",\n \"Layout\",\n \"Layers\",\n \"Copy\",\n \"Save\",\n \"RefreshCw\",\n \"Maximize\",\n \"Code\",\n \"AlertCircle\",\n \"Info\",\n \"HelpCircle\",\n \"CheckCircle\",\n \"XCircle\",\n \"Menu\",\n \"MoreVertical\",\n \"MoreHorizontal\",\n \"PlayCircle\",\n \"PauseCircle\",\n \"LogIn\",\n \"LogOut\",\n \"UserPlus\",\n \"UserMinus\",\n \"Tag\",\n \"Award\",\n \"Gift\",\n \"Truck\",\n \"Clock\",\n \"Handshake\",\n \"Stethoscope\",\n \"Microscope\",\n \"GraduationCap\",\n \"BookOpen\",\n \"Building2\",\n \"Trees\",\n \"HeartHandshake\",\n \"Brain\",\n \"Lightbulb\",\n] as const;\n\nexport type IconName = (typeof ICON_NAMES)[number];\n"],"mappings":"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GAC7C,SACmD;EACnD,MAAM,EAAE,SAAS,UAAU,eAAe;EAC1C,MAAM,YAAY,QAAQ,UAAU;EACpC,MAAM,QAAQ,iBAAiB,MAAM;EACrC,OAAO,kBACL,eAAe,UAAU,GAAG,OAAO,WAAW,QAAQ,GAAG,QAAQ,IAAI,UAAU,MAC/E;GACE,YAAY,MAAM;GAClB,MAAM,CAAC,WAAW,WAAW,UAAU;GACvC,GAAG;EACL,CACF;CACF;CAEA,OAAO;EAEL;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA,OAAO;EACP,gBAAgB;EAChB,OAAO,EACL,iBACF;CACF;AACF;;;AC3rCA,MAAa,aAAa;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|