@distinctagency/cms-client 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/queries.ts","../src/shop.ts","../src/analytics.tsx","../src/page-tracker.tsx","../src/cdn.ts"],"sourcesContent":["export { createCmsClient } from \"./queries\"\nexport { createShopClient } from \"./shop\"\nexport { CmsAnalytics } from \"./analytics\"\nexport { PageTracker } from \"./page-tracker\"\nexport { getTransformUrl, getSrcSet, IMAGE_PRESETS } from \"./cdn\"\nexport type { ImageTransformOptions } from \"./cdn\"\nexport type {\n FieldType,\n FieldDefinition,\n Tenant,\n Profile,\n ContentType,\n ContentItem,\n MediaItem,\n ContentQueryOptions,\n CmsClientOptions,\n TenantMembership,\n ImageConfig,\n ContentTypeSeoConfig,\n Product,\n ProductVariant,\n ProductOption,\n OrderAddress,\n CreateOrderParams,\n CreateOrderResult,\n ProductQueryOptions,\n} from \"./types\"\n","import { createClient as createSupabaseClient } from \"@supabase/supabase-js\"\nimport type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type {\n CmsClientOptions,\n ContentItem,\n ContentQueryOptions,\n ContentType,\n} from \"./types\"\n\n/**\n * Creates a CMS query client authenticated with a tenant API key.\n *\n * Usage:\n * ```ts\n * const cms = createCmsClient(supabase, { apiKey: process.env.CMS_API_KEY! })\n * const events = await cms.getContentItems('events', { status: 'published' })\n * ```\n *\n * The API key is sent as an `x-cms-api-key` header on every request.\n * Supabase RLS policies validate it against the tenant's stored key.\n */\nexport function createCmsClient(\n supabase: SupabaseClient,\n options: CmsClientOptions\n) {\n const { apiKey } = options\n\n // Create a new Supabase client with the API key header injected globally\n const client = withApiKey(supabase, apiKey) as SupabaseClient\n\n /** Resolve the tenant ID from the API key (cached per request) */\n let tenantIdCache: string | null = null\n\n async function getTenantId(): Promise<string> {\n if (tenantIdCache) return tenantIdCache\n\n const { data, error } = await client\n .from(\"tenants\")\n .select(\"id\")\n .single()\n\n if (error || !data) {\n throw new Error(\n \"Invalid CMS API key — no tenant found. Check your apiKey.\"\n )\n }\n\n tenantIdCache = data.id\n return data.id\n }\n\n /** Resolve a content type ID from its slug */\n async function getContentTypeId(contentTypeSlug: string): Promise<string> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data.id\n }\n\n return {\n /**\n * List content items for a content type.\n * Defaults to published items ordered by most recent.\n */\n async getContentItems(\n contentTypeSlug: string,\n options: ContentQueryOptions = {}\n ): Promise<ContentItem[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const {\n status = \"published\",\n orderBy = \"published_at\",\n orderDirection = \"desc\",\n limit = 100,\n offset = 0,\n } = options\n\n let query = client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n query = query\n .order(orderBy, { ascending: orderDirection === \"asc\" })\n .range(offset, offset + limit - 1)\n\n const { data, error } = await query\n\n if (error) {\n throw new Error(`Failed to fetch ${contentTypeSlug}: ${error.message}`)\n }\n\n return (data ?? []) as ContentItem[]\n },\n\n /**\n * Get a single content item by its slug.\n * Returns null if not found.\n */\n async getContentItemBySlug(\n contentTypeSlug: string,\n itemSlug: string\n ): Promise<ContentItem | null> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"slug\", itemSlug)\n .single()\n\n if (error) {\n if (error.code === \"PGRST116\") return null // not found\n throw new Error(\n `Failed to fetch ${contentTypeSlug}/${itemSlug}: ${error.message}`\n )\n }\n\n return data as ContentItem\n },\n\n /**\n * Get a content type definition (including its field schema).\n */\n async getContentType(contentTypeSlug: string): Promise<ContentType> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data as ContentType\n },\n\n /**\n * Get all slugs for a content type (for generateStaticParams).\n */\n async getAllSlugs(\n contentTypeSlug: string\n ): Promise<{ slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"slug\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"status\", \"published\")\n\n if (error) {\n throw new Error(\n `Failed to fetch slugs for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { slug: string }[]\n },\n\n /**\n * List all content types for this tenant.\n */\n async getContentTypes(): Promise<ContentType[]> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .order(\"name\")\n\n if (error) {\n throw new Error(`Failed to fetch content types: ${error.message}`)\n }\n\n return (data ?? []) as ContentType[]\n },\n\n /**\n * Get all slug redirects for a content type.\n * Use in next.config.js redirects() or middleware for 301s.\n * Returns: [{ old_slug, new_slug }, ...]\n */\n async getRedirects(\n contentTypeSlug: string\n ): Promise<{ old_slug: string; new_slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"slug_redirects\")\n .select(\"old_slug, new_slug\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (error) {\n throw new Error(\n `Failed to fetch redirects for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { old_slug: string; new_slug: string }[]\n },\n\n /**\n * Get all custom path redirects for this tenant.\n * Use alongside getRedirects() in next.config.ts for full redirect coverage.\n */\n async getCustomRedirects(): Promise<\n { source_path: string; destination_path: string; permanent: boolean }[]\n > {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"custom_redirects\")\n .select(\"source_path, destination_path, permanent\")\n .eq(\"tenant_id\", tenantId)\n\n if (error) {\n throw new Error(`Failed to fetch custom redirects: ${error.message}`)\n }\n\n return (data ?? []) as {\n source_path: string\n destination_path: string\n permanent: boolean\n }[]\n },\n\n /**\n * Get form submissions for a specific form.\n * Useful for displaying testimonials, reviews, etc.\n */\n async getFormSubmissions(\n formSlug: string,\n options: { status?: string; limit?: number; offset?: number } = {}\n ): Promise<Record<string, unknown>[]> {\n const tenantId = await getTenantId()\n\n const { data: form } = await client\n .from(\"forms\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n if (!form) return []\n\n const { limit = 50, offset = 0, status } = options\n\n let query = client\n .from(\"form_submissions\")\n .select(\"*\")\n .eq(\"form_id\", form.id)\n .eq(\"is_spam\", false)\n .order(\"created_at\", { ascending: false })\n .range(offset, offset + limit - 1)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n const { data } = await query\n return (data ?? []) as Record<string, unknown>[]\n },\n\n /**\n * Get a form configuration by slug.\n */\n async getForm(\n formSlug: string\n ): Promise<Record<string, unknown> | null> {\n const tenantId = await getTenantId()\n\n const { data } = await client\n .from(\"forms\")\n .select(\"id, name, slug, description, is_active\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n return data as Record<string, unknown> | null\n },\n }\n}\n\n/**\n * Creates a new Supabase client that includes the `x-cms-api-key`\n * header in every request, using the same URL and key as the original.\n */\nfunction withApiKey(supabase: SupabaseClient, apiKey: string) {\n // Extract URL and key from the existing client\n const supabaseUrl = (supabase as unknown as { supabaseUrl: string }).supabaseUrl\n const supabaseKey = (supabase as unknown as { supabaseKey: string }).supabaseKey\n\n return createSupabaseClient(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n \"x-cms-api-key\": apiKey,\n },\n },\n })\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type { Product, ProductQueryOptions, CreateOrderParams, CreateOrderResult } from \"./types\"\n\nexport function createShopClient(supabase: SupabaseClient, options: { apiKey: string; appUrl?: string }) {\n const { apiKey, appUrl } = options\n\n return {\n async getProducts(queryOptions?: ProductQueryOptions): Promise<Product[]> {\n let query = supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"status\", \"published\")\n .order(queryOptions?.sort ?? \"sort_order\", { ascending: (queryOptions?.order ?? \"asc\") === \"asc\" })\n\n if (queryOptions?.category) {\n query = query.eq(\"category\", queryOptions.category)\n }\n if (queryOptions?.tags?.length) {\n query = query.overlaps(\"tags\", queryOptions.tags)\n }\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit)\n }\n if (queryOptions?.offset) {\n query = query.range(queryOptions.offset, queryOptions.offset + (queryOptions.limit ?? 50) - 1)\n }\n\n const { data } = await query\n return (data ?? []) as Product[]\n },\n\n async getProductBySlug(slug: string): Promise<Product | null> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"slug\", slug)\n .eq(\"status\", \"published\")\n .single()\n return (data as Product) ?? null\n },\n\n async getProductCategories(): Promise<string[]> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null)\n const categories = [...new Set((data ?? []).map((d: { category: string }) => d.category))]\n return categories.sort()\n },\n\n async createOrder(params: CreateOrderParams): Promise<CreateOrderResult> {\n // This must go through the API (not direct Supabase) because\n // order creation requires server-side Stripe PaymentIntent creation\n const baseUrl = appUrl ?? \"\"\n const res = await fetch(`${baseUrl}/api/orders/create`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ api_key: apiKey, ...params }),\n })\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Order creation failed\" }))\n throw new Error(err.error ?? \"Order creation failed\")\n }\n return res.json()\n },\n }\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\n\ninterface CmsAnalyticsProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Content item ID (from CMS) */\n contentItemId?: string\n /** Content type slug (e.g. \"blog_posts\") */\n contentTypeSlug: string\n /** Item slug (e.g. \"my-post\") */\n itemSlug: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Drop-in analytics component for CMS content pages.\n * Tracks page views, scroll depth, and time on page.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage:\n * ```tsx\n * <CmsAnalytics\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * contentTypeSlug=\"blog_posts\"\n * itemSlug={params.slug}\n * />\n * ```\n */\nexport function CmsAnalytics({\n trackingUrl,\n apiKey,\n contentItemId,\n contentTypeSlug,\n itemSlug,\n trackScroll = true,\n trackTime = true,\n}: CmsAnalyticsProps) {\n const sentRef = useRef(false)\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Only send page view once per mount\n if (sentRef.current) return\n sentRef.current = true\n\n // Page view event\n sendEvent(trackingUrl, {\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"page_view\",\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n })\n\n // Scroll tracking\n let scrollHandler: (() => void) | null = null\n if (trackScroll) {\n scrollHandler = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n window.addEventListener(\"scroll\", scrollHandler, { passive: true })\n }\n\n // Send engagement data on page leave\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const payload = JSON.stringify({\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"engagement\",\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n },\n })\n\n // Use sendBeacon for reliable delivery on page unload\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n if (trackScroll || trackTime) {\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n\n return () => {\n if (scrollHandler) window.removeEventListener(\"scroll\", scrollHandler)\n if (trackScroll || trackTime) window.removeEventListener(\"beforeunload\", handleUnload)\n }\n }, [trackingUrl, apiKey, contentItemId, contentTypeSlug, itemSlug, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {}) // fire and forget\n}\n\n/** Generate a random session ID (persists for the browser session) */\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\nimport { usePathname } from \"next/navigation\"\n\ninterface PageTrackerProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Site-wide page tracker. Add once in root layout to track all pages.\n * Automatically detects CMS content pages from URL structure.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage in src/app/layout.tsx:\n * ```tsx\n * import { PageTracker } from \"@distinctagency/cms-client\"\n *\n * <body>\n * {children}\n * <PageTracker\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * />\n * </body>\n * ```\n */\nexport function PageTracker({\n trackingUrl,\n apiKey,\n trackScroll = true,\n trackTime = true,\n}: PageTrackerProps) {\n const pathname = usePathname()\n const prevPathRef = useRef(\"\")\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Skip if same path (prevents double-fire on mount)\n if (pathname === prevPathRef.current) return\n prevPathRef.current = pathname\n\n // Reset engagement tracking for new page\n maxScrollRef.current = 0\n startTimeRef.current = Date.now()\n\n // Try to extract content type and item slug from URL\n // Supports patterns like /events/future-finance, /blog/my-post, etc.\n const segments = pathname.split(\"/\").filter(Boolean)\n const contentTypeSlug = segments[0] ?? null\n const itemSlug = segments.length >= 2 ? segments[segments.length - 1] : null\n\n // Fire page view\n sendEvent(trackingUrl, {\n api_key: apiKey,\n event_type: \"page_view\",\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n metadata: { path: pathname },\n })\n }, [pathname, trackingUrl, apiKey])\n\n // Scroll tracking\n useEffect(() => {\n if (!trackScroll) return\n\n const handleScroll = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n return () => window.removeEventListener(\"scroll\", handleScroll)\n }, [trackScroll])\n\n // Send engagement data on page leave\n useEffect(() => {\n if (!trackScroll && !trackTime) return\n\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const segments = prevPathRef.current.split(\"/\").filter(Boolean)\n\n const payload = JSON.stringify({\n api_key: apiKey,\n event_type: \"engagement\",\n content_type_slug: segments[0] ?? null,\n item_slug: segments.length >= 2 ? segments[segments.length - 1] : null,\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n path: prevPathRef.current,\n },\n })\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n window.addEventListener(\"beforeunload\", handleUnload)\n return () => window.removeEventListener(\"beforeunload\", handleUnload)\n }, [trackingUrl, apiKey, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {})\n}\n\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","/**\n * CDN image transform helpers using Supabase Storage's built-in image transformation.\n *\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n * Works both server-side and client-side (no Node.js-only APIs).\n */\n\nexport interface ImageTransformOptions {\n width?: number\n height?: number\n quality?: number\n resize?: \"contain\" | \"cover\" | \"fill\"\n format?: \"origin\" // Supabase doesn't support format param yet, but we plan for it\n}\n\n/**\n * Transform a Supabase Storage URL to use Supabase's image transformation.\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n */\nexport function getTransformUrl(\n originalUrl: string,\n options: ImageTransformOptions = {}\n): string {\n // Only transform Supabase storage URLs\n if (!originalUrl.includes(\"/storage/v1/object/public/\")) {\n return originalUrl\n }\n\n // Convert from /object/public/ to /render/image/public/\n const transformUrl = originalUrl.replace(\n \"/storage/v1/object/public/\",\n \"/storage/v1/render/image/public/\"\n )\n\n const params = new URLSearchParams()\n if (options.width) params.set(\"width\", String(options.width))\n if (options.height) params.set(\"height\", String(options.height))\n if (options.quality) params.set(\"quality\", String(options.quality))\n if (options.resize) params.set(\"resize\", options.resize)\n\n const qs = params.toString()\n return qs ? `${transformUrl}?${qs}` : transformUrl\n}\n\n/**\n * Generate a srcSet string for responsive images.\n */\nexport function getSrcSet(\n originalUrl: string,\n widths: number[] = [320, 640, 960, 1280, 1920],\n quality = 80\n): string {\n return widths\n .map(\n (w) =>\n `${getTransformUrl(originalUrl, { width: w, quality, resize: \"contain\" })} ${w}w`\n )\n .join(\", \")\n}\n\n/**\n * Generate common image sizes for different use cases.\n */\nexport const IMAGE_PRESETS = {\n thumbnail: { width: 150, height: 150, resize: \"cover\" as const, quality: 70 },\n card: { width: 400, height: 300, resize: \"cover\" as const, quality: 80 },\n hero: { width: 1200, height: 630, resize: \"cover\" as const, quality: 85 },\n og: { width: 1200, height: 630, resize: \"cover\" as const, quality: 90 },\n avatar: { width: 80, height: 80, resize: \"cover\" as const, quality: 75 },\n full: { width: 1920, resize: \"contain\" as const, quality: 85 },\n} as const\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAAqD;AAqB9C,SAAS,gBACd,UACA,SACA;AACA,QAAM,EAAE,OAAO,IAAI;AAGnB,QAAM,SAAS,WAAW,UAAU,MAAM;AAG1C,MAAI,gBAA+B;AAEnC,iBAAe,cAA+B;AAC5C,QAAI,cAAe,QAAO;AAE1B,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,SAAS,EACd,OAAO,IAAI,EACX,OAAO;AAEV,QAAI,SAAS,CAAC,MAAM;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,oBAAgB,KAAK;AACrB,WAAO,KAAK;AAAA,EACd;AAGA,iBAAe,iBAAiB,iBAA0C;AACxE,UAAM,WAAW,MAAM,YAAY;AAEnC,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,IAAI,EACX,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,eAAe,EAC1B,OAAO;AAEV,QAAI,SAAS,CAAC,MAAM;AAClB,YAAM,IAAI,MAAM,2BAA2B,eAAe,EAAE;AAAA,IAC9D;AAEA,WAAO,KAAK;AAAA,EACd;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL,MAAM,gBACJ,iBACAA,WAA+B,CAAC,GACR;AACxB,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,iBAAiB;AAAA,QACjB,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,IAAIA;AAEJ,UAAI,QAAQ,OACT,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,mBAAmB,aAAa;AAEtC,UAAI,QAAQ;AACV,gBAAQ,MAAM,GAAG,UAAU,MAAM;AAAA,MACnC;AAEA,cAAQ,MACL,MAAM,SAAS,EAAE,WAAW,mBAAmB,MAAM,CAAC,EACtD,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM;AAE9B,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,mBAAmB,eAAe,KAAK,MAAM,OAAO,EAAE;AAAA,MACxE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,qBACJ,iBACA,UAC6B;AAC7B,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,mBAAmB,aAAa,EACnC,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,UAAI,OAAO;AACT,YAAI,MAAM,SAAS,WAAY,QAAO;AACtC,cAAM,IAAI;AAAA,UACR,mBAAmB,eAAe,IAAI,QAAQ,KAAK,MAAM,OAAO;AAAA,QAClE;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,eAAe,iBAA+C;AAClE,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,eAAe,EAC1B,OAAO;AAEV,UAAI,SAAS,CAAC,MAAM;AAClB,cAAM,IAAI,MAAM,2BAA2B,eAAe,EAAE;AAAA,MAC9D;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,YACJ,iBAC6B;AAC7B,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,MAAM,EACb,GAAG,mBAAmB,aAAa,EACnC,GAAG,UAAU,WAAW;AAE3B,UAAI,OAAO;AACT,cAAM,IAAI;AAAA,UACR,6BAA6B,eAAe,KAAK,MAAM,OAAO;AAAA,QAChE;AAAA,MACF;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,kBAA0C;AAC9C,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,aAAa,QAAQ,EACxB,MAAM,MAAM;AAEf,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO,EAAE;AAAA,MACnE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,MAAM,aACJ,iBACmD;AACnD,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,gBAAgB,EACrB,OAAO,oBAAoB,EAC3B,GAAG,mBAAmB,aAAa;AAEtC,UAAI,OAAO;AACT,cAAM,IAAI;AAAA,UACR,iCAAiC,eAAe,KAAK,MAAM,OAAO;AAAA,QACpE;AAAA,MACF;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,qBAEJ;AACA,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,kBAAkB,EACvB,OAAO,0CAA0C,EACjD,GAAG,aAAa,QAAQ;AAE3B,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,qCAAqC,MAAM,OAAO,EAAE;AAAA,MACtE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IAKnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,mBACJ,UACAA,WAAgE,CAAC,GAC7B;AACpC,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,KAAK,IAAI,MAAM,OAC1B,KAAK,OAAO,EACZ,OAAO,IAAI,EACX,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,UAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,YAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,OAAO,IAAIA;AAE3C,UAAI,QAAQ,OACT,KAAK,kBAAkB,EACvB,OAAO,GAAG,EACV,GAAG,WAAW,KAAK,EAAE,EACrB,GAAG,WAAW,KAAK,EACnB,MAAM,cAAc,EAAE,WAAW,MAAM,CAAC,EACxC,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAEnC,UAAI,QAAQ;AACV,gBAAQ,MAAM,GAAG,UAAU,MAAM;AAAA,MACnC;AAEA,YAAM,EAAE,KAAK,IAAI,MAAM;AACvB,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,QACJ,UACyC;AACzC,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,KAAK,IAAI,MAAM,OACpB,KAAK,OAAO,EACZ,OAAO,wCAAwC,EAC/C,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,WAAW,UAA0B,QAAgB;AAE5D,QAAM,cAAe,SAAgD;AACrE,QAAM,cAAe,SAAgD;AAErE,aAAO,mBAAAC,cAAqB,aAAa,aAAa;AAAA,IACpD,QAAQ;AAAA,MACN,SAAS;AAAA,QACP,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AC9TO,SAAS,iBAAiB,UAA0B,SAA8C;AACvG,QAAM,EAAE,QAAQ,OAAO,IAAI;AAE3B,SAAO;AAAA,IACL,MAAM,YAAY,cAAwD;AACxE,UAAI,QAAQ,SACT,KAAK,UAAU,EACf,OAAO,6DAA6D,EACpE,GAAG,UAAU,WAAW,EACxB,MAAM,cAAc,QAAQ,cAAc,EAAE,YAAY,cAAc,SAAS,WAAW,MAAM,CAAC;AAEpG,UAAI,cAAc,UAAU;AAC1B,gBAAQ,MAAM,GAAG,YAAY,aAAa,QAAQ;AAAA,MACpD;AACA,UAAI,cAAc,MAAM,QAAQ;AAC9B,gBAAQ,MAAM,SAAS,QAAQ,aAAa,IAAI;AAAA,MAClD;AACA,UAAI,cAAc,OAAO;AACvB,gBAAQ,MAAM,MAAM,aAAa,KAAK;AAAA,MACxC;AACA,UAAI,cAAc,QAAQ;AACxB,gBAAQ,MAAM,MAAM,aAAa,QAAQ,aAAa,UAAU,aAAa,SAAS,MAAM,CAAC;AAAA,MAC/F;AAEA,YAAM,EAAE,KAAK,IAAI,MAAM;AACvB,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA,IAEA,MAAM,iBAAiB,MAAuC;AAC5D,YAAM,EAAE,KAAK,IAAI,MAAM,SACpB,KAAK,UAAU,EACf,OAAO,6DAA6D,EACpE,GAAG,QAAQ,IAAI,EACf,GAAG,UAAU,WAAW,EACxB,OAAO;AACV,aAAQ,QAAoB;AAAA,IAC9B;AAAA,IAEA,MAAM,uBAA0C;AAC9C,YAAM,EAAE,KAAK,IAAI,MAAM,SACpB,KAAK,UAAU,EACf,OAAO,UAAU,EACjB,GAAG,UAAU,WAAW,EACxB,IAAI,YAAY,MAAM,IAAI;AAC7B,YAAM,aAAa,CAAC,GAAG,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAA4B,EAAE,QAAQ,CAAC,CAAC;AACzF,aAAO,WAAW,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,YAAY,QAAuD;AAGvE,YAAM,UAAU,UAAU;AAC1B,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,sBAAsB;AAAA,QACtD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,QAAQ,GAAG,OAAO,CAAC;AAAA,MACrD,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,wBAAwB,EAAE;AAC7E,cAAM,IAAI,MAAM,IAAI,SAAS,uBAAuB;AAAA,MACtD;AACA,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,EACF;AACF;;;ACjEA,mBAAkC;AAoC3B,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,GAAsB;AACpB,QAAM,cAAU,qBAAO,KAAK;AAC5B,QAAM,mBAAe,qBAAO,CAAC;AAC7B,QAAM,mBAAe,qBAAO,KAAK,IAAI,CAAC;AACtC,QAAM,mBAAe,qBAAO,aAAa,CAAC;AAE1C,8BAAU,MAAM;AAEd,QAAI,QAAQ,QAAS;AACrB,YAAQ,UAAU;AAGlB,cAAU,aAAa;AAAA,MACrB,SAAS;AAAA,MACT,iBAAiB;AAAA,MACjB,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,UAAU,SAAS,YAAY;AAAA,MAC/B,YAAY,aAAa;AAAA,IAC3B,CAAC;AAGD,QAAI,gBAAqC;AACzC,QAAI,aAAa;AACf,sBAAgB,MAAM;AACpB,cAAM,eAAe,SAAS,gBAAgB,eAAe,OAAO;AACpE,YAAI,gBAAgB,EAAG;AACvB,cAAM,MAAM,KAAK,MAAO,OAAO,UAAU,eAAgB,GAAG;AAC5D,YAAI,MAAM,aAAa,QAAS,cAAa,UAAU;AAAA,MACzD;AACA,aAAO,iBAAiB,UAAU,eAAe,EAAE,SAAS,KAAK,CAAC;AAAA,IACpE;AAGA,UAAM,eAAe,MAAM;AACzB,YAAM,aAAa,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,WAAW,GAAI;AACxE,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,SAAS;AAAA,QACT,iBAAiB;AAAA,QACjB,mBAAmB;AAAA,QACnB,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,YAAY,aAAa;AAAA,QACzB,UAAU;AAAA,UACR,cAAc,aAAa;AAAA,UAC3B,cAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAGD,UAAI,UAAU,YAAY;AACxB,kBAAU,WAAW,aAAa,OAAO;AAAA,MAC3C;AAAA,IACF;AAEA,QAAI,eAAe,WAAW;AAC5B,aAAO,iBAAiB,gBAAgB,YAAY;AAAA,IACtD;AAEA,WAAO,MAAM;AACX,UAAI,cAAe,QAAO,oBAAoB,UAAU,aAAa;AACrE,UAAI,eAAe,UAAW,QAAO,oBAAoB,gBAAgB,YAAY;AAAA,IACvF;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,eAAe,iBAAiB,UAAU,aAAa,SAAS,CAAC;AAE1F,SAAO;AACT;AAEA,SAAS,UAAU,KAAa,MAA+B;AAC7D,QAAM,KAAK;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,WAAW;AAAA,EACb,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAGA,SAAS,eAAuB;AAC9B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,MAAM;AACZ,MAAI,MAAM,eAAe,QAAQ,GAAG;AACpC,MAAI,CAAC,KAAK;AACR,UAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE;AAClE,mBAAe,QAAQ,KAAK,GAAG;AAAA,EACjC;AACA,SAAO;AACT;;;ACpIA,IAAAC,gBAAkC;AAClC,wBAA4B;AAiCrB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,GAAqB;AACnB,QAAM,eAAW,+BAAY;AAC7B,QAAM,kBAAc,sBAAO,EAAE;AAC7B,QAAM,mBAAe,sBAAO,CAAC;AAC7B,QAAM,mBAAe,sBAAO,KAAK,IAAI,CAAC;AACtC,QAAM,mBAAe,sBAAOC,cAAa,CAAC;AAE1C,+BAAU,MAAM;AAEd,QAAI,aAAa,YAAY,QAAS;AACtC,gBAAY,UAAU;AAGtB,iBAAa,UAAU;AACvB,iBAAa,UAAU,KAAK,IAAI;AAIhC,UAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnD,UAAM,kBAAkB,SAAS,CAAC,KAAK;AACvC,UAAM,WAAW,SAAS,UAAU,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAGxE,IAAAC,WAAU,aAAa;AAAA,MACrB,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,UAAU,SAAS,YAAY;AAAA,MAC/B,YAAY,aAAa;AAAA,MACzB,UAAU,EAAE,MAAM,SAAS;AAAA,IAC7B,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,aAAa,MAAM,CAAC;AAGlC,+BAAU,MAAM;AACd,QAAI,CAAC,YAAa;AAElB,UAAM,eAAe,MAAM;AACzB,YAAM,eAAe,SAAS,gBAAgB,eAAe,OAAO;AACpE,UAAI,gBAAgB,EAAG;AACvB,YAAM,MAAM,KAAK,MAAO,OAAO,UAAU,eAAgB,GAAG;AAC5D,UAAI,MAAM,aAAa,QAAS,cAAa,UAAU;AAAA,IACzD;AAEA,WAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;AACjE,WAAO,MAAM,OAAO,oBAAoB,UAAU,YAAY;AAAA,EAChE,GAAG,CAAC,WAAW,CAAC;AAGhB,+BAAU,MAAM;AACd,QAAI,CAAC,eAAe,CAAC,UAAW;AAEhC,UAAM,eAAe,MAAM;AACzB,YAAM,aAAa,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,WAAW,GAAI;AACxE,YAAM,WAAW,YAAY,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAE9D,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,mBAAmB,SAAS,CAAC,KAAK;AAAA,QAClC,WAAW,SAAS,UAAU,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAAA,QAClE,YAAY,aAAa;AAAA,QACzB,UAAU;AAAA,UACR,cAAc,aAAa;AAAA,UAC3B,cAAc;AAAA,UACd,MAAM,YAAY;AAAA,QACpB;AAAA,MACF,CAAC;AAED,UAAI,UAAU,YAAY;AACxB,kBAAU,WAAW,aAAa,OAAO;AAAA,MAC3C;AAAA,IACF;AAEA,WAAO,iBAAiB,gBAAgB,YAAY;AACpD,WAAO,MAAM,OAAO,oBAAoB,gBAAgB,YAAY;AAAA,EACtE,GAAG,CAAC,aAAa,QAAQ,aAAa,SAAS,CAAC;AAEhD,SAAO;AACT;AAEA,SAASA,WAAU,KAAa,MAA+B;AAC7D,QAAM,KAAK;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,WAAW;AAAA,EACb,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAEA,SAASD,gBAAuB;AAC9B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,MAAM;AACZ,MAAI,MAAM,eAAe,QAAQ,GAAG;AACpC,MAAI,CAAC,KAAK;AACR,UAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE;AAClE,mBAAe,QAAQ,KAAK,GAAG;AAAA,EACjC;AACA,SAAO;AACT;;;AC1HO,SAAS,gBACd,aACA,UAAiC,CAAC,GAC1B;AAER,MAAI,CAAC,YAAY,SAAS,4BAA4B,GAAG;AACvD,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,YAAY;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC5D,MAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAC/D,MAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,OAAO,QAAQ,OAAO,CAAC;AAClE,MAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AAEvD,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,KAAK,GAAG,YAAY,IAAI,EAAE,KAAK;AACxC;AAKO,SAAS,UACd,aACA,SAAmB,CAAC,KAAK,KAAK,KAAK,MAAM,IAAI,GAC7C,UAAU,IACF;AACR,SAAO,OACJ;AAAA,IACC,CAAC,MACC,GAAG,gBAAgB,aAAa,EAAE,OAAO,GAAG,SAAS,QAAQ,UAAU,CAAC,CAAC,IAAI,CAAC;AAAA,EAClF,EACC,KAAK,IAAI;AACd;AAKO,IAAM,gBAAgB;AAAA,EAC3B,WAAW,EAAE,OAAO,KAAK,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EAC5E,MAAM,EAAE,OAAO,KAAK,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACvE,MAAM,EAAE,OAAO,MAAM,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACxE,IAAI,EAAE,OAAO,MAAM,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACtE,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACvE,MAAM,EAAE,OAAO,MAAM,QAAQ,WAAoB,SAAS,GAAG;AAC/D;","names":["options","createSupabaseClient","import_react","getSessionId","sendEvent"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/queries.ts","../src/shop.ts","../src/analytics.tsx","../src/page-tracker.tsx","../src/cdn.ts"],"sourcesContent":["export { createCmsClient } from \"./queries\"\nexport { createShopClient } from \"./shop\"\nexport { CmsAnalytics } from \"./analytics\"\nexport { PageTracker } from \"./page-tracker\"\nexport { getTransformUrl, getSrcSet, IMAGE_PRESETS } from \"./cdn\"\nexport type { ImageTransformOptions } from \"./cdn\"\nexport type {\n FieldType,\n FieldDefinition,\n Tenant,\n Profile,\n ContentType,\n ContentItem,\n MediaItem,\n ContentQueryOptions,\n CmsClientOptions,\n TenantMembership,\n ImageConfig,\n ContentTypeSeoConfig,\n Product,\n ProductVariant,\n ProductOption,\n OrderAddress,\n CreateOrderParams,\n CreateOrderResult,\n ProductQueryOptions,\n} from \"./types\"\n","import { createClient as createSupabaseClient } from \"@supabase/supabase-js\"\nimport type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type {\n CmsClientOptions,\n ContentItem,\n ContentQueryOptions,\n ContentType,\n} from \"./types\"\n\n/**\n * Creates a CMS query client authenticated with a tenant API key.\n *\n * Usage:\n * ```ts\n * const cms = createCmsClient(supabase, { apiKey: process.env.CMS_API_KEY! })\n * const events = await cms.getContentItems('events', { status: 'published' })\n * ```\n *\n * The API key is sent as an `x-cms-api-key` header on every request.\n * Supabase RLS policies validate it against the tenant's stored key.\n */\nexport function createCmsClient(\n supabase: SupabaseClient,\n options: CmsClientOptions\n) {\n const { apiKey } = options\n\n // Create a new Supabase client with the API key header injected globally\n const client = withApiKey(supabase, apiKey) as SupabaseClient\n\n /** Resolve the tenant ID from the API key (cached per request) */\n let tenantIdCache: string | null = null\n\n async function getTenantId(): Promise<string> {\n if (tenantIdCache) return tenantIdCache\n\n const { data, error } = await client\n .from(\"tenants\")\n .select(\"id\")\n .single()\n\n if (error || !data) {\n throw new Error(\n \"Invalid CMS API key — no tenant found. Check your apiKey.\"\n )\n }\n\n tenantIdCache = data.id\n return data.id\n }\n\n /** Resolve a content type ID from its slug */\n async function getContentTypeId(contentTypeSlug: string): Promise<string> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data.id\n }\n\n return {\n /**\n * List content items for a content type.\n * Defaults to published items ordered by most recent.\n */\n async getContentItems(\n contentTypeSlug: string,\n options: ContentQueryOptions = {}\n ): Promise<ContentItem[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const {\n status = \"published\",\n orderBy = \"published_at\",\n orderDirection = \"desc\",\n limit = 100,\n offset = 0,\n } = options\n\n let query = client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n query = query\n .order(orderBy, { ascending: orderDirection === \"asc\" })\n .range(offset, offset + limit - 1)\n\n const { data, error } = await query\n\n if (error) {\n throw new Error(`Failed to fetch ${contentTypeSlug}: ${error.message}`)\n }\n\n return (data ?? []) as ContentItem[]\n },\n\n /**\n * Get a single content item by its slug.\n * Returns null if not found.\n */\n async getContentItemBySlug(\n contentTypeSlug: string,\n itemSlug: string\n ): Promise<ContentItem | null> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"slug\", itemSlug)\n .single()\n\n if (error) {\n if (error.code === \"PGRST116\") return null // not found\n throw new Error(\n `Failed to fetch ${contentTypeSlug}/${itemSlug}: ${error.message}`\n )\n }\n\n return data as ContentItem\n },\n\n /**\n * Get a content type definition (including its field schema).\n */\n async getContentType(contentTypeSlug: string): Promise<ContentType> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data as ContentType\n },\n\n /**\n * Get all slugs for a content type (for generateStaticParams).\n */\n async getAllSlugs(\n contentTypeSlug: string\n ): Promise<{ slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"slug\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"status\", \"published\")\n\n if (error) {\n throw new Error(\n `Failed to fetch slugs for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { slug: string }[]\n },\n\n /**\n * List all content types for this tenant.\n */\n async getContentTypes(): Promise<ContentType[]> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .order(\"name\")\n\n if (error) {\n throw new Error(`Failed to fetch content types: ${error.message}`)\n }\n\n return (data ?? []) as ContentType[]\n },\n\n /**\n * Get all slug redirects for a content type.\n * Use in next.config.js redirects() or middleware for 301s.\n * Returns: [{ old_slug, new_slug }, ...]\n */\n async getRedirects(\n contentTypeSlug: string\n ): Promise<{ old_slug: string; new_slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"slug_redirects\")\n .select(\"old_slug, new_slug\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (error) {\n throw new Error(\n `Failed to fetch redirects for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { old_slug: string; new_slug: string }[]\n },\n\n /**\n * Get all custom path redirects for this tenant.\n * Use alongside getRedirects() in next.config.ts for full redirect coverage.\n */\n async getCustomRedirects(): Promise<\n { source_path: string; destination_path: string; permanent: boolean }[]\n > {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"custom_redirects\")\n .select(\"source_path, destination_path, permanent\")\n .eq(\"tenant_id\", tenantId)\n\n if (error) {\n throw new Error(`Failed to fetch custom redirects: ${error.message}`)\n }\n\n return (data ?? []) as {\n source_path: string\n destination_path: string\n permanent: boolean\n }[]\n },\n\n /**\n * Get form submissions for a specific form.\n * Useful for displaying testimonials, reviews, etc.\n */\n async getFormSubmissions(\n formSlug: string,\n options: { status?: string; limit?: number; offset?: number } = {}\n ): Promise<Record<string, unknown>[]> {\n const tenantId = await getTenantId()\n\n const { data: form } = await client\n .from(\"forms\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n if (!form) return []\n\n const { limit = 50, offset = 0, status } = options\n\n let query = client\n .from(\"form_submissions\")\n .select(\"*\")\n .eq(\"form_id\", form.id)\n .eq(\"is_spam\", false)\n .order(\"created_at\", { ascending: false })\n .range(offset, offset + limit - 1)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n const { data } = await query\n return (data ?? []) as Record<string, unknown>[]\n },\n\n /**\n * Get a form configuration by slug.\n */\n async getForm(\n formSlug: string\n ): Promise<Record<string, unknown> | null> {\n const tenantId = await getTenantId()\n\n const { data } = await client\n .from(\"forms\")\n .select(\"id, name, slug, description, is_active\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n return data as Record<string, unknown> | null\n },\n }\n}\n\n/**\n * Creates a new Supabase client that includes the `x-cms-api-key`\n * header in every request, using the same URL and key as the original.\n */\nfunction withApiKey(supabase: SupabaseClient, apiKey: string) {\n // Extract URL and key from the existing client\n const supabaseUrl = (supabase as unknown as { supabaseUrl: string }).supabaseUrl\n const supabaseKey = (supabase as unknown as { supabaseKey: string }).supabaseKey\n\n return createSupabaseClient(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n \"x-cms-api-key\": apiKey,\n },\n },\n })\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type { Product, ProductQueryOptions, CreateOrderParams, CreateOrderResult } from \"./types\"\n\nexport function createShopClient(supabase: SupabaseClient, options: { apiKey: string; appUrl?: string }) {\n const { apiKey, appUrl } = options\n\n return {\n async getProducts(queryOptions?: ProductQueryOptions): Promise<Product[]> {\n let query = supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"status\", \"published\")\n .order(queryOptions?.sort ?? \"sort_order\", { ascending: (queryOptions?.order ?? \"asc\") === \"asc\" })\n\n if (queryOptions?.category) {\n query = query.eq(\"category\", queryOptions.category)\n }\n if (queryOptions?.tags?.length) {\n query = query.overlaps(\"tags\", queryOptions.tags)\n }\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit)\n }\n if (queryOptions?.offset) {\n query = query.range(queryOptions.offset, queryOptions.offset + (queryOptions.limit ?? 50) - 1)\n }\n\n const { data } = await query\n return (data ?? []) as Product[]\n },\n\n async getProductBySlug(slug: string): Promise<Product | null> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"slug\", slug)\n .eq(\"status\", \"published\")\n .single()\n return (data as Product) ?? null\n },\n\n async getProductCategories(): Promise<string[]> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null)\n const categories = [...new Set((data ?? []).map((d: { category: string }) => d.category))]\n return categories.sort()\n },\n\n async createOrder(params: CreateOrderParams): Promise<CreateOrderResult> {\n // This must go through the API (not direct Supabase) because\n // order creation requires server-side Stripe PaymentIntent creation\n const baseUrl = appUrl ?? \"\"\n const res = await fetch(`${baseUrl}/api/orders/create`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ api_key: apiKey, ...params }),\n })\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Order creation failed\" }))\n throw new Error(err.error ?? \"Order creation failed\")\n }\n return res.json()\n },\n }\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\n\ninterface CmsAnalyticsProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Content item ID (from CMS) */\n contentItemId?: string\n /** Content type slug (e.g. \"blog_posts\") */\n contentTypeSlug: string\n /** Item slug (e.g. \"my-post\") */\n itemSlug: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Drop-in analytics component for CMS content pages.\n * Tracks page views, scroll depth, and time on page.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage:\n * ```tsx\n * <CmsAnalytics\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * contentTypeSlug=\"blog_posts\"\n * itemSlug={params.slug}\n * />\n * ```\n */\nexport function CmsAnalytics({\n trackingUrl,\n apiKey,\n contentItemId,\n contentTypeSlug,\n itemSlug,\n trackScroll = true,\n trackTime = true,\n}: CmsAnalyticsProps) {\n const sentRef = useRef(false)\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Only send page view once per mount\n if (sentRef.current) return\n sentRef.current = true\n\n // Page view event\n sendEvent(trackingUrl, {\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"page_view\",\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n })\n\n // Scroll tracking\n let scrollHandler: (() => void) | null = null\n if (trackScroll) {\n scrollHandler = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n window.addEventListener(\"scroll\", scrollHandler, { passive: true })\n }\n\n // Send engagement data on page leave\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const payload = JSON.stringify({\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"engagement\",\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n },\n })\n\n // Use sendBeacon for reliable delivery on page unload\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n if (trackScroll || trackTime) {\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n\n return () => {\n if (scrollHandler) window.removeEventListener(\"scroll\", scrollHandler)\n if (trackScroll || trackTime) window.removeEventListener(\"beforeunload\", handleUnload)\n }\n }, [trackingUrl, apiKey, contentItemId, contentTypeSlug, itemSlug, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {}) // fire and forget\n}\n\n/** Generate a random session ID (persists for the browser session) */\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\nimport { usePathname } from \"next/navigation\"\n\ninterface PageTrackerProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Site-wide page tracker. Add once in root layout to track all pages.\n * Automatically detects CMS content pages from URL structure.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage in src/app/layout.tsx:\n * ```tsx\n * import { PageTracker } from \"@distinctagency/cms-client\"\n *\n * <body>\n * {children}\n * <PageTracker\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * />\n * </body>\n * ```\n */\nexport function PageTracker({\n trackingUrl,\n apiKey,\n trackScroll = true,\n trackTime = true,\n}: PageTrackerProps) {\n const pathname = usePathname()\n const prevPathRef = useRef(\"\")\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Skip if same path (prevents double-fire on mount)\n if (pathname === prevPathRef.current) return\n prevPathRef.current = pathname\n\n // Reset engagement tracking for new page\n maxScrollRef.current = 0\n startTimeRef.current = Date.now()\n\n // Try to extract content type and item slug from URL\n // Supports patterns like /events/future-finance, /blog/my-post, etc.\n const segments = pathname.split(\"/\").filter(Boolean)\n const contentTypeSlug = segments[0] ?? null\n const itemSlug = segments.length >= 2 ? segments[segments.length - 1] : null\n\n // Fire page view\n sendEvent(trackingUrl, {\n api_key: apiKey,\n event_type: \"page_view\",\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n metadata: { path: pathname },\n })\n }, [pathname, trackingUrl, apiKey])\n\n // Scroll tracking\n useEffect(() => {\n if (!trackScroll) return\n\n const handleScroll = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n return () => window.removeEventListener(\"scroll\", handleScroll)\n }, [trackScroll])\n\n // Send engagement data on page leave\n useEffect(() => {\n if (!trackScroll && !trackTime) return\n\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const segments = prevPathRef.current.split(\"/\").filter(Boolean)\n\n const payload = JSON.stringify({\n api_key: apiKey,\n event_type: \"engagement\",\n content_type_slug: segments[0] ?? null,\n item_slug: segments.length >= 2 ? segments[segments.length - 1] : null,\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n path: prevPathRef.current,\n },\n })\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n window.addEventListener(\"beforeunload\", handleUnload)\n return () => window.removeEventListener(\"beforeunload\", handleUnload)\n }, [trackingUrl, apiKey, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {})\n}\n\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","/**\n * CDN image transform helpers using Supabase Storage's built-in image transformation.\n *\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n * Works both server-side and client-side (no Node.js-only APIs).\n */\n\nexport interface ImageTransformOptions {\n width?: number\n height?: number\n quality?: number\n resize?: \"contain\" | \"cover\" | \"fill\"\n format?: \"origin\" // Supabase doesn't support format param yet, but we plan for it\n}\n\n/**\n * Transform a Supabase Storage URL to use Supabase's image transformation.\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n */\nexport function getTransformUrl(\n originalUrl: string,\n options: ImageTransformOptions = {}\n): string {\n // Only transform Supabase storage URLs\n if (!originalUrl.includes(\"/storage/v1/object/public/\")) {\n return originalUrl\n }\n\n // Convert from /object/public/ to /render/image/public/\n const transformUrl = originalUrl.replace(\n \"/storage/v1/object/public/\",\n \"/storage/v1/render/image/public/\"\n )\n\n const params = new URLSearchParams()\n if (options.width) params.set(\"width\", String(options.width))\n if (options.height) params.set(\"height\", String(options.height))\n if (options.quality) params.set(\"quality\", String(options.quality))\n if (options.resize) params.set(\"resize\", options.resize)\n\n const qs = params.toString()\n return qs ? `${transformUrl}?${qs}` : transformUrl\n}\n\n/**\n * Generate a srcSet string for responsive images.\n */\nexport function getSrcSet(\n originalUrl: string,\n widths: number[] = [320, 640, 960, 1280, 1920],\n quality = 80\n): string {\n return widths\n .map(\n (w) =>\n `${getTransformUrl(originalUrl, { width: w, quality, resize: \"contain\" })} ${w}w`\n )\n .join(\", \")\n}\n\n/**\n * Generate common image sizes for different use cases.\n */\nexport const IMAGE_PRESETS = {\n thumbnail: { width: 150, height: 150, resize: \"cover\" as const, quality: 70 },\n card: { width: 400, height: 300, resize: \"cover\" as const, quality: 80 },\n hero: { width: 1200, height: 630, resize: \"cover\" as const, quality: 85 },\n og: { width: 1200, height: 630, resize: \"cover\" as const, quality: 90 },\n avatar: { width: 80, height: 80, resize: \"cover\" as const, quality: 75 },\n full: { width: 1920, resize: \"contain\" as const, quality: 85 },\n} as const\n"],"mappings":"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","names":["options","createSupabaseClient","import_react","getSessionId","sendEvent"]}
|
package/dist/index.mjs
CHANGED
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/queries.ts","../src/shop.ts","../src/analytics.tsx","../src/page-tracker.tsx","../src/cdn.ts"],"sourcesContent":["import { createClient as createSupabaseClient } from \"@supabase/supabase-js\"\nimport type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type {\n CmsClientOptions,\n ContentItem,\n ContentQueryOptions,\n ContentType,\n} from \"./types\"\n\n/**\n * Creates a CMS query client authenticated with a tenant API key.\n *\n * Usage:\n * ```ts\n * const cms = createCmsClient(supabase, { apiKey: process.env.CMS_API_KEY! })\n * const events = await cms.getContentItems('events', { status: 'published' })\n * ```\n *\n * The API key is sent as an `x-cms-api-key` header on every request.\n * Supabase RLS policies validate it against the tenant's stored key.\n */\nexport function createCmsClient(\n supabase: SupabaseClient,\n options: CmsClientOptions\n) {\n const { apiKey } = options\n\n // Create a new Supabase client with the API key header injected globally\n const client = withApiKey(supabase, apiKey) as SupabaseClient\n\n /** Resolve the tenant ID from the API key (cached per request) */\n let tenantIdCache: string | null = null\n\n async function getTenantId(): Promise<string> {\n if (tenantIdCache) return tenantIdCache\n\n const { data, error } = await client\n .from(\"tenants\")\n .select(\"id\")\n .single()\n\n if (error || !data) {\n throw new Error(\n \"Invalid CMS API key — no tenant found. Check your apiKey.\"\n )\n }\n\n tenantIdCache = data.id\n return data.id\n }\n\n /** Resolve a content type ID from its slug */\n async function getContentTypeId(contentTypeSlug: string): Promise<string> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data.id\n }\n\n return {\n /**\n * List content items for a content type.\n * Defaults to published items ordered by most recent.\n */\n async getContentItems(\n contentTypeSlug: string,\n options: ContentQueryOptions = {}\n ): Promise<ContentItem[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const {\n status = \"published\",\n orderBy = \"published_at\",\n orderDirection = \"desc\",\n limit = 100,\n offset = 0,\n } = options\n\n let query = client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n query = query\n .order(orderBy, { ascending: orderDirection === \"asc\" })\n .range(offset, offset + limit - 1)\n\n const { data, error } = await query\n\n if (error) {\n throw new Error(`Failed to fetch ${contentTypeSlug}: ${error.message}`)\n }\n\n return (data ?? []) as ContentItem[]\n },\n\n /**\n * Get a single content item by its slug.\n * Returns null if not found.\n */\n async getContentItemBySlug(\n contentTypeSlug: string,\n itemSlug: string\n ): Promise<ContentItem | null> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"slug\", itemSlug)\n .single()\n\n if (error) {\n if (error.code === \"PGRST116\") return null // not found\n throw new Error(\n `Failed to fetch ${contentTypeSlug}/${itemSlug}: ${error.message}`\n )\n }\n\n return data as ContentItem\n },\n\n /**\n * Get a content type definition (including its field schema).\n */\n async getContentType(contentTypeSlug: string): Promise<ContentType> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data as ContentType\n },\n\n /**\n * Get all slugs for a content type (for generateStaticParams).\n */\n async getAllSlugs(\n contentTypeSlug: string\n ): Promise<{ slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"slug\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"status\", \"published\")\n\n if (error) {\n throw new Error(\n `Failed to fetch slugs for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { slug: string }[]\n },\n\n /**\n * List all content types for this tenant.\n */\n async getContentTypes(): Promise<ContentType[]> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .order(\"name\")\n\n if (error) {\n throw new Error(`Failed to fetch content types: ${error.message}`)\n }\n\n return (data ?? []) as ContentType[]\n },\n\n /**\n * Get all slug redirects for a content type.\n * Use in next.config.js redirects() or middleware for 301s.\n * Returns: [{ old_slug, new_slug }, ...]\n */\n async getRedirects(\n contentTypeSlug: string\n ): Promise<{ old_slug: string; new_slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"slug_redirects\")\n .select(\"old_slug, new_slug\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (error) {\n throw new Error(\n `Failed to fetch redirects for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { old_slug: string; new_slug: string }[]\n },\n\n /**\n * Get all custom path redirects for this tenant.\n * Use alongside getRedirects() in next.config.ts for full redirect coverage.\n */\n async getCustomRedirects(): Promise<\n { source_path: string; destination_path: string; permanent: boolean }[]\n > {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"custom_redirects\")\n .select(\"source_path, destination_path, permanent\")\n .eq(\"tenant_id\", tenantId)\n\n if (error) {\n throw new Error(`Failed to fetch custom redirects: ${error.message}`)\n }\n\n return (data ?? []) as {\n source_path: string\n destination_path: string\n permanent: boolean\n }[]\n },\n\n /**\n * Get form submissions for a specific form.\n * Useful for displaying testimonials, reviews, etc.\n */\n async getFormSubmissions(\n formSlug: string,\n options: { status?: string; limit?: number; offset?: number } = {}\n ): Promise<Record<string, unknown>[]> {\n const tenantId = await getTenantId()\n\n const { data: form } = await client\n .from(\"forms\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n if (!form) return []\n\n const { limit = 50, offset = 0, status } = options\n\n let query = client\n .from(\"form_submissions\")\n .select(\"*\")\n .eq(\"form_id\", form.id)\n .eq(\"is_spam\", false)\n .order(\"created_at\", { ascending: false })\n .range(offset, offset + limit - 1)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n const { data } = await query\n return (data ?? []) as Record<string, unknown>[]\n },\n\n /**\n * Get a form configuration by slug.\n */\n async getForm(\n formSlug: string\n ): Promise<Record<string, unknown> | null> {\n const tenantId = await getTenantId()\n\n const { data } = await client\n .from(\"forms\")\n .select(\"id, name, slug, description, is_active\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n return data as Record<string, unknown> | null\n },\n }\n}\n\n/**\n * Creates a new Supabase client that includes the `x-cms-api-key`\n * header in every request, using the same URL and key as the original.\n */\nfunction withApiKey(supabase: SupabaseClient, apiKey: string) {\n // Extract URL and key from the existing client\n const supabaseUrl = (supabase as unknown as { supabaseUrl: string }).supabaseUrl\n const supabaseKey = (supabase as unknown as { supabaseKey: string }).supabaseKey\n\n return createSupabaseClient(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n \"x-cms-api-key\": apiKey,\n },\n },\n })\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type { Product, ProductQueryOptions, CreateOrderParams, CreateOrderResult } from \"./types\"\n\nexport function createShopClient(supabase: SupabaseClient, options: { apiKey: string; appUrl?: string }) {\n const { apiKey, appUrl } = options\n\n return {\n async getProducts(queryOptions?: ProductQueryOptions): Promise<Product[]> {\n let query = supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"status\", \"published\")\n .order(queryOptions?.sort ?? \"sort_order\", { ascending: (queryOptions?.order ?? \"asc\") === \"asc\" })\n\n if (queryOptions?.category) {\n query = query.eq(\"category\", queryOptions.category)\n }\n if (queryOptions?.tags?.length) {\n query = query.overlaps(\"tags\", queryOptions.tags)\n }\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit)\n }\n if (queryOptions?.offset) {\n query = query.range(queryOptions.offset, queryOptions.offset + (queryOptions.limit ?? 50) - 1)\n }\n\n const { data } = await query\n return (data ?? []) as Product[]\n },\n\n async getProductBySlug(slug: string): Promise<Product | null> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"slug\", slug)\n .eq(\"status\", \"published\")\n .single()\n return (data as Product) ?? null\n },\n\n async getProductCategories(): Promise<string[]> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null)\n const categories = [...new Set((data ?? []).map((d: { category: string }) => d.category))]\n return categories.sort()\n },\n\n async createOrder(params: CreateOrderParams): Promise<CreateOrderResult> {\n // This must go through the API (not direct Supabase) because\n // order creation requires server-side Stripe PaymentIntent creation\n const baseUrl = appUrl ?? \"\"\n const res = await fetch(`${baseUrl}/api/orders/create`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ api_key: apiKey, ...params }),\n })\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Order creation failed\" }))\n throw new Error(err.error ?? \"Order creation failed\")\n }\n return res.json()\n },\n }\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\n\ninterface CmsAnalyticsProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Content item ID (from CMS) */\n contentItemId?: string\n /** Content type slug (e.g. \"blog_posts\") */\n contentTypeSlug: string\n /** Item slug (e.g. \"my-post\") */\n itemSlug: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Drop-in analytics component for CMS content pages.\n * Tracks page views, scroll depth, and time on page.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage:\n * ```tsx\n * <CmsAnalytics\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * contentTypeSlug=\"blog_posts\"\n * itemSlug={params.slug}\n * />\n * ```\n */\nexport function CmsAnalytics({\n trackingUrl,\n apiKey,\n contentItemId,\n contentTypeSlug,\n itemSlug,\n trackScroll = true,\n trackTime = true,\n}: CmsAnalyticsProps) {\n const sentRef = useRef(false)\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Only send page view once per mount\n if (sentRef.current) return\n sentRef.current = true\n\n // Page view event\n sendEvent(trackingUrl, {\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"page_view\",\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n })\n\n // Scroll tracking\n let scrollHandler: (() => void) | null = null\n if (trackScroll) {\n scrollHandler = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n window.addEventListener(\"scroll\", scrollHandler, { passive: true })\n }\n\n // Send engagement data on page leave\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const payload = JSON.stringify({\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"engagement\",\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n },\n })\n\n // Use sendBeacon for reliable delivery on page unload\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n if (trackScroll || trackTime) {\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n\n return () => {\n if (scrollHandler) window.removeEventListener(\"scroll\", scrollHandler)\n if (trackScroll || trackTime) window.removeEventListener(\"beforeunload\", handleUnload)\n }\n }, [trackingUrl, apiKey, contentItemId, contentTypeSlug, itemSlug, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {}) // fire and forget\n}\n\n/** Generate a random session ID (persists for the browser session) */\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\nimport { usePathname } from \"next/navigation\"\n\ninterface PageTrackerProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Site-wide page tracker. Add once in root layout to track all pages.\n * Automatically detects CMS content pages from URL structure.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage in src/app/layout.tsx:\n * ```tsx\n * import { PageTracker } from \"@distinctagency/cms-client\"\n *\n * <body>\n * {children}\n * <PageTracker\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * />\n * </body>\n * ```\n */\nexport function PageTracker({\n trackingUrl,\n apiKey,\n trackScroll = true,\n trackTime = true,\n}: PageTrackerProps) {\n const pathname = usePathname()\n const prevPathRef = useRef(\"\")\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Skip if same path (prevents double-fire on mount)\n if (pathname === prevPathRef.current) return\n prevPathRef.current = pathname\n\n // Reset engagement tracking for new page\n maxScrollRef.current = 0\n startTimeRef.current = Date.now()\n\n // Try to extract content type and item slug from URL\n // Supports patterns like /events/future-finance, /blog/my-post, etc.\n const segments = pathname.split(\"/\").filter(Boolean)\n const contentTypeSlug = segments[0] ?? null\n const itemSlug = segments.length >= 2 ? segments[segments.length - 1] : null\n\n // Fire page view\n sendEvent(trackingUrl, {\n api_key: apiKey,\n event_type: \"page_view\",\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n metadata: { path: pathname },\n })\n }, [pathname, trackingUrl, apiKey])\n\n // Scroll tracking\n useEffect(() => {\n if (!trackScroll) return\n\n const handleScroll = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n return () => window.removeEventListener(\"scroll\", handleScroll)\n }, [trackScroll])\n\n // Send engagement data on page leave\n useEffect(() => {\n if (!trackScroll && !trackTime) return\n\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const segments = prevPathRef.current.split(\"/\").filter(Boolean)\n\n const payload = JSON.stringify({\n api_key: apiKey,\n event_type: \"engagement\",\n content_type_slug: segments[0] ?? null,\n item_slug: segments.length >= 2 ? segments[segments.length - 1] : null,\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n path: prevPathRef.current,\n },\n })\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n window.addEventListener(\"beforeunload\", handleUnload)\n return () => window.removeEventListener(\"beforeunload\", handleUnload)\n }, [trackingUrl, apiKey, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {})\n}\n\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","/**\n * CDN image transform helpers using Supabase Storage's built-in image transformation.\n *\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n * Works both server-side and client-side (no Node.js-only APIs).\n */\n\nexport interface ImageTransformOptions {\n width?: number\n height?: number\n quality?: number\n resize?: \"contain\" | \"cover\" | \"fill\"\n format?: \"origin\" // Supabase doesn't support format param yet, but we plan for it\n}\n\n/**\n * Transform a Supabase Storage URL to use Supabase's image transformation.\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n */\nexport function getTransformUrl(\n originalUrl: string,\n options: ImageTransformOptions = {}\n): string {\n // Only transform Supabase storage URLs\n if (!originalUrl.includes(\"/storage/v1/object/public/\")) {\n return originalUrl\n }\n\n // Convert from /object/public/ to /render/image/public/\n const transformUrl = originalUrl.replace(\n \"/storage/v1/object/public/\",\n \"/storage/v1/render/image/public/\"\n )\n\n const params = new URLSearchParams()\n if (options.width) params.set(\"width\", String(options.width))\n if (options.height) params.set(\"height\", String(options.height))\n if (options.quality) params.set(\"quality\", String(options.quality))\n if (options.resize) params.set(\"resize\", options.resize)\n\n const qs = params.toString()\n return qs ? `${transformUrl}?${qs}` : transformUrl\n}\n\n/**\n * Generate a srcSet string for responsive images.\n */\nexport function getSrcSet(\n originalUrl: string,\n widths: number[] = [320, 640, 960, 1280, 1920],\n quality = 80\n): string {\n return widths\n .map(\n (w) =>\n `${getTransformUrl(originalUrl, { width: w, quality, resize: \"contain\" })} ${w}w`\n )\n .join(\", \")\n}\n\n/**\n * Generate common image sizes for different use cases.\n */\nexport const IMAGE_PRESETS = {\n thumbnail: { width: 150, height: 150, resize: \"cover\" as const, quality: 70 },\n card: { width: 400, height: 300, resize: \"cover\" as const, quality: 80 },\n hero: { width: 1200, height: 630, resize: \"cover\" as const, quality: 85 },\n og: { width: 1200, height: 630, resize: \"cover\" as const, quality: 90 },\n avatar: { width: 80, height: 80, resize: \"cover\" as const, quality: 75 },\n full: { width: 1920, resize: \"contain\" as const, quality: 85 },\n} as const\n"],"mappings":";AAAA,SAAS,gBAAgB,4BAA4B;AAqB9C,SAAS,gBACd,UACA,SACA;AACA,QAAM,EAAE,OAAO,IAAI;AAGnB,QAAM,SAAS,WAAW,UAAU,MAAM;AAG1C,MAAI,gBAA+B;AAEnC,iBAAe,cAA+B;AAC5C,QAAI,cAAe,QAAO;AAE1B,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,SAAS,EACd,OAAO,IAAI,EACX,OAAO;AAEV,QAAI,SAAS,CAAC,MAAM;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,oBAAgB,KAAK;AACrB,WAAO,KAAK;AAAA,EACd;AAGA,iBAAe,iBAAiB,iBAA0C;AACxE,UAAM,WAAW,MAAM,YAAY;AAEnC,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,IAAI,EACX,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,eAAe,EAC1B,OAAO;AAEV,QAAI,SAAS,CAAC,MAAM;AAClB,YAAM,IAAI,MAAM,2BAA2B,eAAe,EAAE;AAAA,IAC9D;AAEA,WAAO,KAAK;AAAA,EACd;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL,MAAM,gBACJ,iBACAA,WAA+B,CAAC,GACR;AACxB,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,iBAAiB;AAAA,QACjB,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,IAAIA;AAEJ,UAAI,QAAQ,OACT,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,mBAAmB,aAAa;AAEtC,UAAI,QAAQ;AACV,gBAAQ,MAAM,GAAG,UAAU,MAAM;AAAA,MACnC;AAEA,cAAQ,MACL,MAAM,SAAS,EAAE,WAAW,mBAAmB,MAAM,CAAC,EACtD,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM;AAE9B,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,mBAAmB,eAAe,KAAK,MAAM,OAAO,EAAE;AAAA,MACxE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,qBACJ,iBACA,UAC6B;AAC7B,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,mBAAmB,aAAa,EACnC,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,UAAI,OAAO;AACT,YAAI,MAAM,SAAS,WAAY,QAAO;AACtC,cAAM,IAAI;AAAA,UACR,mBAAmB,eAAe,IAAI,QAAQ,KAAK,MAAM,OAAO;AAAA,QAClE;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,eAAe,iBAA+C;AAClE,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,eAAe,EAC1B,OAAO;AAEV,UAAI,SAAS,CAAC,MAAM;AAClB,cAAM,IAAI,MAAM,2BAA2B,eAAe,EAAE;AAAA,MAC9D;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,YACJ,iBAC6B;AAC7B,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,MAAM,EACb,GAAG,mBAAmB,aAAa,EACnC,GAAG,UAAU,WAAW;AAE3B,UAAI,OAAO;AACT,cAAM,IAAI;AAAA,UACR,6BAA6B,eAAe,KAAK,MAAM,OAAO;AAAA,QAChE;AAAA,MACF;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,kBAA0C;AAC9C,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,aAAa,QAAQ,EACxB,MAAM,MAAM;AAEf,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,kCAAkC,MAAM,OAAO,EAAE;AAAA,MACnE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,MAAM,aACJ,iBACmD;AACnD,YAAM,gBAAgB,MAAM,iBAAiB,eAAe;AAE5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,gBAAgB,EACrB,OAAO,oBAAoB,EAC3B,GAAG,mBAAmB,aAAa;AAEtC,UAAI,OAAO;AACT,cAAM,IAAI;AAAA,UACR,iCAAiC,eAAe,KAAK,MAAM,OAAO;AAAA,QACpE;AAAA,MACF;AAEA,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,qBAEJ;AACA,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAC3B,KAAK,kBAAkB,EACvB,OAAO,0CAA0C,EACjD,GAAG,aAAa,QAAQ;AAE3B,UAAI,OAAO;AACT,cAAM,IAAI,MAAM,qCAAqC,MAAM,OAAO,EAAE;AAAA,MACtE;AAEA,aAAQ,QAAQ,CAAC;AAAA,IAKnB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,mBACJ,UACAA,WAAgE,CAAC,GAC7B;AACpC,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,MAAM,KAAK,IAAI,MAAM,OAC1B,KAAK,OAAO,EACZ,OAAO,IAAI,EACX,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,UAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,YAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,OAAO,IAAIA;AAE3C,UAAI,QAAQ,OACT,KAAK,kBAAkB,EACvB,OAAO,GAAG,EACV,GAAG,WAAW,KAAK,EAAE,EACrB,GAAG,WAAW,KAAK,EACnB,MAAM,cAAc,EAAE,WAAW,MAAM,CAAC,EACxC,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAEnC,UAAI,QAAQ;AACV,gBAAQ,MAAM,GAAG,UAAU,MAAM;AAAA,MACnC;AAEA,YAAM,EAAE,KAAK,IAAI,MAAM;AACvB,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,QACJ,UACyC;AACzC,YAAM,WAAW,MAAM,YAAY;AAEnC,YAAM,EAAE,KAAK,IAAI,MAAM,OACpB,KAAK,OAAO,EACZ,OAAO,wCAAwC,EAC/C,GAAG,aAAa,QAAQ,EACxB,GAAG,QAAQ,QAAQ,EACnB,OAAO;AAEV,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,WAAW,UAA0B,QAAgB;AAE5D,QAAM,cAAe,SAAgD;AACrE,QAAM,cAAe,SAAgD;AAErE,SAAO,qBAAqB,aAAa,aAAa;AAAA,IACpD,QAAQ;AAAA,MACN,SAAS;AAAA,QACP,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AC9TO,SAAS,iBAAiB,UAA0B,SAA8C;AACvG,QAAM,EAAE,QAAQ,OAAO,IAAI;AAE3B,SAAO;AAAA,IACL,MAAM,YAAY,cAAwD;AACxE,UAAI,QAAQ,SACT,KAAK,UAAU,EACf,OAAO,6DAA6D,EACpE,GAAG,UAAU,WAAW,EACxB,MAAM,cAAc,QAAQ,cAAc,EAAE,YAAY,cAAc,SAAS,WAAW,MAAM,CAAC;AAEpG,UAAI,cAAc,UAAU;AAC1B,gBAAQ,MAAM,GAAG,YAAY,aAAa,QAAQ;AAAA,MACpD;AACA,UAAI,cAAc,MAAM,QAAQ;AAC9B,gBAAQ,MAAM,SAAS,QAAQ,aAAa,IAAI;AAAA,MAClD;AACA,UAAI,cAAc,OAAO;AACvB,gBAAQ,MAAM,MAAM,aAAa,KAAK;AAAA,MACxC;AACA,UAAI,cAAc,QAAQ;AACxB,gBAAQ,MAAM,MAAM,aAAa,QAAQ,aAAa,UAAU,aAAa,SAAS,MAAM,CAAC;AAAA,MAC/F;AAEA,YAAM,EAAE,KAAK,IAAI,MAAM;AACvB,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA,IAEA,MAAM,iBAAiB,MAAuC;AAC5D,YAAM,EAAE,KAAK,IAAI,MAAM,SACpB,KAAK,UAAU,EACf,OAAO,6DAA6D,EACpE,GAAG,QAAQ,IAAI,EACf,GAAG,UAAU,WAAW,EACxB,OAAO;AACV,aAAQ,QAAoB;AAAA,IAC9B;AAAA,IAEA,MAAM,uBAA0C;AAC9C,YAAM,EAAE,KAAK,IAAI,MAAM,SACpB,KAAK,UAAU,EACf,OAAO,UAAU,EACjB,GAAG,UAAU,WAAW,EACxB,IAAI,YAAY,MAAM,IAAI;AAC7B,YAAM,aAAa,CAAC,GAAG,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAA4B,EAAE,QAAQ,CAAC,CAAC;AACzF,aAAO,WAAW,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,YAAY,QAAuD;AAGvE,YAAM,UAAU,UAAU;AAC1B,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,sBAAsB;AAAA,QACtD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,QAAQ,GAAG,OAAO,CAAC;AAAA,MACrD,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,wBAAwB,EAAE;AAC7E,cAAM,IAAI,MAAM,IAAI,SAAS,uBAAuB;AAAA,MACtD;AACA,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,EACF;AACF;;;ACjEA,SAAS,WAAW,cAAc;AAoC3B,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,GAAsB;AACpB,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,eAAe,OAAO,CAAC;AAC7B,QAAM,eAAe,OAAO,KAAK,IAAI,CAAC;AACtC,QAAM,eAAe,OAAO,aAAa,CAAC;AAE1C,YAAU,MAAM;AAEd,QAAI,QAAQ,QAAS;AACrB,YAAQ,UAAU;AAGlB,cAAU,aAAa;AAAA,MACrB,SAAS;AAAA,MACT,iBAAiB;AAAA,MACjB,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,UAAU,SAAS,YAAY;AAAA,MAC/B,YAAY,aAAa;AAAA,IAC3B,CAAC;AAGD,QAAI,gBAAqC;AACzC,QAAI,aAAa;AACf,sBAAgB,MAAM;AACpB,cAAM,eAAe,SAAS,gBAAgB,eAAe,OAAO;AACpE,YAAI,gBAAgB,EAAG;AACvB,cAAM,MAAM,KAAK,MAAO,OAAO,UAAU,eAAgB,GAAG;AAC5D,YAAI,MAAM,aAAa,QAAS,cAAa,UAAU;AAAA,MACzD;AACA,aAAO,iBAAiB,UAAU,eAAe,EAAE,SAAS,KAAK,CAAC;AAAA,IACpE;AAGA,UAAM,eAAe,MAAM;AACzB,YAAM,aAAa,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,WAAW,GAAI;AACxE,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,SAAS;AAAA,QACT,iBAAiB;AAAA,QACjB,mBAAmB;AAAA,QACnB,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,YAAY,aAAa;AAAA,QACzB,UAAU;AAAA,UACR,cAAc,aAAa;AAAA,UAC3B,cAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAGD,UAAI,UAAU,YAAY;AACxB,kBAAU,WAAW,aAAa,OAAO;AAAA,MAC3C;AAAA,IACF;AAEA,QAAI,eAAe,WAAW;AAC5B,aAAO,iBAAiB,gBAAgB,YAAY;AAAA,IACtD;AAEA,WAAO,MAAM;AACX,UAAI,cAAe,QAAO,oBAAoB,UAAU,aAAa;AACrE,UAAI,eAAe,UAAW,QAAO,oBAAoB,gBAAgB,YAAY;AAAA,IACvF;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,eAAe,iBAAiB,UAAU,aAAa,SAAS,CAAC;AAE1F,SAAO;AACT;AAEA,SAAS,UAAU,KAAa,MAA+B;AAC7D,QAAM,KAAK;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,WAAW;AAAA,EACb,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAGA,SAAS,eAAuB;AAC9B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,MAAM;AACZ,MAAI,MAAM,eAAe,QAAQ,GAAG;AACpC,MAAI,CAAC,KAAK;AACR,UAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE;AAClE,mBAAe,QAAQ,KAAK,GAAG;AAAA,EACjC;AACA,SAAO;AACT;;;ACpIA,SAAS,aAAAC,YAAW,UAAAC,eAAc;AAClC,SAAS,mBAAmB;AAiCrB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,GAAqB;AACnB,QAAM,WAAW,YAAY;AAC7B,QAAM,cAAcA,QAAO,EAAE;AAC7B,QAAM,eAAeA,QAAO,CAAC;AAC7B,QAAM,eAAeA,QAAO,KAAK,IAAI,CAAC;AACtC,QAAM,eAAeA,QAAOC,cAAa,CAAC;AAE1C,EAAAF,WAAU,MAAM;AAEd,QAAI,aAAa,YAAY,QAAS;AACtC,gBAAY,UAAU;AAGtB,iBAAa,UAAU;AACvB,iBAAa,UAAU,KAAK,IAAI;AAIhC,UAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnD,UAAM,kBAAkB,SAAS,CAAC,KAAK;AACvC,UAAM,WAAW,SAAS,UAAU,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAGxE,IAAAG,WAAU,aAAa;AAAA,MACrB,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,UAAU,SAAS,YAAY;AAAA,MAC/B,YAAY,aAAa;AAAA,MACzB,UAAU,EAAE,MAAM,SAAS;AAAA,IAC7B,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,aAAa,MAAM,CAAC;AAGlC,EAAAH,WAAU,MAAM;AACd,QAAI,CAAC,YAAa;AAElB,UAAM,eAAe,MAAM;AACzB,YAAM,eAAe,SAAS,gBAAgB,eAAe,OAAO;AACpE,UAAI,gBAAgB,EAAG;AACvB,YAAM,MAAM,KAAK,MAAO,OAAO,UAAU,eAAgB,GAAG;AAC5D,UAAI,MAAM,aAAa,QAAS,cAAa,UAAU;AAAA,IACzD;AAEA,WAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;AACjE,WAAO,MAAM,OAAO,oBAAoB,UAAU,YAAY;AAAA,EAChE,GAAG,CAAC,WAAW,CAAC;AAGhB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,eAAe,CAAC,UAAW;AAEhC,UAAM,eAAe,MAAM;AACzB,YAAM,aAAa,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,WAAW,GAAI;AACxE,YAAM,WAAW,YAAY,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAE9D,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,mBAAmB,SAAS,CAAC,KAAK;AAAA,QAClC,WAAW,SAAS,UAAU,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAAA,QAClE,YAAY,aAAa;AAAA,QACzB,UAAU;AAAA,UACR,cAAc,aAAa;AAAA,UAC3B,cAAc;AAAA,UACd,MAAM,YAAY;AAAA,QACpB;AAAA,MACF,CAAC;AAED,UAAI,UAAU,YAAY;AACxB,kBAAU,WAAW,aAAa,OAAO;AAAA,MAC3C;AAAA,IACF;AAEA,WAAO,iBAAiB,gBAAgB,YAAY;AACpD,WAAO,MAAM,OAAO,oBAAoB,gBAAgB,YAAY;AAAA,EACtE,GAAG,CAAC,aAAa,QAAQ,aAAa,SAAS,CAAC;AAEhD,SAAO;AACT;AAEA,SAASG,WAAU,KAAa,MAA+B;AAC7D,QAAM,KAAK;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,WAAW;AAAA,EACb,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAEA,SAASD,gBAAuB;AAC9B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,MAAM;AACZ,MAAI,MAAM,eAAe,QAAQ,GAAG;AACpC,MAAI,CAAC,KAAK;AACR,UAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE;AAClE,mBAAe,QAAQ,KAAK,GAAG;AAAA,EACjC;AACA,SAAO;AACT;;;AC1HO,SAAS,gBACd,aACA,UAAiC,CAAC,GAC1B;AAER,MAAI,CAAC,YAAY,SAAS,4BAA4B,GAAG;AACvD,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,YAAY;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC5D,MAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAC/D,MAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,OAAO,QAAQ,OAAO,CAAC;AAClE,MAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AAEvD,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,KAAK,GAAG,YAAY,IAAI,EAAE,KAAK;AACxC;AAKO,SAAS,UACd,aACA,SAAmB,CAAC,KAAK,KAAK,KAAK,MAAM,IAAI,GAC7C,UAAU,IACF;AACR,SAAO,OACJ;AAAA,IACC,CAAC,MACC,GAAG,gBAAgB,aAAa,EAAE,OAAO,GAAG,SAAS,QAAQ,UAAU,CAAC,CAAC,IAAI,CAAC;AAAA,EAClF,EACC,KAAK,IAAI;AACd;AAKO,IAAM,gBAAgB;AAAA,EAC3B,WAAW,EAAE,OAAO,KAAK,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EAC5E,MAAM,EAAE,OAAO,KAAK,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACvE,MAAM,EAAE,OAAO,MAAM,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACxE,IAAI,EAAE,OAAO,MAAM,QAAQ,KAAK,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACtE,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,QAAQ,SAAkB,SAAS,GAAG;AAAA,EACvE,MAAM,EAAE,OAAO,MAAM,QAAQ,WAAoB,SAAS,GAAG;AAC/D;","names":["options","useEffect","useRef","getSessionId","sendEvent"]}
|
|
1
|
+
{"version":3,"sources":["../src/queries.ts","../src/shop.ts","../src/analytics.tsx","../src/page-tracker.tsx","../src/cdn.ts"],"sourcesContent":["import { createClient as createSupabaseClient } from \"@supabase/supabase-js\"\nimport type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type {\n CmsClientOptions,\n ContentItem,\n ContentQueryOptions,\n ContentType,\n} from \"./types\"\n\n/**\n * Creates a CMS query client authenticated with a tenant API key.\n *\n * Usage:\n * ```ts\n * const cms = createCmsClient(supabase, { apiKey: process.env.CMS_API_KEY! })\n * const events = await cms.getContentItems('events', { status: 'published' })\n * ```\n *\n * The API key is sent as an `x-cms-api-key` header on every request.\n * Supabase RLS policies validate it against the tenant's stored key.\n */\nexport function createCmsClient(\n supabase: SupabaseClient,\n options: CmsClientOptions\n) {\n const { apiKey } = options\n\n // Create a new Supabase client with the API key header injected globally\n const client = withApiKey(supabase, apiKey) as SupabaseClient\n\n /** Resolve the tenant ID from the API key (cached per request) */\n let tenantIdCache: string | null = null\n\n async function getTenantId(): Promise<string> {\n if (tenantIdCache) return tenantIdCache\n\n const { data, error } = await client\n .from(\"tenants\")\n .select(\"id\")\n .single()\n\n if (error || !data) {\n throw new Error(\n \"Invalid CMS API key — no tenant found. Check your apiKey.\"\n )\n }\n\n tenantIdCache = data.id\n return data.id\n }\n\n /** Resolve a content type ID from its slug */\n async function getContentTypeId(contentTypeSlug: string): Promise<string> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data.id\n }\n\n return {\n /**\n * List content items for a content type.\n * Defaults to published items ordered by most recent.\n */\n async getContentItems(\n contentTypeSlug: string,\n options: ContentQueryOptions = {}\n ): Promise<ContentItem[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const {\n status = \"published\",\n orderBy = \"published_at\",\n orderDirection = \"desc\",\n limit = 100,\n offset = 0,\n } = options\n\n let query = client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n query = query\n .order(orderBy, { ascending: orderDirection === \"asc\" })\n .range(offset, offset + limit - 1)\n\n const { data, error } = await query\n\n if (error) {\n throw new Error(`Failed to fetch ${contentTypeSlug}: ${error.message}`)\n }\n\n return (data ?? []) as ContentItem[]\n },\n\n /**\n * Get a single content item by its slug.\n * Returns null if not found.\n */\n async getContentItemBySlug(\n contentTypeSlug: string,\n itemSlug: string\n ): Promise<ContentItem | null> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"*\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"slug\", itemSlug)\n .single()\n\n if (error) {\n if (error.code === \"PGRST116\") return null // not found\n throw new Error(\n `Failed to fetch ${contentTypeSlug}/${itemSlug}: ${error.message}`\n )\n }\n\n return data as ContentItem\n },\n\n /**\n * Get a content type definition (including its field schema).\n */\n async getContentType(contentTypeSlug: string): Promise<ContentType> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", contentTypeSlug)\n .single()\n\n if (error || !data) {\n throw new Error(`Content type not found: ${contentTypeSlug}`)\n }\n\n return data as ContentType\n },\n\n /**\n * Get all slugs for a content type (for generateStaticParams).\n */\n async getAllSlugs(\n contentTypeSlug: string\n ): Promise<{ slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"content_items\")\n .select(\"slug\")\n .eq(\"content_type_id\", contentTypeId)\n .eq(\"status\", \"published\")\n\n if (error) {\n throw new Error(\n `Failed to fetch slugs for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { slug: string }[]\n },\n\n /**\n * List all content types for this tenant.\n */\n async getContentTypes(): Promise<ContentType[]> {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"content_types\")\n .select(\"*\")\n .eq(\"tenant_id\", tenantId)\n .order(\"name\")\n\n if (error) {\n throw new Error(`Failed to fetch content types: ${error.message}`)\n }\n\n return (data ?? []) as ContentType[]\n },\n\n /**\n * Get all slug redirects for a content type.\n * Use in next.config.js redirects() or middleware for 301s.\n * Returns: [{ old_slug, new_slug }, ...]\n */\n async getRedirects(\n contentTypeSlug: string\n ): Promise<{ old_slug: string; new_slug: string }[]> {\n const contentTypeId = await getContentTypeId(contentTypeSlug)\n\n const { data, error } = await client\n .from(\"slug_redirects\")\n .select(\"old_slug, new_slug\")\n .eq(\"content_type_id\", contentTypeId)\n\n if (error) {\n throw new Error(\n `Failed to fetch redirects for ${contentTypeSlug}: ${error.message}`\n )\n }\n\n return (data ?? []) as { old_slug: string; new_slug: string }[]\n },\n\n /**\n * Get all custom path redirects for this tenant.\n * Use alongside getRedirects() in next.config.ts for full redirect coverage.\n */\n async getCustomRedirects(): Promise<\n { source_path: string; destination_path: string; permanent: boolean }[]\n > {\n const tenantId = await getTenantId()\n\n const { data, error } = await client\n .from(\"custom_redirects\")\n .select(\"source_path, destination_path, permanent\")\n .eq(\"tenant_id\", tenantId)\n\n if (error) {\n throw new Error(`Failed to fetch custom redirects: ${error.message}`)\n }\n\n return (data ?? []) as {\n source_path: string\n destination_path: string\n permanent: boolean\n }[]\n },\n\n /**\n * Get form submissions for a specific form.\n * Useful for displaying testimonials, reviews, etc.\n */\n async getFormSubmissions(\n formSlug: string,\n options: { status?: string; limit?: number; offset?: number } = {}\n ): Promise<Record<string, unknown>[]> {\n const tenantId = await getTenantId()\n\n const { data: form } = await client\n .from(\"forms\")\n .select(\"id\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n if (!form) return []\n\n const { limit = 50, offset = 0, status } = options\n\n let query = client\n .from(\"form_submissions\")\n .select(\"*\")\n .eq(\"form_id\", form.id)\n .eq(\"is_spam\", false)\n .order(\"created_at\", { ascending: false })\n .range(offset, offset + limit - 1)\n\n if (status) {\n query = query.eq(\"status\", status)\n }\n\n const { data } = await query\n return (data ?? []) as Record<string, unknown>[]\n },\n\n /**\n * Get a form configuration by slug.\n */\n async getForm(\n formSlug: string\n ): Promise<Record<string, unknown> | null> {\n const tenantId = await getTenantId()\n\n const { data } = await client\n .from(\"forms\")\n .select(\"id, name, slug, description, is_active\")\n .eq(\"tenant_id\", tenantId)\n .eq(\"slug\", formSlug)\n .single()\n\n return data as Record<string, unknown> | null\n },\n }\n}\n\n/**\n * Creates a new Supabase client that includes the `x-cms-api-key`\n * header in every request, using the same URL and key as the original.\n */\nfunction withApiKey(supabase: SupabaseClient, apiKey: string) {\n // Extract URL and key from the existing client\n const supabaseUrl = (supabase as unknown as { supabaseUrl: string }).supabaseUrl\n const supabaseKey = (supabase as unknown as { supabaseKey: string }).supabaseKey\n\n return createSupabaseClient(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n \"x-cms-api-key\": apiKey,\n },\n },\n })\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\"\nimport type { Product, ProductQueryOptions, CreateOrderParams, CreateOrderResult } from \"./types\"\n\nexport function createShopClient(supabase: SupabaseClient, options: { apiKey: string; appUrl?: string }) {\n const { apiKey, appUrl } = options\n\n return {\n async getProducts(queryOptions?: ProductQueryOptions): Promise<Product[]> {\n let query = supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"status\", \"published\")\n .order(queryOptions?.sort ?? \"sort_order\", { ascending: (queryOptions?.order ?? \"asc\") === \"asc\" })\n\n if (queryOptions?.category) {\n query = query.eq(\"category\", queryOptions.category)\n }\n if (queryOptions?.tags?.length) {\n query = query.overlaps(\"tags\", queryOptions.tags)\n }\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit)\n }\n if (queryOptions?.offset) {\n query = query.range(queryOptions.offset, queryOptions.offset + (queryOptions.limit ?? 50) - 1)\n }\n\n const { data } = await query\n return (data ?? []) as Product[]\n },\n\n async getProductBySlug(slug: string): Promise<Product | null> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"*, variants:product_variants(*), options:product_options(*)\")\n .eq(\"slug\", slug)\n .eq(\"status\", \"published\")\n .single()\n return (data as Product) ?? null\n },\n\n async getProductCategories(): Promise<string[]> {\n const { data } = await supabase\n .from(\"products\")\n .select(\"category\")\n .eq(\"status\", \"published\")\n .not(\"category\", \"is\", null)\n const categories = [...new Set((data ?? []).map((d: { category: string }) => d.category))]\n return categories.sort()\n },\n\n async createOrder(params: CreateOrderParams): Promise<CreateOrderResult> {\n // This must go through the API (not direct Supabase) because\n // order creation requires server-side Stripe PaymentIntent creation\n const baseUrl = appUrl ?? \"\"\n const res = await fetch(`${baseUrl}/api/orders/create`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ api_key: apiKey, ...params }),\n })\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: \"Order creation failed\" }))\n throw new Error(err.error ?? \"Order creation failed\")\n }\n return res.json()\n },\n }\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\n\ninterface CmsAnalyticsProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Content item ID (from CMS) */\n contentItemId?: string\n /** Content type slug (e.g. \"blog_posts\") */\n contentTypeSlug: string\n /** Item slug (e.g. \"my-post\") */\n itemSlug: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Drop-in analytics component for CMS content pages.\n * Tracks page views, scroll depth, and time on page.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage:\n * ```tsx\n * <CmsAnalytics\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * contentTypeSlug=\"blog_posts\"\n * itemSlug={params.slug}\n * />\n * ```\n */\nexport function CmsAnalytics({\n trackingUrl,\n apiKey,\n contentItemId,\n contentTypeSlug,\n itemSlug,\n trackScroll = true,\n trackTime = true,\n}: CmsAnalyticsProps) {\n const sentRef = useRef(false)\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Only send page view once per mount\n if (sentRef.current) return\n sentRef.current = true\n\n // Page view event\n sendEvent(trackingUrl, {\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"page_view\",\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n })\n\n // Scroll tracking\n let scrollHandler: (() => void) | null = null\n if (trackScroll) {\n scrollHandler = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n window.addEventListener(\"scroll\", scrollHandler, { passive: true })\n }\n\n // Send engagement data on page leave\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const payload = JSON.stringify({\n api_key: apiKey,\n content_item_id: contentItemId,\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n event_type: \"engagement\",\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n },\n })\n\n // Use sendBeacon for reliable delivery on page unload\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n if (trackScroll || trackTime) {\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n\n return () => {\n if (scrollHandler) window.removeEventListener(\"scroll\", scrollHandler)\n if (trackScroll || trackTime) window.removeEventListener(\"beforeunload\", handleUnload)\n }\n }, [trackingUrl, apiKey, contentItemId, contentTypeSlug, itemSlug, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {}) // fire and forget\n}\n\n/** Generate a random session ID (persists for the browser session) */\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","\"use client\"\n\nimport { useEffect, useRef } from \"react\"\nimport { usePathname } from \"next/navigation\"\n\ninterface PageTrackerProps {\n /** The CMS tracking endpoint URL (required — your CMS app URL + /api/track) */\n trackingUrl: string\n /** Tenant API key (public, read-only — safe for client-side use) */\n apiKey: string\n /** Enable scroll depth tracking (default: true) */\n trackScroll?: boolean\n /** Enable time-on-page tracking (default: true) */\n trackTime?: boolean\n}\n\n/**\n * Site-wide page tracker. Add once in root layout to track all pages.\n * Automatically detects CMS content pages from URL structure.\n *\n * The apiKey is a public, read-only tenant identifier — it only grants\n * access to published content and is safe for client-side use.\n *\n * Usage in src/app/layout.tsx:\n * ```tsx\n * import { PageTracker } from \"@distinctagency/cms-client\"\n *\n * <body>\n * {children}\n * <PageTracker\n * trackingUrl={process.env.NEXT_PUBLIC_CMS_URL + \"/api/track\"}\n * apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}\n * />\n * </body>\n * ```\n */\nexport function PageTracker({\n trackingUrl,\n apiKey,\n trackScroll = true,\n trackTime = true,\n}: PageTrackerProps) {\n const pathname = usePathname()\n const prevPathRef = useRef(\"\")\n const maxScrollRef = useRef(0)\n const startTimeRef = useRef(Date.now())\n const sessionIdRef = useRef(getSessionId())\n\n useEffect(() => {\n // Skip if same path (prevents double-fire on mount)\n if (pathname === prevPathRef.current) return\n prevPathRef.current = pathname\n\n // Reset engagement tracking for new page\n maxScrollRef.current = 0\n startTimeRef.current = Date.now()\n\n // Try to extract content type and item slug from URL\n // Supports patterns like /events/future-finance, /blog/my-post, etc.\n const segments = pathname.split(\"/\").filter(Boolean)\n const contentTypeSlug = segments[0] ?? null\n const itemSlug = segments.length >= 2 ? segments[segments.length - 1] : null\n\n // Fire page view\n sendEvent(trackingUrl, {\n api_key: apiKey,\n event_type: \"page_view\",\n content_type_slug: contentTypeSlug,\n item_slug: itemSlug,\n referrer: document.referrer || null,\n session_id: sessionIdRef.current,\n metadata: { path: pathname },\n })\n }, [pathname, trackingUrl, apiKey])\n\n // Scroll tracking\n useEffect(() => {\n if (!trackScroll) return\n\n const handleScroll = () => {\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight\n if (scrollHeight <= 0) return\n const pct = Math.round((window.scrollY / scrollHeight) * 100)\n if (pct > maxScrollRef.current) maxScrollRef.current = pct\n }\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n return () => window.removeEventListener(\"scroll\", handleScroll)\n }, [trackScroll])\n\n // Send engagement data on page leave\n useEffect(() => {\n if (!trackScroll && !trackTime) return\n\n const handleUnload = () => {\n const timeOnPage = Math.round((Date.now() - startTimeRef.current) / 1000)\n const segments = prevPathRef.current.split(\"/\").filter(Boolean)\n\n const payload = JSON.stringify({\n api_key: apiKey,\n event_type: \"engagement\",\n content_type_slug: segments[0] ?? null,\n item_slug: segments.length >= 2 ? segments[segments.length - 1] : null,\n session_id: sessionIdRef.current,\n metadata: {\n scroll_depth: maxScrollRef.current,\n time_on_page: timeOnPage,\n path: prevPathRef.current,\n },\n })\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(trackingUrl, payload)\n }\n }\n\n window.addEventListener(\"beforeunload\", handleUnload)\n return () => window.removeEventListener(\"beforeunload\", handleUnload)\n }, [trackingUrl, apiKey, trackScroll, trackTime])\n\n return null\n}\n\nfunction sendEvent(url: string, data: Record<string, unknown>) {\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(data),\n keepalive: true,\n }).catch(() => {})\n}\n\nfunction getSessionId(): string {\n if (typeof window === \"undefined\") return \"\"\n const key = \"__cms_sid\"\n let sid = sessionStorage.getItem(key)\n if (!sid) {\n sid = Math.random().toString(36).slice(2) + Date.now().toString(36)\n sessionStorage.setItem(key, sid)\n }\n return sid\n}\n","/**\n * CDN image transform helpers using Supabase Storage's built-in image transformation.\n *\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n * Works both server-side and client-side (no Node.js-only APIs).\n */\n\nexport interface ImageTransformOptions {\n width?: number\n height?: number\n quality?: number\n resize?: \"contain\" | \"cover\" | \"fill\"\n format?: \"origin\" // Supabase doesn't support format param yet, but we plan for it\n}\n\n/**\n * Transform a Supabase Storage URL to use Supabase's image transformation.\n * Converts /object/public/ URLs to /render/image/public/ with transform params.\n */\nexport function getTransformUrl(\n originalUrl: string,\n options: ImageTransformOptions = {}\n): string {\n // Only transform Supabase storage URLs\n if (!originalUrl.includes(\"/storage/v1/object/public/\")) {\n return originalUrl\n }\n\n // Convert from /object/public/ to /render/image/public/\n const transformUrl = originalUrl.replace(\n \"/storage/v1/object/public/\",\n \"/storage/v1/render/image/public/\"\n )\n\n const params = new URLSearchParams()\n if (options.width) params.set(\"width\", String(options.width))\n if (options.height) params.set(\"height\", String(options.height))\n if (options.quality) params.set(\"quality\", String(options.quality))\n if (options.resize) params.set(\"resize\", options.resize)\n\n const qs = params.toString()\n return qs ? `${transformUrl}?${qs}` : transformUrl\n}\n\n/**\n * Generate a srcSet string for responsive images.\n */\nexport function getSrcSet(\n originalUrl: string,\n widths: number[] = [320, 640, 960, 1280, 1920],\n quality = 80\n): string {\n return widths\n .map(\n (w) =>\n `${getTransformUrl(originalUrl, { width: w, quality, resize: \"contain\" })} ${w}w`\n )\n .join(\", \")\n}\n\n/**\n * Generate common image sizes for different use cases.\n */\nexport const IMAGE_PRESETS = {\n thumbnail: { width: 150, height: 150, resize: \"cover\" as const, quality: 70 },\n card: { width: 400, height: 300, resize: \"cover\" as const, quality: 80 },\n hero: { width: 1200, height: 630, resize: \"cover\" as const, quality: 85 },\n og: { width: 1200, height: 630, resize: \"cover\" as const, quality: 90 },\n avatar: { width: 80, height: 80, resize: \"cover\" as const, quality: 75 },\n full: { width: 1920, resize: \"contain\" as const, quality: 85 },\n} as const\n"],"mappings":"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","names":["options","useEffect","useRef","getSessionId","sendEvent"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@distinctagency/cms-client",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Client library for Distinct CMS — query content, products, and manage orders",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"@supabase/supabase-js": ">=2.0.0",
|
|
24
24
|
"react": ">=18.0.0",
|
|
25
|
-
"react-dom": ">=18.0.0"
|
|
25
|
+
"react-dom": ">=18.0.0",
|
|
26
|
+
"next": ">=14.0.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"tsup": "^8.5.1",
|