     case priv do
       %{:assigns_cache_valid => true, "assigns" => _, "index" => _} = p ->
         p
+
       _ ->
         assigns_and_index = assigns_and_index_from_browser(socket)
         Drab.set_priv(drab, Map.merge(priv, assigns_and_index))

          end

        # TODO: store not encoded
        updated_assigns =
          for {k, v} <- Map.merge(current_assigns, assigns_to_update), into: %{} do
            {k, Drab.Live.Crypto.encode64(v)}
          end

        priv = socket |> Drab.pid() |> Drab.get_priv()
        partial_assigns_updated = %{priv["assigns"] | partial => updated_assigns}
        socket |> Drab.pid() |> Drab.set_priv(%{priv | "assigns" => partial_assigns_updated})
        socket


  @spec assigns_and_index_from_browser(Phoenix.Socket.t()) :: map
  defp assigns_and_index_from_browser(socket) do
    {:ok, ret} = exec_js(socket, "({assigns: __drab.assigns, index: __drab.index})")
    # Map.put(ret, :assigns_cache_valid, true)
    %{
      :assigns_cache_valid => true,
      "assigns" => decrypted_assigns(ret["assigns"]),
      "index" => ret["index"]
    }
  end

  @spec decrypted_assigns(%{}) :: %{}
  defp decrypted_assigns(assigns) do
    for {partial, partial_assigns} <- assigns, into: %{} do
      {partial,
       for {name, value} <- partial_assigns, into: %{} do
         {name, Drab.Live.Crypto.decode64(value)}
       end}
    end
  end

  @spec partial_hash(atom, String.t()) :: String.t() | no_return
