{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "quickstart-with-full-stack-xmc",
  "title": "Quickstart for Next.js with full-stack XMC APIs examples",
  "description": "A quickstart for next.js Sitecore marketplace apps with full-stack XMC API examples",
  "registryDependencies": [
    "https://blok.sitecore.com/r/marketplace/next/quickstart-with-custom-auth.json",
    "https://blok.sitecore.com/r/marketplace/next/quickstart-with-client-side-xmc.json"
  ],
  "files": [
    {
      "path": "src/marketplace/next/components/examples/custom-auth/with-api-route/list-languages.tsx",
      "content": "\"use client\";\n\nimport { useAuth } from \"@/components/providers/auth\";\nimport { useAppContext } from \"@/components/providers/marketplace\";\nimport { Alert, AlertDescription } from \"@/components/ui/alert\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport type { Xmapp } from \"@sitecore-marketplace-sdk/xmc\";\nimport { useState } from \"react\";\n\nexport const ListLanguagesFromApiRoute = () => {\n  const appContext = useAppContext();\n  const { getAccessTokenSilently } = useAuth();\n  const [languages, setLanguages] = useState<Xmapp.Language[]>([]);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  const fetchLanguages = async () => {\n    setLoading(true);\n    setError(null);\n    const accessToken = await getAccessTokenSilently();\n    try {\n      // /app/api/sites/languages/route.ts\n      const response = await fetch(\n        `/api/sites/languages?contextid=${appContext?.resourceAccess?.[0]?.context?.preview}`,\n        {\n          headers: {\n            Authorization: `Bearer ${accessToken}`,\n          },\n        },\n      );\n      if (!response.ok) {\n        throw new Error(`HTTP error! status: ${response.status}`);\n      }\n      const data = await response.json();\n      console.log(\"languages from api\", data);\n      setLanguages(data.data);\n    } catch (error) {\n      console.error(\"error from api\", error);\n      setError(error instanceof Error ? error.message : \"An error occurred\");\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  return (\n    <Card style={\"outline\"}>\n      <CardHeader>\n        <CardTitle className=\"flex items-center gap-2\">\n          API Route Example\n          <Badge colorScheme={\"primary\"}>Server-side</Badge>\n          <Badge colorScheme={\"warning\"}>Custom Auth</Badge>\n        </CardTitle>\n        <CardDescription>\n          Fetch languages using Next.js API route from client component\n          <br />\n          User access token is passed from client component to API route\n        </CardDescription>\n      </CardHeader>\n      <CardContent className=\"space-y-4\">\n        <Button\n          onClick={fetchLanguages}\n          disabled={loading}\n          className=\"w-full sm:w-auto\"\n        >\n          {loading ? \"Fetching...\" : \"Fetch Languages\"}\n        </Button>\n\n        {error && (\n          <Alert variant=\"danger\">\n            <AlertDescription>{error}</AlertDescription>\n          </Alert>\n        )}\n\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-sm font-medium\">Languages found:</span>\n            {loading ? (\n              <Skeleton className=\"h-5 w-8\" />\n            ) : (\n              <Badge>{languages?.length || 0}</Badge>\n            )}\n          </div>\n\n          {languages.length > 0 && (\n            <div className=\"space-y-1\">\n              <p className=\"text-sm text-muted-foreground\">Language names:</p>\n              <div className=\"flex flex-wrap gap-1\">\n                {languages.map((language, index) => (\n                  <Badge key={index}>{language.name}</Badge>\n                ))}\n              </div>\n            </div>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/examples/custom-auth/with-api-route/list-languages.tsx"
    },
    {
      "path": "src/marketplace/next/components/examples/custom-auth/with-api-route/route.ts",
      "content": "import { experimental_createXMCClient } from \"@sitecore-marketplace-sdk/xmc\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\nexport async function GET(request: NextRequest) {\n  const url = new URL(request.url);\n  const contextId = url.searchParams.get(\"contextid\");\n\n  const accessToken = request.headers.get(\"authorization\")?.split(\" \")[1];\n\n  if (!contextId) {\n    return NextResponse.json(\n      { error: \"Context ID is required\" },\n      { status: 400 },\n    );\n  }\n\n  if (!accessToken) {\n    return NextResponse.json(\n      { error: \"Access token is required\" },\n      { status: 401 },\n    );\n  }\n\n  const xmcClient = await experimental_createXMCClient({\n    getAccessToken: async () => {\n      return accessToken;\n    },\n  });\n\n  try {\n    const languages = await xmcClient.sites.listLanguages({\n      query: {\n        sitecoreContextId: contextId,\n      },\n    });\n\n    console.log(\"languages from API\", languages);\n    return NextResponse.json(languages);\n  } catch (error) {\n    console.error(\"Error fetching languages\", error);\n    return NextResponse.json(\n      { error: \"Failed to fetch languages\" },\n      { status: 500 },\n    );\n  }\n}\n",
      "type": "registry:file",
      "target": "app/api/sites/languages/route.ts"
    },
    {
      "path": "src/marketplace/next/components/examples/custom-auth/with-server-action/list-languages.tsx",
      "content": "\"use client\";\n\nimport { useAuth } from \"@/components/providers/auth\";\nimport { useAppContext } from \"@/components/providers/marketplace\";\nimport { Alert, AlertDescription } from \"@/components/ui/alert\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport type { Xmapp } from \"@sitecore-marketplace-sdk/xmc\";\nimport { useState } from \"react\";\nimport { fetchLanguagesAction } from \"./action\";\n\nexport const ListLanguagesFromServerAction = () => {\n  const appContext = useAppContext();\n  const { getAccessTokenSilently } = useAuth();\n  const [languages, setLanguages] = useState<Xmapp.Language[]>([]);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  const fetchLanguages = async () => {\n    setLoading(true);\n    setError(null);\n    try {\n      // server action\n      const languages = await fetchLanguagesAction({\n        sitecoreContextId:\n          appContext?.resourceAccess?.[0]?.context?.preview || \"\",\n        accessToken: await getAccessTokenSilently(),\n      });\n\n      setLanguages(languages);\n    } catch (error) {\n      console.error(\"error from server action\", error);\n      setError(error instanceof Error ? error.message : \"An error occurred\");\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  return (\n    <Card style={\"outline\"}>\n      <CardHeader>\n        <CardTitle className=\"flex items-center gap-2\">\n          Server Action Example\n          <Badge colorScheme={\"primary\"}>Server-side</Badge>\n          <Badge colorScheme={\"warning\"}>Custom Auth</Badge>\n        </CardTitle>\n        <CardDescription>\n          Fetch languages using Next.js server action from client component\n          <br />\n          User access token is passed from client component to server action\n        </CardDescription>\n      </CardHeader>\n      <CardContent className=\"space-y-4\">\n        <Button\n          onClick={fetchLanguages}\n          disabled={loading}\n          className=\"w-full sm:w-auto\"\n        >\n          {loading ? \"Fetching...\" : \"Fetch Languages\"}\n        </Button>\n\n        {error && (\n          <Alert variant=\"danger\">\n            <AlertDescription>{error}</AlertDescription>\n          </Alert>\n        )}\n\n        <div className=\"space-y-2\">\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-sm font-medium\">Languages found:</span>\n            {loading ? (\n              <Skeleton className=\"h-5 w-8\" />\n            ) : (\n              <Badge>{languages.length}</Badge>\n            )}\n          </div>\n\n          {languages.length > 0 && (\n            <div className=\"space-y-1\">\n              <p className=\"text-sm text-muted-foreground\">Language names:</p>\n              <div className=\"flex flex-wrap gap-1\">\n                {languages.map((language, index) => (\n                  <Badge key={index}>{language.name}</Badge>\n                ))}\n              </div>\n            </div>\n          )}\n        </div>\n      </CardContent>\n    </Card>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/examples/custom-auth/with-server-action/list-languages.tsx"
    },
    {
      "path": "src/marketplace/next/components/examples/custom-auth/with-server-action/action.ts",
      "content": "\"use server\";\n\nimport { experimental_createXMCClient } from \"@sitecore-marketplace-sdk/xmc\";\nimport type { Xmapp } from \"@sitecore-marketplace-sdk/xmc\";\n\ntype Context = {\n  sitecoreContextId: string;\n  accessToken: string;\n};\n\nexport async function fetchLanguagesAction(\n  context: Context,\n): Promise<Xmapp.Language[]> {\n  const client = await experimental_createXMCClient({\n    getAccessToken: async () => {\n      return context.accessToken;\n    },\n  });\n\n  const languages = await client.sites.listLanguages({\n    query: {\n      sitecoreContextId: context.sitecoreContextId,\n    },\n  });\n\n  console.log(\"languages from server action\", languages);\n\n  return languages?.data ?? [];\n}\n",
      "type": "registry:file",
      "target": "components/examples/custom-auth/with-server-action/action.ts"
    },
    {
      "path": "src/marketplace/next/components/examples/custom-auth/page.tsx",
      "content": "\"use client\";\n\nimport { ApplicationContext } from \"@/components/examples/built-in-auth/application-context\";\nimport { ListLanguagesFromClientSdk } from \"@/components/examples/built-in-auth/with-xmc/list-languages\";\nimport { ListLanguagesFromApiRoute } from \"@/components/examples/custom-auth/with-api-route/list-languages\";\nimport { ListLanguagesFromServerAction } from \"@/components/examples/custom-auth/with-server-action/list-languages\";\nimport { Separator } from \"@/components/ui/separator\";\n\nfunction ServerSideExamples() {\n  return (\n    <div className=\"container mx-auto p-6 space-y-8 max-w-3xl\">\n      <div className=\"space-y-4\">\n        <h1 className=\"text-3xl font-semibold tracking-tight\">\n          Marketplace SDK Demo\n        </h1>\n        <p className=\"text-muted-foreground\">\n          Marketplace SDK with custom authentication and XMC API server-side\n          examples\n        </p>\n      </div>\n\n      <ApplicationContext />\n\n      <Separator />\n\n      <div className=\"space-y-6\">\n        <h2 className=\"text-2xl font-semibold\">Built-in Auth Examples</h2>\n        <div className=\"grid gap-6\">\n          <ListLanguagesFromClientSdk />\n        </div>\n      </div>\n\n      <div className=\"space-y-6\">\n        <h2 className=\"text-2xl font-semibold\">Custom Auth Examples</h2>\n        <div className=\"grid gap-6\">\n          <ListLanguagesFromApiRoute />\n          <ListLanguagesFromServerAction />\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ServerSideExamples;\n",
      "type": "registry:page",
      "target": "app/page.tsx"
    }
  ],
  "type": "registry:block"
}