{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bitcoin-signin",
  "title": "Bitcoin Sign In",
  "author": "Satchmo <https://bigblocks.dev>",
  "description": "A sign-in button that initiates OAuth flow via Sigma Identity (Bitcoin-based authentication using Better Auth)",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "alert",
    "button"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/bitcoin-signin/index.tsx",
      "content": "\"use client\"\n\nimport {\n  BitcoinSigninUI,\n  type BitcoinSigninUIProps,\n} from \"./bitcoin-signin-ui\"\nimport {\n  useBitcoinSignin,\n  type UseBitcoinSigninOptions,\n  type UseBitcoinSigninReturn,\n  type SigmaSignInFn,\n  type OAuthProvider,\n} from \"./use-bitcoin-signin\"\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport {\n  BitcoinSigninUI,\n  type BitcoinSigninUIProps,\n} from \"./bitcoin-signin-ui\"\nexport {\n  useBitcoinSignin,\n  type UseBitcoinSigninOptions,\n  type UseBitcoinSigninReturn,\n  type SigmaSignInFn,\n  type OAuthProvider,\n} from \"./use-bitcoin-signin\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface BitcoinSigninProps {\n  /** OAuth client ID registered with Sigma Identity (required) */\n  clientId: string\n  /**\n   * Callback URL after OAuth redirect.\n   * Defaults to `window.location.origin + \"/auth/sigma/callback\"`.\n   */\n  callbackUrl?: string\n  /**\n   * The `signIn.sigma` function from a Better Auth client configured\n   * with the sigma plugin.\n   *\n   * @example\n   * ```ts\n   * import { authClient } from \"@/lib/auth-client\"\n   * <BitcoinSignin signIn={(opts) => authClient.signIn.sigma(opts)} />\n   * ```\n   */\n  signIn: SigmaSignInFn\n  /** Show OAuth provider buttons for account restore (default: false) */\n  showProviders?: boolean\n  /** Which OAuth providers to show (default: [\"github\", \"google\"]) */\n  providers?: OAuthProvider[]\n  /** Visual style variant */\n  variant?: \"default\" | \"outline\" | \"ghost\"\n  /** Size variant */\n  size?: \"sm\" | \"md\" | \"lg\"\n  /** Additional CSS classes */\n  className?: string\n  /** Called when a sign-in error occurs */\n  onError?: (error: Error) => void\n}\n\n// ---------------------------------------------------------------------------\n// Composed component\n// ---------------------------------------------------------------------------\n\n/**\n * A sign-in button that initiates OAuth flow via Sigma Identity\n * (Bitcoin-based authentication using Better Auth).\n *\n * Requires a `signIn` function — typically `authClient.signIn.sigma`\n * from a Better Auth client configured with `sigmaClient()`.\n *\n * @example\n * ```tsx\n * import { authClient } from \"@/lib/auth-client\"\n * import { BitcoinSignin } from \"@/components/blocks/bitcoin-signin\"\n *\n * function LoginPage() {\n *   return (\n *     <BitcoinSignin\n *       clientId=\"my-app\"\n *       signIn={(opts) => authClient.signIn.sigma(opts)}\n *       showProviders\n *     />\n *   )\n * }\n * ```\n */\nexport function BitcoinSignin({\n  clientId,\n  callbackUrl,\n  signIn,\n  showProviders = false,\n  providers = [\"github\", \"google\"],\n  variant = \"default\",\n  size = \"md\",\n  className,\n  onError,\n}: BitcoinSigninProps) {\n  const hook = useBitcoinSignin({\n    clientId,\n    callbackUrl,\n    signIn,\n    onError,\n  })\n\n  return (\n    <BitcoinSigninUI\n      className={className}\n      variant={variant}\n      size={size}\n      isLoading={hook.isLoading}\n      error={hook.error}\n      showProviders={showProviders}\n      providers={providers}\n      onSignIn={hook.loginWithSigma}\n      onProviderSignIn={hook.loginWithProvider}\n    />\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/bitcoin-signin/index.tsx"
    },
    {
      "path": "registry/new-york/blocks/bitcoin-signin/bitcoin-signin-ui.tsx",
      "content": "\"use client\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Alert, AlertDescription } from \"@/components/ui/alert\"\nimport { Button } from \"@/components/ui/button\"\nimport { AlertCircle, Github, Loader2 } from \"lucide-react\"\nimport type { OAuthProvider } from \"./use-bitcoin-signin\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface BitcoinSigninUIProps {\n  /** Additional CSS classes */\n  className?: string\n  /** Visual style variant */\n  variant?: \"default\" | \"outline\" | \"ghost\"\n  /** Size variant */\n  size?: \"sm\" | \"md\" | \"lg\"\n  /** Whether a sign-in request is in progress */\n  isLoading: boolean\n  /** Error to display */\n  error: Error | null\n  /** Show OAuth provider buttons for account restore */\n  showProviders: boolean\n  /** Which OAuth providers to show */\n  providers: OAuthProvider[]\n  /** Handle Bitcoin sign-in click */\n  onSignIn: () => void\n  /** Handle OAuth provider sign-in click */\n  onProviderSignIn: (provider: OAuthProvider) => void\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst sizeClasses = {\n  sm: \"h-9 px-3 text-sm\",\n  md: \"h-10 px-4 text-sm\",\n  lg: \"h-11 px-6 text-base\",\n} as const\n\n/** Bitcoin sigma symbol used as the brand icon */\nfunction SigmaIcon({ className }: { className?: string }) {\n  return (\n    <span className={cn(\"font-semibold leading-none\", className)} aria-hidden=\"true\">\n      σ\n    </span>\n  )\n}\n\n/** Google \"G\" icon */\nfunction GoogleIcon({ className }: { className?: string }) {\n  return (\n    <svg\n      className={className}\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      aria-hidden=\"true\"\n    >\n      <path\n        d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1Z\"\n        fill=\"#4285F4\"\n      />\n      <path\n        d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23Z\"\n        fill=\"#34A853\"\n      />\n      <path\n        d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A10.96 10.96 0 0 0 1 12c0 1.77.42 3.45 1.18 4.93l3.66-2.84Z\"\n        fill=\"#FBBC05\"\n      />\n      <path\n        d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53Z\"\n        fill=\"#EA4335\"\n      />\n    </svg>\n  )\n}\n\n/** Map provider to icon and label */\nfunction providerConfig(provider: OAuthProvider): {\n  icon: React.ReactNode\n  label: string\n} {\n  switch (provider) {\n    case \"github\":\n      return {\n        icon: <Github className=\"size-4\" />,\n        label: \"Continue with GitHub\",\n      }\n    case \"google\":\n      return {\n        icon: <GoogleIcon className=\"size-4\" />,\n        label: \"Continue with Google\",\n      }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// UI Component\n// ---------------------------------------------------------------------------\n\n/**\n * Pure UI component for Bitcoin sign-in via Sigma Identity.\n *\n * Renders a primary \"Sign in with Bitcoin\" button and optionally\n * OAuth provider buttons for account restore/linking.\n */\nexport function BitcoinSigninUI({\n  className,\n  variant = \"default\",\n  size = \"md\",\n  isLoading,\n  error,\n  showProviders,\n  providers,\n  onSignIn,\n  onProviderSignIn,\n}: BitcoinSigninUIProps) {\n  return (\n    <div className={cn(\"flex flex-col gap-3\", className)}>\n      {/* Primary Bitcoin sign-in button */}\n      <Button\n        variant={variant}\n        className={cn(sizeClasses[size], \"gap-2\")}\n        disabled={isLoading}\n        onClick={onSignIn}\n        aria-busy={isLoading}\n        aria-label=\"Sign in with Bitcoin\"\n      >\n        {isLoading ? (\n          <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n        ) : (\n          <SigmaIcon className=\"text-base\" />\n        )}\n        {isLoading ? \"Signing in\\u2026\" : \"Sign in with Bitcoin\"}\n      </Button>\n\n      {/* OAuth provider buttons for account restore */}\n      {showProviders && providers.length > 0 && (\n        <>\n          <div className=\"relative flex items-center gap-2\">\n            <div className=\"flex-1 border-t border-border\" />\n            <span className=\"text-xs text-muted-foreground\">or restore with</span>\n            <div className=\"flex-1 border-t border-border\" />\n          </div>\n          <div className=\"flex flex-col gap-2\">\n            {providers.map((provider) => {\n              const config = providerConfig(provider)\n              return (\n                <Button\n                  key={provider}\n                  variant=\"outline\"\n                  className={cn(sizeClasses[size], \"gap-2\")}\n                  disabled={isLoading}\n                  onClick={() => onProviderSignIn(provider)}\n                  aria-label={config.label}\n                >\n                  {config.icon}\n                  {config.label}\n                </Button>\n              )\n            })}\n          </div>\n        </>\n      )}\n\n      {/* Error display */}\n      {error && (\n        <Alert variant=\"destructive\" className=\"animate-in fade-in-50\">\n          <AlertCircle className=\"size-4\" />\n          <AlertDescription>{error.message}</AlertDescription>\n        </Alert>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "~/components/blocks/bitcoin-signin/bitcoin-signin-ui.tsx"
    },
    {
      "path": "registry/new-york/blocks/bitcoin-signin/use-bitcoin-signin.ts",
      "content": "import { useCallback, useState } from \"react\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Supported OAuth providers for account restore/linking */\nexport type OAuthProvider = \"github\" | \"google\"\n\n/**\n * A function that initiates Sigma OAuth sign-in.\n *\n * This matches the shape of `authClient.signIn.sigma()` from\n * `@sigma-auth/better-auth-plugin/client` so consumers can pass\n * it directly, but any function with the same signature works.\n *\n * @example\n * ```ts\n * import { authClient } from \"@/lib/auth-client\"\n *\n * const sigmaSignIn: SigmaSignInFn = (opts) =>\n *   authClient.signIn.sigma(opts)\n * ```\n */\nexport type SigmaSignInFn = (options: {\n  clientId: string\n  callbackURL?: string\n  provider?: string\n}) => Promise<unknown>\n\nexport interface UseBitcoinSigninOptions {\n  /** OAuth client ID registered with Sigma Identity */\n  clientId: string\n  /**\n   * Callback URL after OAuth redirect.\n   * Defaults to `window.location.origin + \"/auth/sigma/callback\"`.\n   */\n  callbackUrl?: string\n  /**\n   * The `signIn.sigma` function from a Better Auth client configured\n   * with the sigma plugin. This keeps the block decoupled from any\n   * specific auth client instance.\n   *\n   * @example\n   * ```ts\n   * import { authClient } from \"@/lib/auth-client\"\n   * const signIn = (opts) => authClient.signIn.sigma(opts)\n   * ```\n   */\n  signIn: SigmaSignInFn\n  /** Called when a sign-in error occurs */\n  onError?: (error: Error) => void\n}\n\nexport interface UseBitcoinSigninReturn {\n  /** Whether a sign-in request is in progress */\n  isLoading: boolean\n  /** The most recent error, if any */\n  error: Error | null\n  /** Initiate Bitcoin (Sigma) sign-in */\n  loginWithSigma: () => Promise<void>\n  /** Initiate OAuth provider sign-in for account restore */\n  loginWithProvider: (provider: OAuthProvider) => Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Hook that wraps Sigma Identity sign-in calls.\n *\n * Accepts a `signIn` function rather than importing the auth client\n * directly, keeping the block decoupled from any specific Better Auth\n * client configuration.\n */\nexport function useBitcoinSignin({\n  clientId,\n  callbackUrl,\n  signIn,\n  onError,\n}: UseBitcoinSigninOptions): UseBitcoinSigninReturn {\n  const [isLoading, setIsLoading] = useState(false)\n  const [error, setError] = useState<Error | null>(null)\n\n  const resolveCallbackUrl = useCallback((): string => {\n    if (callbackUrl) return callbackUrl\n    if (typeof window !== \"undefined\") {\n      return `${window.location.origin}/auth/sigma/callback`\n    }\n    return \"/auth/sigma/callback\"\n  }, [callbackUrl])\n\n  const loginWithSigma = useCallback(async () => {\n    setIsLoading(true)\n    setError(null)\n    try {\n      await signIn({\n        clientId,\n        callbackURL: resolveCallbackUrl(),\n      })\n    } catch (e) {\n      const err = e instanceof Error ? e : new Error(String(e))\n      setError(err)\n      onError?.(err)\n    } finally {\n      setIsLoading(false)\n    }\n  }, [clientId, signIn, resolveCallbackUrl, onError])\n\n  const loginWithProvider = useCallback(\n    async (provider: OAuthProvider) => {\n      setIsLoading(true)\n      setError(null)\n      try {\n        await signIn({\n          clientId,\n          callbackURL: resolveCallbackUrl(),\n          provider,\n        })\n      } catch (e) {\n        const err = e instanceof Error ? e : new Error(String(e))\n        setError(err)\n        onError?.(err)\n      } finally {\n        setIsLoading(false)\n      }\n    },\n    [clientId, signIn, resolveCallbackUrl, onError],\n  )\n\n  return {\n    isLoading,\n    error,\n    loginWithSigma,\n    loginWithProvider,\n  }\n}\n",
      "type": "registry:component",
      "target": "~/components/blocks/bitcoin-signin/use-bitcoin-signin.ts"
    }
  ],
  "categories": [
    "authentication"
  ],
  "type": "registry:block"
}