diff --git a/app/api/sponsorship/route.ts b/app/api/sponsorship/route.ts
new file mode 100644
index 00000000..2ace78b8
--- /dev/null
+++ b/app/api/sponsorship/route.ts
@@ -0,0 +1,96 @@
+
+import { NextResponse } from "next/server";
+import { z } from "zod";
+import { apiVersion, dataset, projectId } from "@/sanity/lib/api";
+import { createClient } from "next-sanity";
+
+const sanityWriteClient = createClient({
+ projectId,
+ dataset,
+ apiVersion,
+ token: process.env.SANITY_API_WRITE_TOKEN,
+ perspective: "published",
+ useCdn: false,
+});
+
+const formSchema = z.object({
+ fullName: z.string(),
+ email: z.string().email(),
+ companyName: z.string().optional(),
+ sponsorshipTier: z.array(z.string()),
+ message: z.string().optional(),
+ honeypot: z.string().optional(),
+ "cf-turnstile-response": z.string(),
+});
+
+export async function POST(request: Request) {
+ const body = await request.json();
+
+ try {
+ const {
+ fullName,
+ email,
+ companyName,
+ sponsorshipTier,
+ message,
+ honeypot,
+ "cf-turnstile-response": turnstileToken,
+ } = formSchema.parse(body);
+
+ // Honeypot check
+ if (honeypot) {
+ return NextResponse.json({ message: "Spam detected" }, { status: 400 });
+ }
+
+ const ip = request.headers.get("CF-Connecting-IP");
+ const turnstileResponse = await fetch(
+ "https://challenges.cloudflare.com/turnstile/v0/siteverify",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ secret: process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY,
+ response: turnstileToken,
+ remoteip: ip,
+ }),
+ }
+ );
+ const turnstileData = await turnstileResponse.json();
+ if (!turnstileData.success) {
+ return NextResponse.json(
+ { message: "Invalid CAPTCHA", details: turnstileData["error-codes"] },
+ { status: 400 }
+ );
+ }
+
+ const sponsorshipRequest = {
+ _type: "sponsorshipRequest",
+ fullName,
+ email,
+ companyName,
+ sponsorshipTier,
+ message,
+ };
+
+ try {
+ await sanityWriteClient.create(sponsorshipRequest);
+ } catch (error) {
+ return NextResponse.json(
+ { message: "Failed to save sponsorship request", details: error },
+ { status: 500 }
+ );
+ }
+
+ return NextResponse.json({ message: "Sponsorship request submitted successfully" });
+ } catch (error) {
+ if (error instanceof z.ZodError) {
+ return NextResponse.json({ message: error.message }, { status: 400 });
+ }
+ return NextResponse.json(
+ { message: "Internal Server Error" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/api/verify-turnstile.ts b/app/api/verify-turnstile.ts
new file mode 100644
index 00000000..d788f6f0
--- /dev/null
+++ b/app/api/verify-turnstile.ts
@@ -0,0 +1,28 @@
+
+import { NextResponse } from "next/server";
+
+export async function POST(request: Request) {
+ const {'cf-turnstile-response': turnstileToken} = await request.json();
+
+ const secretKey = process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY;
+
+ if (!secretKey) {
+ return NextResponse.json({ success: false, message: 'TURNSTILE_SECRET_KEY is not set' }, { status: 500 });
+ }
+
+ const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: `secret=${secretKey}&response=${turnstileToken}`,
+ });
+
+ const data = await response.json();
+
+ if (data.success) {
+ return NextResponse.json({ success: true, message: 'Turnstile verification successful' });
+ } else {
+ return NextResponse.json({ success: false, message: 'Turnstile verification failed' }, { status: 400 });
+ }
+}
diff --git a/app/globals.css b/app/globals.css
index c2a8e844..9eb302fe 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -162,3 +162,65 @@
@apply bg-background text-foreground;
}
}
+
+@keyframes float {
+ 0% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(-20px);
+ }
+ 100% {
+ transform: translateY(0px);
+ }
+}
+
+@keyframes paw-one {
+ 0% {
+ transform: translate(0, 0);
+ }
+ 20% {
+ transform: translate(-40px, 40px) rotate(-15deg);
+ }
+ 40% {
+ transform: translate(-30px, 30px) rotate(-5deg);
+ }
+ 60% {
+ transform: translate(-40px, 40px) rotate(-15deg);
+ }
+ 80% {
+ transform: translate(-30px, 30px) rotate(-5deg);
+ }
+ 100% {
+ transform: translate(0, 0);
+ }
+}
+
+@keyframes paw-two {
+ 0% {
+ transform: translate(0, 0);
+ }
+ 20% {
+ transform: translate(40px, -40px) rotate(15deg);
+ }
+ 40% {
+ transform: translate(30px, -30px) rotate(5deg);
+ }
+ 60% {
+ transform: translate(40px, -40px) rotate(15deg);
+ }
+ 80% {
+ transform: translate(30px, -30px) rotate(5deg);
+ }
+ 100% {
+ transform: translate(0, 0);
+ }
+}
+
+.animate-paw-one {
+ animation: paw-one 8s ease-in-out infinite;
+}
+
+.animate-paw-two {
+ animation: paw-two 8s ease-in-out infinite 2s;
+}
diff --git a/components/animated-hero.tsx b/components/animated-hero.tsx
new file mode 100644
index 00000000..468e3746
--- /dev/null
+++ b/components/animated-hero.tsx
@@ -0,0 +1,69 @@
+'use client';
+
+import { useState } from 'react';
+import { FaReact, FaVuejs, FaAngular, FaNodeJs, FaPython } from 'react-icons/fa';
+import { SiSvelte } from 'react-icons/si';
+import { SiNextdotjs, SiTypescript, SiJavascript, SiOpenai, SiTensorflow } from 'react-icons/si';
+import { RiGeminiFill } from "react-icons/ri";
+import AJHeadphones from '@/components/icons/aj-headphones';
+import AJPrimary from '@/components/icons/aj-primary-alt';
+
+const icons = [
+ { icon:
, name: 'React' },
+ { icon:
, name: 'Vue.js' },
+ { icon:
, name: 'Angular' },
+ { icon:
, name: 'Svelte' },
+ { icon:
, name: 'Node.js' },
+ { icon:
, name: 'Next.js' },
+ { icon:
, name: 'TypeScript' },
+ { icon:
, name: 'JavaScript' },
+ { icon:
, name: 'Python' },
+ { icon:
, name: 'OpenAI' },
+ { icon:
, name: 'TensorFlow' },
+ { icon:
, name: 'Gemini' },
+];
+
+export default function AnimatedHero() {
+ const [isHovered, setIsHovered] = useState(false);
+
+ return (
+
+
+ {icons.map((item, index) => (
+
+ {item.icon}
+
+ ))}
+
+
+
setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ >
+
+ CodingCat.dev Podcast
+
+
+ Purrfect Podcast for Web Developers
+
+
+
+
+
+ );
+}
diff --git a/components/become-sponsor-popup.tsx b/components/become-sponsor-popup.tsx
new file mode 100644
index 00000000..995e9030
--- /dev/null
+++ b/components/become-sponsor-popup.tsx
@@ -0,0 +1,48 @@
+
+'use client';
+
+import { useEffect, useState } from 'react';
+import { Button } from '@/components/ui/button';
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from '@/components/ui/alert-dialog';
+import Link from 'next/link';
+
+export function BecomeSponsorPopup() {
+ const [isOpen, setIsOpen] = useState(false);
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setIsOpen(true);
+ }, 5000); // 5 seconds
+
+ return () => clearTimeout(timer);
+ }, []);
+
+ return (
+
+
+
+ Become a Sponsor!
+
+ Enjoying the content? Help us keep it going by becoming a sponsor.
+ You'll get your brand in front of a large audience of developers.
+
+
+
+ Maybe later
+
+ Learn More
+
+
+
+
+ );
+}
diff --git a/components/carbon-ad-banner.tsx b/components/carbon-ad-banner.tsx
deleted file mode 100644
index 4a1ccf0c..00000000
--- a/components/carbon-ad-banner.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-"use client";
-import { useEffect, useRef } from "react";
-
-export default function CarbonAdBanner() {
- const reference = useRef
(null);
-
- useEffect(() => {
- if (!reference.current) return;
- reference.current.innerHTML = "";
- const s = document.createElement("script");
- s.id = "_carbonads_js";
- s.src = `//cdn.carbonads.com/carbon.js?serve=CW7DCKJJ&placement=codingcatdev&format=cover`;
- reference.current.appendChild(s);
- }, []);
- return
;
-}
diff --git a/components/cloudflare-turnstile.tsx b/components/cloudflare-turnstile.tsx
new file mode 100644
index 00000000..ab2fd658
--- /dev/null
+++ b/components/cloudflare-turnstile.tsx
@@ -0,0 +1,26 @@
+
+'use client';
+
+import { Turnstile } from '@marsidev/react-turnstile';
+
+export function CloudflareTurnstileWidget({
+ value,
+ onChange,
+ ...props
+}: {
+ value?: string;
+ onChange?: (token: string) => void;
+ [key: string]: any;
+}) {
+ return (
+ {
+ if (onChange) {
+ onChange(token);
+ }
+ }}
+ {...props}
+ />
+ );
+}
diff --git a/components/icons/aj-alt.tsx b/components/icons/aj-alt.tsx
new file mode 100644
index 00000000..3200d367
--- /dev/null
+++ b/components/icons/aj-alt.tsx
@@ -0,0 +1,30 @@
+export default function AjAlt({ cls = "block w-12 h-12" }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/icons/aj-dark.tsx b/components/icons/aj-dark.tsx
new file mode 100644
index 00000000..0e9582ac
--- /dev/null
+++ b/components/icons/aj-dark.tsx
@@ -0,0 +1,21 @@
+export default function AJDark({ cls = "block w-12 h-12" }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/icons/aj-headphones-alt.tsx b/components/icons/aj-headphones-alt.tsx
new file mode 100644
index 00000000..48c96879
--- /dev/null
+++ b/components/icons/aj-headphones-alt.tsx
@@ -0,0 +1,65 @@
+export default function AJHeadphonesAlt({ cls = "block w-12 h-12" }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/components/icons/aj-headphones.tsx b/components/icons/aj-headphones.tsx
index fe8fb13b..df138ecd 100644
--- a/components/icons/aj-headphones.tsx
+++ b/components/icons/aj-headphones.tsx
@@ -1,149 +1,66 @@
export default function AJHeadphones({ cls = "block w-12 h-12" }) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/components/icons/aj-light.tsx b/components/icons/aj-light.tsx
new file mode 100644
index 00000000..f1dfe1ef
--- /dev/null
+++ b/components/icons/aj-light.tsx
@@ -0,0 +1,21 @@
+export default function AJLight({ cls = "block w-12 h-12" }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/icons/aj-primary-alt.tsx b/components/icons/aj-primary-alt.tsx
new file mode 100644
index 00000000..318dd146
--- /dev/null
+++ b/components/icons/aj-primary-alt.tsx
@@ -0,0 +1,40 @@
+export default function AJHeadphonesAlt({ cls = "block w-12 h-12" }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/icons/aj-primary.tsx b/components/icons/aj-primary.tsx
index 54cd36a8..39da801f 100644
--- a/components/icons/aj-primary.tsx
+++ b/components/icons/aj-primary.tsx
@@ -1,125 +1,41 @@
export default function AJPrimary({ cls = "block w-12 h-12" }) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/podmatch-badge.tsx b/components/podmatch-badge.tsx
new file mode 100644
index 00000000..05f637bb
--- /dev/null
+++ b/components/podmatch-badge.tsx
@@ -0,0 +1,75 @@
+'use client';
+
+export default function PodmatchBadge() {
+ return (
+
+ );
+}
diff --git a/package.json b/package.json
index 94ff5084..34e0c6f3 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"dependencies": {
"@codingcatdev/sanity-plugin-podcast-rss": "^1.0.0",
"@hookform/resolvers": "^5.2.1",
+ "@marsidev/react-turnstile": "^1.3.1",
"@portabletext/block-tools": "^3.5.5",
"@portabletext/react": "^4.0.3",
"@portabletext/to-html": "^3.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 31386851..ea179fcc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,6 +14,9 @@ importers:
'@hookform/resolvers':
specifier: ^5.2.1
version: 5.2.2(react-hook-form@7.64.0(react@19.2.0))
+ '@marsidev/react-turnstile':
+ specifier: ^1.3.1
+ version: 1.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@portabletext/block-tools':
specifier: ^3.5.5
version: 3.5.10(@sanity/schema@4.10.2(@types/react@19.2.2))(@sanity/types@4.10.2(@types/react@19.2.2))
@@ -1790,6 +1793,12 @@ packages:
'@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
+ '@marsidev/react-turnstile@1.3.1':
+ resolution: {integrity: sha512-h2THG/75k4Y049hgjSGPIcajxXnh+IZAiXVbryQyVmagkboN7pJtBgR16g8akjwUBSfRrg6jw6KvPDjscQflog==}
+ peerDependencies:
+ react: ^17.0.2 || ^18.0.0 || ^19.0
+ react-dom: ^17.0.2 || ^18.0.0 || ^19.0
+
'@mux/mux-data-google-ima@0.2.8':
resolution: {integrity: sha512-0ZEkHdcZ6bS8QtcjFcoJeZxJTpX7qRIledf4q1trMWPznugvtajCjCM2kieK/pzkZj1JM6liDRFs1PJSfVUs2A==}
@@ -9312,6 +9321,11 @@ snapshots:
'@marijn/find-cluster-break@1.0.2': {}
+ '@marsidev/react-turnstile@1.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
'@mux/mux-data-google-ima@0.2.8':
dependencies:
mux-embed: 5.9.0
diff --git a/production.tar.gz b/production.tar.gz
new file mode 100644
index 00000000..e33b55c8
Binary files /dev/null and b/production.tar.gz differ
diff --git a/sanity.config.ts b/sanity.config.ts
index 1123cc61..aae55fa3 100644
--- a/sanity.config.ts
+++ b/sanity.config.ts
@@ -43,6 +43,7 @@ import podcastType from "@/sanity/schemas/documents/podcastType";
import post from "@/sanity/schemas/documents/post";
import settings from "@/sanity/schemas/singletons/settings";
import sponsor from "@/sanity/schemas/documents/sponsor";
+import sponsorshipRequest from "@/sanity/schemas/documents/sponsorshipRequest";
import youtubeUpdateTask from "@/sanity/schemas/documents/youtubeUpdateTask";
import { resolveHref } from "@/sanity/lib/utils";
@@ -140,6 +141,7 @@ export default defineConfig({
sponsor,
youtubeUpdateTask,
previewSession,
+ sponsorshipRequest,
],
},
document: {
diff --git a/sanity/extract.json b/sanity/extract.json
index 06007cf0..6ac474c7 100644
--- a/sanity/extract.json
+++ b/sanity/extract.json
@@ -1,4 +1,79 @@
[
+ {
+ "name": "sponsorshipRequest",
+ "type": "document",
+ "attributes": {
+ "_id": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ }
+ },
+ "_type": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string",
+ "value": "sponsorshipRequest"
+ }
+ },
+ "_createdAt": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ }
+ },
+ "_updatedAt": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ }
+ },
+ "_rev": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ }
+ },
+ "fullName": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ },
+ "optional": true
+ },
+ "email": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ },
+ "optional": true
+ },
+ "companyName": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ },
+ "optional": true
+ },
+ "sponsorshipTier": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "array",
+ "of": {
+ "type": "string"
+ }
+ },
+ "optional": true
+ },
+ "message": {
+ "type": "objectAttribute",
+ "value": {
+ "type": "string"
+ },
+ "optional": true
+ }
+ }
+ },
{
"name": "previewSession",
"type": "document",
diff --git a/sanity/schemas/documents/sponsorshipRequest.ts b/sanity/schemas/documents/sponsorshipRequest.ts
new file mode 100644
index 00000000..99eb5361
--- /dev/null
+++ b/sanity/schemas/documents/sponsorshipRequest.ts
@@ -0,0 +1,54 @@
+
+import {defineField, defineType} from 'sanity'
+
+export default defineType({
+ name: 'sponsorshipRequest',
+ title: 'Sponsorship Request',
+ type: 'document',
+ fields: [
+ defineField({
+ name: 'fullName',
+ title: 'Full Name',
+ type: 'string',
+ validation: (Rule) => Rule.required(),
+ }),
+ defineField({
+ name: 'email',
+ title: 'Email Address',
+ type: 'string',
+ validation: (Rule) => Rule.required().email(),
+ }),
+ defineField({
+ name: 'companyName',
+ title: 'Company Name',
+ type: 'string',
+ }),
+ defineField({
+ name: 'sponsorshipTier',
+ title: 'Sponsorship Tier',
+ type: 'array',
+ of: [{type: 'string'}],
+ options: {
+ list: [
+ {title: 'Dedicated Video', value: 'dedicated-video'},
+ {title: 'Integrated Mid-Roll Ad', value: 'mid-roll-ad'},
+ {title: 'Quick Shout-Out', value: 'shout-out'},
+ {title: 'Blog Post / Newsletter', value: 'blog-newsletter'},
+ {title: 'Video Series', value: 'video-series'},
+ ],
+ },
+ validation: (Rule) => Rule.required(),
+ }),
+ defineField({
+ name: 'message',
+ title: 'Message',
+ type: 'text',
+ }),
+ ],
+ preview: {
+ select: {
+ title: 'companyName',
+ subtitle: 'fullName',
+ },
+ },
+})
diff --git a/sanity/types.ts b/sanity/types.ts
index d72f63ce..1094e227 100644
--- a/sanity/types.ts
+++ b/sanity/types.ts
@@ -13,6 +13,19 @@
*/
// Source: schema.json
+export type SponsorshipRequest = {
+ _id: string;
+ _type: "sponsorshipRequest";
+ _createdAt: string;
+ _updatedAt: string;
+ _rev: string;
+ fullName?: string;
+ email?: string;
+ companyName?: string;
+ sponsorshipTier?: Array;
+ message?: string;
+};
+
export type PreviewSession = {
_id: string;
_type: "previewSession";
@@ -1753,7 +1766,7 @@ export type SanityAssetSourceData = {
url?: string;
};
-export type AllSanitySchemaTypes = PreviewSession | YoutubeUpdateTask | Sponsor | Lesson | Author | Post | Podcast | Guest | PodcastType | Course | Page | Settings | PodcastRssEpisode | Code | CloudinaryAssetContextCustom | CloudinaryAssetDerived | CloudinaryAsset | CloudinaryAssetContext | SanityAssistInstructionTask | SanityAssistTaskStatus | SanityAssistSchemaTypeAnnotations | SanityAssistOutputType | SanityAssistOutputField | SanityAssistInstructionContext | AssistInstructionContext | SanityAssistInstructionUserInput | SanityAssistInstructionPrompt | SanityAssistInstructionFieldRef | SanityAssistInstruction | SanityAssistSchemaTypeField | SanityImagePaletteSwatch | SanityImagePalette | SanityImageDimensions | SanityImageHotspot | SanityImageCrop | SanityFileAsset | SanityImageAsset | SanityImageMetadata | Geopoint | Slug | SanityAssetSourceData;
+export type AllSanitySchemaTypes = SponsorshipRequest | PreviewSession | YoutubeUpdateTask | Sponsor | Lesson | Author | Post | Podcast | Guest | PodcastType | Course | Page | Settings | PodcastRssEpisode | Code | CloudinaryAssetContextCustom | CloudinaryAssetDerived | CloudinaryAsset | CloudinaryAssetContext | SanityAssistInstructionTask | SanityAssistTaskStatus | SanityAssistSchemaTypeAnnotations | SanityAssistOutputType | SanityAssistOutputField | SanityAssistInstructionContext | AssistInstructionContext | SanityAssistInstructionUserInput | SanityAssistInstructionPrompt | SanityAssistInstructionFieldRef | SanityAssistInstruction | SanityAssistSchemaTypeField | SanityImagePaletteSwatch | SanityImagePalette | SanityImageDimensions | SanityImageHotspot | SanityImageCrop | SanityFileAsset | SanityImageAsset | SanityImageMetadata | Geopoint | Slug | SanityAssetSourceData;
export declare const internalGroqTypeReferenceTo: unique symbol;
// Source: sanity/lib/queries.ts
// Variable: docCount